blob: 16137f6426d69bc0e2f2ae18b48041520d2aa9c2 [file] [log] [blame]
developer3abe1ad2022-01-24 11:13:32 +08001/* Copyright (C) 2021-2022 Mediatek Inc. */
2#define _GNU_SOURCE
3
4#include <unl.h>
5
6#include "atenl.h"
7
8#define to_rssi(_rcpi) ((_rcpi - 220) / 2)
9
10struct atenl_nl_priv {
11 struct atenl *an;
12 struct unl unl;
13 struct nl_msg *msg;
14 int attr;
15 void *res;
16};
17
18struct atenl_nl_ops {
19 int set;
20 int dump;
21 int (*ops)(struct atenl *an, struct atenl_data *data,
22 struct atenl_nl_priv *nl_priv);
23};
24
25static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
26 [MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
27 [MT76_TM_ATTR_MTD_PART] = { .type = NLA_STRING },
28 [MT76_TM_ATTR_MTD_OFFSET] = { .type = NLA_U32 },
29 [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
30 [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
31 [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
32 [MT76_TM_ATTR_TX_RATE_NSS] = { .type = NLA_U8 },
33 [MT76_TM_ATTR_TX_RATE_IDX] = { .type = NLA_U8 },
34 [MT76_TM_ATTR_TX_RATE_SGI] = { .type = NLA_U8 },
35 [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },
36 [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },
37 [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },
38 [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
39 [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },
40 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
41 [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED },
42};
43
44static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
45 [MT76_TM_STATS_ATTR_TX_PENDING] = { .type = NLA_U32 },
46 [MT76_TM_STATS_ATTR_TX_QUEUED] = { .type = NLA_U32 },
47 [MT76_TM_STATS_ATTR_TX_DONE] = { .type = NLA_U32 },
48 [MT76_TM_STATS_ATTR_RX_PACKETS] = { .type = NLA_U64 },
49 [MT76_TM_STATS_ATTR_RX_FCS_ERROR] = { .type = NLA_U64 },
50};
51
52static struct nla_policy rx_policy[NUM_MT76_TM_RX_ATTRS] = {
53 [MT76_TM_RX_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
54 [MT76_TM_RX_ATTR_RCPI] = { .type = NLA_NESTED },
55 [MT76_TM_RX_ATTR_IB_RSSI] = { .type = NLA_NESTED },
56 [MT76_TM_RX_ATTR_WB_RSSI] = { .type = NLA_NESTED },
57 [MT76_TM_RX_ATTR_SNR] = { .type = NLA_U8 },
58};
59
60struct he_sgi {
61 enum mt76_testmode_tx_mode tx_mode;
62 u8 sgi;
63 u8 tx_ltf;
64};
65
66#define HE_SGI_GROUP(_tx_mode, _sgi, _tx_ltf) \
67 { .tx_mode = MT76_TM_TX_MODE_##_tx_mode, .sgi = _sgi, .tx_ltf = _tx_ltf }
68static const struct he_sgi he_sgi_groups[] = {
69 HE_SGI_GROUP(HE_SU, 0, 0),
70 HE_SGI_GROUP(HE_SU, 0, 1),
71 HE_SGI_GROUP(HE_SU, 1, 1),
72 HE_SGI_GROUP(HE_SU, 2, 2),
73 HE_SGI_GROUP(HE_SU, 0, 2),
74 HE_SGI_GROUP(HE_EXT_SU, 0, 0),
75 HE_SGI_GROUP(HE_EXT_SU, 0, 1),
76 HE_SGI_GROUP(HE_EXT_SU, 1, 1),
77 HE_SGI_GROUP(HE_EXT_SU, 2, 2),
78 HE_SGI_GROUP(HE_EXT_SU, 0, 2),
79 HE_SGI_GROUP(HE_TB, 1, 0),
80 HE_SGI_GROUP(HE_TB, 1, 1),
81 HE_SGI_GROUP(HE_TB, 2, 2),
82 HE_SGI_GROUP(HE_MU, 0, 2),
83 HE_SGI_GROUP(HE_MU, 0, 1),
84 HE_SGI_GROUP(HE_MU, 1, 1),
85 HE_SGI_GROUP(HE_MU, 2, 2),
86};
87#undef HE_SGI_LTF_GROUP
88
89static u8 phy_type_to_attr(u8 phy_type)
90{
91 static const u8 phy_type_to_attr[] = {
92 [ATENL_PHY_TYPE_CCK] = MT76_TM_TX_MODE_CCK,
93 [ATENL_PHY_TYPE_OFDM] = MT76_TM_TX_MODE_OFDM,
94 [ATENL_PHY_TYPE_HT] = MT76_TM_TX_MODE_HT,
95 [ATENL_PHY_TYPE_HT_GF] = MT76_TM_TX_MODE_HT,
96 [ATENL_PHY_TYPE_VHT] = MT76_TM_TX_MODE_VHT,
97 [ATENL_PHY_TYPE_HE_SU] = MT76_TM_TX_MODE_HE_SU,
98 [ATENL_PHY_TYPE_HE_EXT_SU] = MT76_TM_TX_MODE_HE_EXT_SU,
99 [ATENL_PHY_TYPE_HE_TB] = MT76_TM_TX_MODE_HE_TB,
100 [ATENL_PHY_TYPE_HE_MU] = MT76_TM_TX_MODE_HE_MU,
101 };
102
103 if (phy_type >= ARRAY_SIZE(phy_type_to_attr))
104 return 0;
105
106 return phy_type_to_attr[phy_type];
107}
108
109static void
110atenl_set_attr_state(struct atenl *an, struct nl_msg *msg,
111 u8 band, enum mt76_testmode_state state)
112{
113 if (get_band_val(an, band, cur_state) == state)
114 return;
115
116 nla_put_u8(msg, MT76_TM_ATTR_STATE, state);
117 set_band_val(an, band, cur_state, state);
118}
119
120static void
developer763ab652022-06-14 18:38:23 +0800121atenl_set_attr_tx_length(struct atenl *an, struct nl_msg *msg,
122 u32 tx_length, bool is_mu)
123{
124#define IEEE80211_MAX_FRAME_LEN 2352
125 int hdr_len = 24;
126
127 if (tx_length > IEEE80211_MAX_FRAME_LEN || is_mu)
128 hdr_len += 2;
129
130 if (an->ibf_cal)
131 hdr_len = 0;
132
133 /* The definition of MT76_TM_ATTR_TX_LENGTH is MPDU length,
134 * so add ieee80211_hdr length.
135 */
136 nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, tx_length + hdr_len);
137}
138
139static void
developer3abe1ad2022-01-24 11:13:32 +0800140atenl_set_attr_antenna(struct atenl *an, struct nl_msg *msg, u8 tx_antenna)
141{
142 if (!tx_antenna)
143 return;
144
145 if (is_mt7915(an))
146 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA,
147 tx_antenna << (2 * an->cur_band));
148 else if (is_mt7916(an) || is_mt7986(an))
149 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, tx_antenna);
150}
151
152static int
153atenl_nl_set_attr(struct atenl *an, struct atenl_data *data,
154 struct atenl_nl_priv *nl_priv)
155{
156 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
157 struct nl_msg *msg = nl_priv->msg;
158 u32 val = ntohl(*(u32 *)hdr->data);
159 int attr = nl_priv->attr;
160 void *ptr, *a;
161
162 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
163 if (!ptr)
164 return -ENOMEM;
165
166 switch (attr) {
167 case MT76_TM_ATTR_TX_ANTENNA:
168 atenl_set_attr_antenna(an, msg, val);
169 break;
170 case MT76_TM_ATTR_FREQ_OFFSET:
171 nla_put_u32(msg, attr, val);
172 break;
173 case MT76_TM_ATTR_TX_POWER:
174 a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER);
175 if (!a)
176 return -ENOMEM;
177 nla_put_u8(msg, 0, val);
178 nla_nest_end(msg, a);
179 break;
180 default:
181 nla_put_u8(msg, attr, val);
182 break;
183 }
184
185 nla_nest_end(msg, ptr);
186
187 return unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
188}
189
190static int
191atenl_nl_set_cfg(struct atenl *an, struct atenl_data *data,
192 struct atenl_nl_priv *nl_priv)
193{
194 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
195 struct nl_msg *msg = nl_priv->msg;
196 enum atenl_cmd cmd = data->cmd;
197 u32 *v = (u32 *)hdr->data;
198 u8 type = ntohl(v[0]);
199 u8 enable = ntohl(v[1]);
200 void *ptr, *cfg;
201
202 if (cmd == HQA_CMD_SET_TSSI) {
203 type = 0;
204 enable = 1;
205 }
206
207 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
208 if (!ptr)
209 return -ENOMEM;
210
211 cfg = nla_nest_start(msg, MT76_TM_ATTR_CFG);
212 if (!cfg)
213 return -ENOMEM;
214
215 if (nla_put_u8(msg, 0, type) ||
216 nla_put_u8(msg, 1, enable))
217 return -EINVAL;
218
219 nla_nest_end(msg, cfg);
220
221 nla_nest_end(msg, ptr);
222
223 return unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
224}
225
226static int
227atenl_nl_set_tx(struct atenl *an, struct atenl_data *data,
228 struct atenl_nl_priv *nl_priv)
229{
230 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
231 struct nl_msg *msg = nl_priv->msg;
232 u32 *v = (u32 *)hdr->data;
233 u8 *addr1 = hdr->data + 36;
234 u8 *addr2 = addr1 + ETH_ALEN;
235 u8 *addr3 = addr2 + ETH_ALEN;
developer5698c9c2022-05-30 16:40:23 +0800236 u8 def_mac[ETH_ALEN] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
developer3abe1ad2022-01-24 11:13:32 +0800237 void *ptr, *a;
238
developer5698c9c2022-05-30 16:40:23 +0800239 if (get_band_val(an, an->cur_band, use_tx_time))
240 set_band_val(an, an->cur_band, tx_time, ntohl(v[7]));
241 else
242 set_band_val(an, an->cur_band, tx_mpdu_len, ntohl(v[7]));
243
developer3abe1ad2022-01-24 11:13:32 +0800244 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
245 if (!ptr)
246 return -ENOMEM;
247
developer3abe1ad2022-01-24 11:13:32 +0800248 a = nla_nest_start(msg, MT76_TM_ATTR_MAC_ADDRS);
249 if (!a)
250 return -ENOMEM;
251
developer5698c9c2022-05-30 16:40:23 +0800252 nla_put(msg, 0, ETH_ALEN, use_default_addr(addr1) ? def_mac : addr1);
253 nla_put(msg, 1, ETH_ALEN, use_default_addr(addr2) ? def_mac : addr2);
254 nla_put(msg, 2, ETH_ALEN, use_default_addr(addr3) ? def_mac : addr3);
developer3abe1ad2022-01-24 11:13:32 +0800255
256 nla_nest_end(msg, a);
257
258 nla_nest_end(msg, ptr);
259
260 *(u32 *)(hdr->data + 2) = data->ext_id;
261
262 return unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
263}
264
265static int
266atenl_nl_tx(struct atenl *an, struct atenl_data *data, struct atenl_nl_priv *nl_priv)
267{
268#define USE_SPE_IDX BIT(31)
269 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
270 struct nl_msg *msg = nl_priv->msg;
271 u32 *v = (u32 *)hdr->data;
272 u8 band = ntohl(v[2]);
273 void *ptr;
274 int ret;
275
276 if (band >= MAX_BAND_NUM)
277 return -EINVAL;
278
279 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
280 if (!ptr)
281 return -ENOMEM;
282
283 if (data->ext_cmd == HQA_EXT_CMD_STOP_TX) {
284 atenl_set_attr_state(an, msg, band, MT76_TM_STATE_IDLE);
285 } else {
286 u32 tx_count = ntohl(v[3]);
287 u8 tx_rate_mode = phy_type_to_attr(ntohl(v[4]));
288 u8 aid = ntohl(v[11]);
289 u8 sgi = ntohl(v[13]);
290 u32 tx_antenna = ntohl(v[14]);
291 void *a;
292
293 if (sgi > 5)
294 return -EINVAL;
295
296 if (!tx_count)
297 tx_count = 10000000;
298
299 nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, tx_count);
300 nla_put_u32(msg, MT76_TM_ATTR_TX_IPG, ntohl(v[12]));
301 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, tx_rate_mode);
302 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, ntohl(v[5]));
303 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, ntohl(v[7]));
304 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, ntohl(v[8]));
305 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, ntohl(v[15]));
306
developer5698c9c2022-05-30 16:40:23 +0800307 if (get_band_val(an, band, use_tx_time))
308 nla_put_u32(msg, MT76_TM_ATTR_TX_TIME,
309 get_band_val(an, band, tx_time));
310 else
developer763ab652022-06-14 18:38:23 +0800311 atenl_set_attr_tx_length(an, msg,
312 get_band_val(an, band, tx_mpdu_len),
313 tx_rate_mode == MT76_TM_TX_MODE_HE_MU);
developer5698c9c2022-05-30 16:40:23 +0800314
developer3abe1ad2022-01-24 11:13:32 +0800315 /* for chips after 7915, tx need to use at least wcid = 1 */
316 if (!is_mt7915(an) && !aid)
317 aid = 1;
318 nla_put_u8(msg, MT76_TM_ATTR_AID, aid);
319
320 if (tx_antenna & USE_SPE_IDX) {
321 nla_put_u8(msg, MT76_TM_ATTR_TX_SPE_IDX,
322 tx_antenna & ~USE_SPE_IDX);
323 } else {
324 nla_put_u8(msg, MT76_TM_ATTR_TX_SPE_IDX, 0);
325 atenl_set_attr_antenna(an, msg, tx_antenna);
326 }
327
328 if (tx_rate_mode >= MT76_TM_TX_MODE_HE_SU) {
329 u8 ofs = sgi;
330 size_t i;
331
332 for (i = 0; i < ARRAY_SIZE(he_sgi_groups); i++)
333 if (he_sgi_groups[i].tx_mode == tx_rate_mode)
334 break;
335
336 if ((i + ofs) >= ARRAY_SIZE(he_sgi_groups))
337 return -EINVAL;
338
339 sgi = he_sgi_groups[i + ofs].sgi;
340 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF,
341 he_sgi_groups[i + ofs].tx_ltf);
342 }
343 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, sgi);
344
345 a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER);
346 if (!a)
347 return -ENOMEM;
348 nla_put_u8(msg, 0, ntohl(v[6]));
349 nla_nest_end(msg, a);
350
351 atenl_set_attr_state(an, msg, band, MT76_TM_STATE_TX_FRAMES);
352 }
353
354 nla_nest_end(msg, ptr);
355
356 ret = unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
357 if (ret)
358 return ret;
359
360 *(u32 *)(hdr->data + 2) = data->ext_id;
361
362 return 0;
363}
364
365static int
366atenl_nl_rx(struct atenl *an, struct atenl_data *data, struct atenl_nl_priv *nl_priv)
367{
368 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
369 struct atenl_band *anb = &an->anb[an->cur_band];
370 struct nl_msg *msg = nl_priv->msg;
371 u32 *v = (u32 *)hdr->data;
372 u8 band = ntohl(v[2]);
373 void *ptr;
374
375 if (band >= MAX_BAND_NUM)
376 return -EINVAL;
377
378 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
379 if (!ptr)
380 return -ENOMEM;
381
382 if (data->ext_cmd == HQA_EXT_CMD_STOP_RX) {
383 atenl_set_attr_state(an, msg, band, MT76_TM_STATE_IDLE);
384 } else {
385 v = (u32 *)(hdr->data + 18);
386
387 atenl_set_attr_antenna(an, msg, ntohl(v[0]));
388 nla_put_u8(msg, MT76_TM_ATTR_AID, ntohl(v[1]));
389 atenl_set_attr_state(an, msg, band, MT76_TM_STATE_RX_FRAMES);
390
391 anb->reset_rx_cnt = false;
392
393 /* clear history buffer */
394 memset(&anb->rx_stat, 0, sizeof(anb->rx_stat));
395 }
396
397 nla_nest_end(msg, ptr);
398
399 *(u32 *)(hdr->data + 2) = data->ext_id;
400
401 return unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
402}
403
404static int
405atenl_off_ch_scan(struct atenl *an, struct atenl_data *data,
406 struct atenl_nl_priv *nl_priv)
407{
408 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
409 struct nl_msg *msg = nl_priv->msg;
410 u32 *v = (u32 *)hdr->data;
411 u8 ch = ntohl(v[2]);
412 u8 bw = ntohl(v[4]);
413 u8 tx_path = ntohl(v[5]);
414 u8 status = ntohl(v[6]);
415 void *ptr;
416
417 if (!status)
418 ch = 0; /* stop */
419
420 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
421 if (!ptr)
422 return -ENOMEM;
423
424 nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CH, ch);
425 nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
426 atenl_get_center_channel(bw, CH_BAND_5GHZ, ch));
427 nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_BW, bw);
428 nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_PATH, tx_path);
429
430 nla_nest_end(msg, ptr);
431
developer5698c9c2022-05-30 16:40:23 +0800432 *(u32 *)(hdr->data + 2) = data->ext_id;
developer3abe1ad2022-01-24 11:13:32 +0800433
434 return 0;
435}
436
437static int atenl_nl_dump_cb(struct nl_msg *msg, void *arg)
438{
439 struct atenl_nl_priv *nl_priv = (struct atenl_nl_priv *)arg;
440 struct nlattr *tb1[NUM_MT76_TM_ATTRS];
441 struct nlattr *tb2[NUM_MT76_TM_STATS_ATTRS];
442 struct nlattr *nl_attr;
443 int attr = nl_priv->attr;
444 u64 *res = nl_priv->res;
445
446 nl_attr = unl_find_attr(&nl_priv->unl, msg, NL80211_ATTR_TESTDATA);
447 if (!nl_attr) {
developer5698c9c2022-05-30 16:40:23 +0800448 atenl_err("Testdata attribute not found\n");
developer3abe1ad2022-01-24 11:13:32 +0800449 return NL_SKIP;
450 }
451
452 nla_parse_nested(tb1, MT76_TM_ATTR_MAX, nl_attr, testdata_policy);
453 nla_parse_nested(tb2, MT76_TM_STATS_ATTR_MAX,
454 tb1[MT76_TM_ATTR_STATS], stats_policy);
455
456 if (attr == MT76_TM_STATS_ATTR_TX_DONE)
457 *res = nla_get_u32(tb2[MT76_TM_STATS_ATTR_TX_DONE]);
458
459 return NL_SKIP;
460}
461
462static int
463atenl_nl_dump_attr(struct atenl *an, struct atenl_data *data,
464 struct atenl_nl_priv *nl_priv)
465{
466 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
467 struct nl_msg *msg = nl_priv->msg;
468 void *ptr;
469 u64 res = 0;
470
471 nl_priv->res = (void *)&res;
472
473 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
474 if (!ptr)
475 return -ENOMEM;
476 nla_put_flag(msg, MT76_TM_ATTR_STATS);
477 nla_nest_end(msg, ptr);
478
479 unl_genl_request(&nl_priv->unl, msg, atenl_nl_dump_cb, (void *)nl_priv);
480
481 if (nl_priv->attr == MT76_TM_STATS_ATTR_TX_DONE)
482 *(u32 *)(hdr->data + 2 + 4 * an->cur_band) = htonl(res);
483
484 return 0;
485}
486
487static int atenl_nl_continuous_tx(struct atenl *an,
488 struct atenl_data *data,
489 struct atenl_nl_priv *nl_priv)
490{
491 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
492 struct nl_msg *msg = nl_priv->msg;
493 u32 *v = (u32 *)hdr->data;
494 u8 band = ntohl(v[0]);
495 bool enable = ntohl(v[1]);
496 void *ptr;
497
498 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
499 if (!ptr)
500 return -ENOMEM;
501
502 if (band >= MAX_BAND_NUM)
503 return -EINVAL;
504
505 if (!enable) {
506 int phy = get_band_val(an, band, phy_idx);
507 char cmd[64];
508
509 atenl_set_attr_state(an, msg, band, MT76_TM_STATE_IDLE);
510 nla_nest_end(msg, ptr);
511 unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
512
513 sprintf(cmd, "iw dev mon%d del", phy);
514 system(cmd);
515 sprintf(cmd, "iw phy phy%d interface add mon%d type monitor", phy, phy);
516 system(cmd);
517 sprintf(cmd, "ifconfig mon%d up", phy);
518 system(cmd);
519
520 return 0;
521 }
522
523 if (get_band_val(an, band, rf_mode) != ATENL_RF_MODE_TEST)
524 return 0;
525
526 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, ntohl(v[2]));
527 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, phy_type_to_attr(ntohl(v[3])));
528 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, ntohl(v[6]));
529
530 atenl_dbg("%s: enable = %d, ant=%u, tx_rate_mode=%u, rate_idx=%u\n",
531 __func__, enable, ntohl(v[2]), ntohl(v[3]), ntohl(v[6]));
532
533 atenl_set_attr_state(an, msg, band, MT76_TM_STATE_TX_CONT);
534
535 nla_nest_end(msg, ptr);
536
537 return unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
538}
539
540static int atenl_nl_get_rx_info_cb(struct nl_msg *msg, void *arg)
541{
542 struct atenl_nl_priv *nl_priv = (struct atenl_nl_priv *)arg;
543 struct atenl *an = nl_priv->an;
544 struct atenl_band *anb = &an->anb[an->cur_band];
545 struct atenl_data *data = nl_priv->res;
546 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
547 struct atenl_rx_info_hdr *rx_hdr;
548 struct atenl_rx_info_band *rx_band;
549 struct atenl_rx_info_user *rx_user;
550 struct atenl_rx_info_path *rx_path;
551 struct atenl_rx_info_comm *rx_comm;
552 struct nlattr *tb1[NUM_MT76_TM_ATTRS];
553 struct nlattr *tb2[NUM_MT76_TM_STATS_ATTRS];
554 struct nlattr *tb3[NUM_MT76_TM_RX_ATTRS];
555 struct nlattr *nl_attr, *cur;
556 struct atenl_rx_stat rx_cur, rx_diff = {};
557 u32 rcpi[4] = {};
558 u32 type_num = htonl(4);
559 s32 ib_rssi[4] = {}, wb_rssi[4] = {};
560 u8 path = an->anb[an->cur_band].chainmask;
561 u8 path_num = __builtin_popcount(path);
562 u8 *buf = hdr->data + 2;
563 int i, rem;
564
565 *(u32 *)buf = type_num;
566 buf += sizeof(type_num);
567
568#define RX_PUT_HDR(_hdr, _type, _val, _size) do { \
569 _hdr->type = htonl(_type); \
570 _hdr->val = htonl(_val); \
571 _hdr->len = htonl(_size); \
572 buf += sizeof(*_hdr); \
573 } while (0)
574
575 rx_hdr = (struct atenl_rx_info_hdr *)buf;
576 RX_PUT_HDR(rx_hdr, 0, BIT(an->cur_band), sizeof(*rx_band));
577 rx_band = (struct atenl_rx_info_band *)buf;
578 buf += sizeof(*rx_band);
579
580 rx_hdr = (struct atenl_rx_info_hdr *)buf;
581 RX_PUT_HDR(rx_hdr, 1, path, path_num * sizeof(*rx_path));
582 rx_path = (struct atenl_rx_info_path *)buf;
583 buf += path_num * sizeof(*rx_path);
584
585 rx_hdr = (struct atenl_rx_info_hdr *)buf;
586 RX_PUT_HDR(rx_hdr, 2, GENMASK(15, 0), 16 * sizeof(*rx_user));
587 rx_user = (struct atenl_rx_info_user *)buf;
588 buf += 16 * sizeof(*rx_user);
589
590 rx_hdr = (struct atenl_rx_info_hdr *)buf;
591 RX_PUT_HDR(rx_hdr, 3, BIT(0), sizeof(*rx_comm));
592 rx_comm = (struct atenl_rx_info_comm *)buf;
593 buf += sizeof(*rx_comm);
594
595 hdr->len = htons(buf - hdr->data);
596
597 nl_attr = unl_find_attr(&nl_priv->unl, msg, NL80211_ATTR_TESTDATA);
598 if (!nl_attr) {
developer5698c9c2022-05-30 16:40:23 +0800599 atenl_err("Testdata attribute not found\n");
developer3abe1ad2022-01-24 11:13:32 +0800600 return NL_SKIP;
601 }
602
603 nla_parse_nested(tb1, MT76_TM_ATTR_MAX, nl_attr, testdata_policy);
604 nla_parse_nested(tb2, MT76_TM_STATS_ATTR_MAX,
605 tb1[MT76_TM_ATTR_STATS], stats_policy);
606
607 rx_cur.total = nla_get_u64(tb2[MT76_TM_STATS_ATTR_RX_PACKETS]);
608 rx_cur.err_cnt = nla_get_u64(tb2[MT76_TM_STATS_ATTR_RX_FCS_ERROR]);
609 rx_cur.len_mismatch = nla_get_u64(tb2[MT76_TM_STATS_ATTR_RX_LEN_MISMATCH]);
610 rx_cur.ok_cnt = rx_cur.total - rx_cur.err_cnt - rx_cur.len_mismatch;
611
developer5698c9c2022-05-30 16:40:23 +0800612 if (!anb->reset_rx_cnt ||
613 get_band_val(an, an->cur_band, cur_state) == MT76_TM_STATE_RX_FRAMES) {
developer3abe1ad2022-01-24 11:13:32 +0800614#define RX_COUNT_DIFF(_field) \
developer5698c9c2022-05-30 16:40:23 +0800615 rx_diff._field = (rx_cur._field) - (anb->rx_stat._field);
developer3abe1ad2022-01-24 11:13:32 +0800616 RX_COUNT_DIFF(total);
617 RX_COUNT_DIFF(err_cnt);
618 RX_COUNT_DIFF(len_mismatch);
619 RX_COUNT_DIFF(ok_cnt);
620#undef RX_COUNT_DIFF
621
622 memcpy(&anb->rx_stat, &rx_cur, sizeof(anb->rx_stat));
623 }
624
625 rx_band->mac_rx_mdrdy_cnt = htonl((u32)rx_diff.total);
626 rx_band->mac_rx_fcs_err_cnt = htonl((u32)rx_diff.err_cnt);
627 rx_band->mac_rx_fcs_ok_cnt = htonl((u32)rx_diff.ok_cnt);
628 rx_band->mac_rx_len_mismatch = htonl((u32)rx_diff.len_mismatch);
629 rx_user->fcs_error_cnt = htonl((u32)rx_diff.err_cnt);
630
631 nla_parse_nested(tb3, MT76_TM_RX_ATTR_MAX,
632 tb2[MT76_TM_STATS_ATTR_LAST_RX], rx_policy);
633
634 rx_user->freq_offset = htonl(nla_get_u32(tb3[MT76_TM_RX_ATTR_FREQ_OFFSET]));
635 rx_user->snr = htonl(nla_get_u8(tb3[MT76_TM_RX_ATTR_SNR]));
636
637 i = 0;
638 nla_for_each_nested(cur, tb3[MT76_TM_RX_ATTR_RCPI], rem) {
639 if (nla_len(cur) != 1 || i >= 4)
640 break;
641
642 rcpi[i++] = nla_get_u8(cur);
643 }
644
645 i = 0;
646 nla_for_each_nested(cur, tb3[MT76_TM_RX_ATTR_IB_RSSI], rem) {
647 if (nla_len(cur) != 1 || i >= 4)
648 break;
649
650 ib_rssi[i++] = (s8)nla_get_u8(cur);
651 }
652
653 i = 0;
654 nla_for_each_nested(cur, tb3[MT76_TM_RX_ATTR_WB_RSSI], rem) {
655 if (nla_len(cur) != 1 || i >= 4)
656 break;
657
658 wb_rssi[i++] = (s8)nla_get_u8(cur);
659 }
660
661 for (i = 0; i < 4; i++) {
662 struct atenl_rx_info_path *path = &rx_path[i];
663
664 path->rcpi = htonl(rcpi[i]);
665 path->rssi = htonl(to_rssi((u8)rcpi[i]));
666 path->fagc_ib_rssi = htonl(ib_rssi[i]);
667 path->fagc_wb_rssi = htonl(wb_rssi[i]);
668 }
669
670 return NL_SKIP;
671}
672
673static int atenl_nl_get_rx_info(struct atenl *an, struct atenl_data *data,
674 struct atenl_nl_priv *nl_priv)
675{
676 struct nl_msg *msg = nl_priv->msg;
677 void *ptr;
678
679 nl_priv->an = an;
680 nl_priv->res = (void *)data;
681
682 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
683 if (!ptr)
684 return -ENOMEM;
685
686 nla_put_flag(msg, MT76_TM_ATTR_STATS);
687
688 nla_nest_end(msg, ptr);
689
690 return unl_genl_request(&nl_priv->unl, msg, atenl_nl_get_rx_info_cb,
691 (void *)nl_priv);
692}
693
694static int
695atenl_nl_set_ru(struct atenl *an, struct atenl_data *data,
696 struct atenl_nl_priv *nl_priv)
697{
698 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
699 struct nl_msg *msg;
700 u32 *v = (u32 *)(hdr->data + 4);
701 u32 seg0_num = ntohl(v[0]); /* v[1] seg1_num unused */
702 void *ptr;
703 int i, ret;
704
705 if (seg0_num > 8)
706 return -EINVAL;
707
708 for (i = 0, v = &v[2]; i < seg0_num; i++, v += 11) {
709 u32 ru_alloc = ntohl(v[1]);
710 u32 aid = ntohl(v[2]);
711 u32 ru_idx = ntohl(v[3]);
712 u32 mcs = ntohl(v[4]);
713 u32 ldpc = ntohl(v[5]);
714 u32 nss = ntohl(v[6]);
715 u32 tx_length = ntohl(v[8]);
716 char buf[10];
717
718 if (unl_genl_init(&nl_priv->unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +0800719 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +0800720 return 2;
721 }
722
723 msg = unl_genl_msg(&nl_priv->unl, NL80211_CMD_TESTMODE, false);
724 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, an->cur_band, phy_idx));
725
726 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
727 if (!ptr)
728 return -ENOMEM;
729
730 if (i == 0)
731 atenl_set_attr_state(an, msg, an->cur_band, MT76_TM_STATE_IDLE);
732
733 nla_put_u8(msg, MT76_TM_ATTR_AID, aid);
734 nla_put_u8(msg, MT76_TM_ATTR_RU_IDX, ru_idx);
735 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, mcs);
736 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, ldpc);
737 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, nss);
developer763ab652022-06-14 18:38:23 +0800738 atenl_set_attr_tx_length(an, msg, tx_length, true);
developer3abe1ad2022-01-24 11:13:32 +0800739
740 ret = snprintf(buf, sizeof(buf), "%x", ru_alloc);
741 if (snprintf_error(sizeof(buf), ret))
742 return -EINVAL;
743
744 nla_put_u8(msg, MT76_TM_ATTR_RU_ALLOC, strtol(buf, NULL, 2));
745
746 nla_nest_end(msg, ptr);
747
748 unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
749
750 unl_free(&nl_priv->unl);
751 }
752
753 return 0;
754}
755
developer5698c9c2022-05-30 16:40:23 +0800756static int
757atenl_nl_ibf_init(struct atenl *an, u8 band)
758{
759 struct atenl_nl_priv nl_priv = {};
760 struct nl_msg *msg;
761 void *ptr, *a;
762 int ret;
763
764 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
765 atenl_err("Failed to connect to nl80211\n");
766 return 2;
767 }
768
769 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
770 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, band, phy_idx));
771
772 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
773 if (!ptr) {
774 ret = -ENOMEM;
775 goto out;
776 }
777
778 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, MT76_TM_TX_MODE_HT);
779 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, an->ibf_mcs);
780 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, an->ibf_ant);
781 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, MT76_TM_TXBF_ACT_INIT);
782
783 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
784 if (!a) {
785 ret = -ENOMEM;
786 goto out;
787 }
788 nla_put_u16(msg, 0, 1);
789 nla_nest_end(msg, a);
790
791 nla_nest_end(msg, ptr);
792
793 ret = unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
794
795out:
796 unl_free(&nl_priv.unl);
797 return ret;
798}
799
800static int
801atenl_nl_ibf_e2p_update(struct atenl *an)
802{
803 struct atenl_nl_priv nl_priv = {};
804 struct nl_msg *msg;
805 void *ptr, *a;
806 int ret;
807
808 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
809 atenl_err("Failed to connect to nl80211\n");
810 return 2;
811 }
812
813 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
814 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, an->cur_band, phy_idx));
815
816 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
817 if (!ptr) {
818 ret = -ENOMEM;
819 goto out;
820 }
821
822 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, MT76_TM_TXBF_ACT_E2P_UPDATE);
823 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
824 if (!a) {
825 ret = -ENOMEM;
826 goto out;
827 }
828 nla_put_u16(msg, 0, 0);
829 nla_nest_end(msg, a);
830
831 nla_nest_end(msg, ptr);
832
833 ret = unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
834
835out:
836 unl_free(&nl_priv.unl);
837 return ret;
838}
839
840static void
841atenl_get_ibf_cal_result(struct atenl *an)
842{
843 u16 offset;
844
845 if (an->adie_id == 0x7975)
846 offset = 0x651;
847 else if (an->adie_id == 0x7976)
848 offset = 0x60a;
849
850 /* per group size = 40, for group 0-8 */
851 atenl_eeprom_read_from_driver(an, offset, 40 * 9);
852}
853
854static int
855atenl_nl_ibf_set_val(struct atenl *an, struct atenl_data *data,
856 struct atenl_nl_priv *nl_priv)
developer3abe1ad2022-01-24 11:13:32 +0800857{
858#define MT_IBF(_act) MT76_TM_TXBF_ACT_##_act
859 static const u8 bf_act_map[] = {
860 [TXBF_ACT_IBF_PHASE_COMP] = MT_IBF(PHASE_COMP),
861 [TXBF_ACT_IBF_PROF_UPDATE] = MT_IBF(IBF_PROF_UPDATE),
862 [TXBF_ACT_EBF_PROF_UPDATE] = MT_IBF(EBF_PROF_UPDATE),
863 [TXBF_ACT_IBF_PHASE_CAL] = MT_IBF(PHASE_CAL),
864 };
865#undef MT_IBF
866 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
867 struct nl_msg *msg = nl_priv->msg;
868 u32 *v = (u32 *)(hdr->data + 4);
869 u32 action = ntohl(v[0]);
870 u16 val[8];
developer5698c9c2022-05-30 16:40:23 +0800871 u8 tmp_ant;
developer3abe1ad2022-01-24 11:13:32 +0800872 void *ptr, *a;
873 char cmd[64];
874 int i;
875
876 for (i = 0; i < 8; i++)
877 val[i] = ntohl(v[i + 1]);
878
879 atenl_dbg("%s: action = %u, val = %u, %u, %u, %u, %u\n",
880 __func__, action, val[0], val[1], val[2], val[3], val[4]);
881
882 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
883 if (!ptr)
884 return -ENOMEM;
885
886 switch (action) {
developer3abe1ad2022-01-24 11:13:32 +0800887 case TXBF_ACT_CHANNEL:
developer5698c9c2022-05-30 16:40:23 +0800888 an->cur_band = val[1];
889 /* a sanity to prevent script band idx error */
890 if (val[0] > 14)
891 an->cur_band = 1;
892 atenl_nl_ibf_init(an, an->cur_band);
893 atenl_set_channel(an, 0, an->cur_band, val[0], 0, 0);
894
895 nla_put_u8(msg, MT76_TM_ATTR_AID, 0);
developer3abe1ad2022-01-24 11:13:32 +0800896 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, MT76_TM_TXBF_ACT_UPDATE_CH);
897 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
898 if (!a)
899 return -ENOMEM;
900 nla_put_u16(msg, 0, 0);
901 nla_nest_end(msg, a);
developer763ab652022-06-14 18:38:23 +0800902
903 an->ibf_cal = true;
developer3abe1ad2022-01-24 11:13:32 +0800904 break;
905 case TXBF_ACT_MCS:
developer5698c9c2022-05-30 16:40:23 +0800906 tmp_ant = (1 << DIV_ROUND_UP(val[0], 8)) - 1 ?: 1;
907 /* sometimes the correct band idx will be set after this action,
908 * so maintain a temp variable to allow mcs update in anthor action.
909 */
910 an->ibf_mcs = val[0];
911 an->ibf_ant = tmp_ant;
912 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, an->ibf_mcs);
913 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, an->ibf_ant);
developer3abe1ad2022-01-24 11:13:32 +0800914 break;
915 case TXBF_ACT_TX_ANT:
916 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, val[0]);
917 break;
918 case TXBF_ACT_RX_START:
919 atenl_set_attr_state(an, msg, an->cur_band, MT76_TM_STATE_RX_FRAMES);
920 break;
921 case TXBF_ACT_RX_ANT:
922 nla_put_u8(msg, MT76_TM_ATTR_TX_ANTENNA, val[0]);
923 break;
924 case TXBF_ACT_TX_PKT:
925 nla_put_u8(msg, MT76_TM_ATTR_AID, val[1]);
developer3abe1ad2022-01-24 11:13:32 +0800926 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, MT76_TM_TXBF_ACT_TX_PREP);
developer5698c9c2022-05-30 16:40:23 +0800927 nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, 10000000);
developer763ab652022-06-14 18:38:23 +0800928 atenl_set_attr_tx_length(an, msg, 1024, false);
developer3abe1ad2022-01-24 11:13:32 +0800929 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
930 if (!a)
931 return -ENOMEM;
932
933 for (i = 0; i < 5; i++)
934 nla_put_u16(msg, i, val[i]);
935 nla_nest_end(msg, a);
936
937 atenl_set_attr_state(an, msg, an->cur_band, MT76_TM_STATE_TX_FRAMES);
938 break;
939 case TXBF_ACT_IBF_PHASE_COMP:
developer5698c9c2022-05-30 16:40:23 +0800940 nla_put_u8(msg, MT76_TM_ATTR_AID, 1);
developer3abe1ad2022-01-24 11:13:32 +0800941 case TXBF_ACT_IBF_PROF_UPDATE:
942 case TXBF_ACT_EBF_PROF_UPDATE:
943 case TXBF_ACT_IBF_PHASE_CAL:
944 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, bf_act_map[action]);
945 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
946 if (!a)
947 return -ENOMEM;
948
949 for (i = 0; i < 5; i++)
950 nla_put_u16(msg, i, val[i]);
951 nla_nest_end(msg, a);
952 break;
953 case TXBF_ACT_IBF_PHASE_E2P_UPDATE:
developer5698c9c2022-05-30 16:40:23 +0800954 atenl_nl_ibf_e2p_update(an);
955 atenl_get_ibf_cal_result(an);
developer3abe1ad2022-01-24 11:13:32 +0800956
957 nla_put_u8(msg, MT76_TM_ATTR_AID, 0);
958 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, MT76_TM_TXBF_ACT_INIT);
959
960 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
961 if (!a)
962 return -ENOMEM;
963 nla_put_u16(msg, 0, 0);
964 nla_nest_end(msg, a);
developer763ab652022-06-14 18:38:23 +0800965
966 an->ibf_cal = false;
developer3abe1ad2022-01-24 11:13:32 +0800967 break;
developer5698c9c2022-05-30 16:40:23 +0800968 case TXBF_ACT_INIT:
969 case TXBF_ACT_POWER:
developer3abe1ad2022-01-24 11:13:32 +0800970 default:
971 break;
972 }
973
974 nla_nest_end(msg, ptr);
975
developer5698c9c2022-05-30 16:40:23 +0800976 *(u32 *)(hdr->data + 2) = data->ext_id;
developer3abe1ad2022-01-24 11:13:32 +0800977
978 return unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
979}
980
981static int
982atenl_nl_ibf_get_status(struct atenl *an, struct atenl_data *data,
983 struct atenl_nl_priv *nl_priv)
984{
985 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
986 u32 status = htonl(1);
987
developer5698c9c2022-05-30 16:40:23 +0800988 *(u32 *)(hdr->data + 2) = data->ext_id;
developer3abe1ad2022-01-24 11:13:32 +0800989 memcpy(hdr->data + 6, &status, 4);
990
991 return 0;
992}
993
994static int
995atenl_nl_ibf_profile_update_all(struct atenl *an, struct atenl_data *data,
996 struct atenl_nl_priv *nl_priv)
997{
998 struct atenl_cmd_hdr *hdr = atenl_hdr(data);
999 struct nl_msg *msg;
1000 void *ptr, *a;
1001 u32 *v = (u32 *)(hdr->data + 4);
1002 u16 pfmu_idx = ntohl(v[0]);
1003 int i;
1004
1005 for (i = 0, v = &v[5]; i < 64; i++, v += 5) {
1006 int j;
1007
1008 if (unl_genl_init(&nl_priv->unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001009 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001010 return 2;
1011 }
1012
1013 msg = unl_genl_msg(&nl_priv->unl, NL80211_CMD_TESTMODE, false);
1014 nla_put_u32(msg, NL80211_ATTR_WIPHY,
1015 get_band_val(an, an->cur_band, phy_idx));
1016
1017 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
1018 if (!ptr)
1019 return -ENOMEM;
1020
1021 nla_put_u8(msg, MT76_TM_ATTR_TXBF_ACT, MT76_TM_TXBF_ACT_PROF_UPDATE_ALL);
1022 a = nla_nest_start(msg, MT76_TM_ATTR_TXBF_PARAM);
1023 if (!a)
1024 return -ENOMEM;
1025 nla_put_u16(msg, 0, pfmu_idx);
1026
1027 for (j = 0; j < 5; j++)
1028 nla_put_u16(msg, j + 1, ntohl(v[j]));
1029 nla_nest_end(msg, a);
1030
1031 nla_nest_end(msg, ptr);
1032
1033 unl_genl_request(&nl_priv->unl, msg, NULL, NULL);
1034
1035 unl_free(&nl_priv->unl);
1036 }
1037
developer5698c9c2022-05-30 16:40:23 +08001038 *(u32 *)(hdr->data + 2) = data->ext_id;
developer3abe1ad2022-01-24 11:13:32 +08001039
1040 return 0;
1041}
1042
1043#define NL_OPS_GROUP(cmd, ...) [HQA_CMD_##cmd] = { __VA_ARGS__ }
1044static const struct atenl_nl_ops nl_ops[] = {
1045 NL_OPS_GROUP(SET_TX_PATH, .set=MT76_TM_ATTR_TX_ANTENNA),
1046 NL_OPS_GROUP(SET_TX_POWER, .set=MT76_TM_ATTR_TX_POWER),
1047 NL_OPS_GROUP(SET_RX_PATH, .set=MT76_TM_ATTR_TX_ANTENNA),
1048 NL_OPS_GROUP(SET_FREQ_OFFSET, .set=MT76_TM_ATTR_FREQ_OFFSET),
1049 NL_OPS_GROUP(SET_CFG, .ops=atenl_nl_set_cfg),
1050 NL_OPS_GROUP(SET_TSSI, .ops=atenl_nl_set_cfg),
1051 NL_OPS_GROUP(CONTINUOUS_TX, .ops=atenl_nl_continuous_tx),
1052 NL_OPS_GROUP(GET_TX_INFO, .dump=MT76_TM_STATS_ATTR_TX_DONE),
1053 NL_OPS_GROUP(GET_RX_INFO, .ops=atenl_nl_get_rx_info, .dump=true),
1054 NL_OPS_GROUP(SET_RU, .ops=atenl_nl_set_ru),
1055};
1056#undef NL_OPS_GROUP
1057
1058#define NL_OPS_EXT(cmd, ...) [HQA_EXT_CMD_##cmd] = { __VA_ARGS__ }
1059static const struct atenl_nl_ops nl_ops_ext[] = {
1060 NL_OPS_EXT(SET_TX, .ops=atenl_nl_set_tx),
1061 NL_OPS_EXT(START_TX, .ops=atenl_nl_tx),
1062 NL_OPS_EXT(STOP_TX, .ops=atenl_nl_tx),
1063 NL_OPS_EXT(START_RX, .ops=atenl_nl_rx),
1064 NL_OPS_EXT(STOP_RX, .ops=atenl_nl_rx),
1065 NL_OPS_EXT(OFF_CH_SCAN, .ops=atenl_off_ch_scan),
1066 NL_OPS_EXT(IBF_SET_VAL, .ops=atenl_nl_ibf_set_val),
1067 NL_OPS_EXT(IBF_GET_STATUS, .ops=atenl_nl_ibf_get_status),
1068 NL_OPS_EXT(IBF_PROF_UPDATE_ALL, .ops=atenl_nl_ibf_profile_update_all),
1069};
1070#undef NL_OPS_EXT
1071
1072int atenl_nl_process(struct atenl *an, struct atenl_data *data)
1073{
1074 struct atenl_nl_priv nl_priv = {};
1075 const struct atenl_nl_ops *ops;
1076 struct nl_msg *msg;
1077 int ret = 0;
1078
1079 if (data->ext_cmd != 0)
1080 ops = &nl_ops_ext[data->ext_cmd];
1081 else
1082 ops = &nl_ops[data->cmd];
1083
1084 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001085 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001086 return -1;
1087 }
1088
1089 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, !!ops->dump);
1090 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, an->cur_band, phy_idx));
1091 nl_priv.msg = msg;
1092
1093 if (ops->ops) {
1094 ret = ops->ops(an, data, &nl_priv);
1095 } else if (ops->dump) {
1096 nl_priv.attr = ops->dump;
1097 ret = atenl_nl_dump_attr(an, data, &nl_priv);
1098 } else {
1099 nl_priv.attr = ops->set;
1100 ret = atenl_nl_set_attr(an, data, &nl_priv);
1101 }
1102
1103 if (ret)
developer5698c9c2022-05-30 16:40:23 +08001104 atenl_err("command process error: 0x%x (0x%x)\n", data->cmd_id, data->ext_id);
developer3abe1ad2022-01-24 11:13:32 +08001105
1106 unl_free(&nl_priv.unl);
1107
1108 return ret;
1109}
1110
1111int atenl_nl_process_many(struct atenl *an, struct atenl_data *data)
1112{
1113 struct atenl_nl_priv nl_priv = {};
1114 const struct atenl_nl_ops *ops;
1115 int ret = 0;
1116
1117 if (data->ext_cmd != 0)
1118 ops = &nl_ops_ext[data->ext_cmd];
1119 else
1120 ops = &nl_ops[data->cmd];
1121
1122 if (ops->ops)
1123 ret = ops->ops(an, data, &nl_priv);
1124
1125 return ret;
1126}
1127
1128int atenl_nl_set_state(struct atenl *an, u8 band,
1129 enum mt76_testmode_state state)
1130{
1131 struct atenl_nl_priv nl_priv = {};
1132 struct nl_msg *msg;
1133 void *ptr;
1134
1135 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001136 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001137 return 2;
1138 }
1139
1140 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
1141 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, band, phy_idx));
1142
1143 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
1144 if (!ptr)
1145 return -ENOMEM;
1146
1147 atenl_set_attr_state(an, msg, band, state);
1148
1149 nla_nest_end(msg, ptr);
1150
1151 unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
1152
1153 unl_free(&nl_priv.unl);
1154
1155 return 0;
1156}
1157
developer5698c9c2022-05-30 16:40:23 +08001158int atenl_nl_set_aid(struct atenl *an, u8 band, u8 aid)
1159{
1160 struct atenl_nl_priv nl_priv = {};
1161 struct nl_msg *msg;
1162 void *ptr;
1163
1164 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
1165 atenl_err("Failed to connect to nl80211\n");
1166 return 2;
1167 }
1168
1169 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
1170 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, band, phy_idx));
1171
1172 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
1173 if (!ptr)
1174 return -ENOMEM;
1175
1176 nla_put_u8(msg, MT76_TM_ATTR_AID, aid);
1177
1178 nla_nest_end(msg, ptr);
1179
1180 unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
1181
1182 unl_free(&nl_priv.unl);
1183
1184 return 0;
1185}
1186
developer3abe1ad2022-01-24 11:13:32 +08001187static int atenl_nl_check_mtd_cb(struct nl_msg *msg, void *arg)
1188{
1189 struct atenl_nl_priv *nl_priv = (struct atenl_nl_priv *)arg;
1190 struct atenl *an = nl_priv->an;
1191 struct nlattr *tb[NUM_MT76_TM_ATTRS];
1192 struct nlattr *attr;
1193
1194 attr = unl_find_attr(&nl_priv->unl, msg, NL80211_ATTR_TESTDATA);
1195 if (!attr)
1196 return NL_SKIP;
1197
1198 nla_parse_nested(tb, MT76_TM_ATTR_MAX, attr, testdata_policy);
1199 if (!tb[MT76_TM_ATTR_MTD_PART] || !tb[MT76_TM_ATTR_MTD_OFFSET])
1200 return NL_SKIP;
1201
1202 an->mtd_part = strdup(nla_get_string(tb[MT76_TM_ATTR_MTD_PART]));
1203 an->mtd_offset = nla_get_u32(tb[MT76_TM_ATTR_MTD_OFFSET]);
1204
1205 return NL_SKIP;
1206}
1207
1208int atenl_nl_check_mtd(struct atenl *an)
1209{
1210 struct atenl_nl_priv nl_priv = { .an = an };
1211 struct nl_msg *msg;
1212
1213 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001214 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001215 return 2;
1216 }
1217
1218 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, true);
1219 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, 0, phy_idx));
1220 unl_genl_request(&nl_priv.unl, msg, atenl_nl_check_mtd_cb, (void *)&nl_priv);
1221
1222 unl_free(&nl_priv.unl);
1223
1224 return 0;
1225}
1226
1227int atenl_nl_write_eeprom(struct atenl *an, u32 offset, u8 *val, int len)
1228{
1229 struct atenl_nl_priv nl_priv = {};
1230 struct nl_msg *msg;
1231 void *ptr, *a;
1232 int i;
1233
1234 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001235 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001236 return 2;
1237 }
1238
1239 if (len > 16)
1240 return -EINVAL;
1241
1242 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
1243 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, 0, phy_idx));
1244
1245 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
1246 if (!ptr)
1247 return -ENOMEM;
1248
1249 nla_put_u8(msg, MT76_TM_ATTR_EEPROM_ACTION,
1250 MT76_TM_EEPROM_ACTION_UPDATE_DATA);
1251 nla_put_u32(msg, MT76_TM_ATTR_EEPROM_OFFSET, offset);
1252
1253 a = nla_nest_start(msg, MT76_TM_ATTR_EEPROM_VAL);
1254 if (!a)
1255 return -ENOMEM;
1256
1257 for (i = 0; i < len; i++)
1258 if (nla_put_u8(msg, i, val[i]))
1259 goto out;
1260
1261 nla_nest_end(msg, a);
1262
1263 nla_nest_end(msg, ptr);
1264
1265 unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
1266
1267 unl_free(&nl_priv.unl);
1268
1269out:
1270 return 0;
1271}
1272
developer9b7cdad2022-03-10 14:24:55 +08001273int atenl_nl_write_efuse_all(struct atenl *an)
developer3abe1ad2022-01-24 11:13:32 +08001274{
1275 struct atenl_nl_priv nl_priv = {};
1276 struct nl_msg *msg;
1277 void *ptr;
1278
1279 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001280 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001281 return 2;
1282 }
1283
1284 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
1285 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, 0, phy_idx));
1286
1287 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
1288 if (!ptr)
1289 return -ENOMEM;
1290
1291 nla_put_u8(msg, MT76_TM_ATTR_EEPROM_ACTION,
1292 MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE);
1293
1294 nla_nest_end(msg, ptr);
1295
1296 unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
1297
1298 unl_free(&nl_priv.unl);
1299
1300 return 0;
1301}
1302
1303int atenl_nl_update_buffer_mode(struct atenl *an)
1304{
1305 struct atenl_nl_priv nl_priv = {};
1306 struct nl_msg *msg;
1307 void *ptr;
1308
1309 if (unl_genl_init(&nl_priv.unl, "nl80211") < 0) {
developer5698c9c2022-05-30 16:40:23 +08001310 atenl_err("Failed to connect to nl80211\n");
developer3abe1ad2022-01-24 11:13:32 +08001311 return 2;
1312 }
1313
1314 msg = unl_genl_msg(&nl_priv.unl, NL80211_CMD_TESTMODE, false);
1315 nla_put_u32(msg, NL80211_ATTR_WIPHY, get_band_val(an, 0, phy_idx));
1316
1317 ptr = nla_nest_start(msg, NL80211_ATTR_TESTDATA);
1318 if (!ptr)
1319 return -ENOMEM;
1320
1321 nla_put_u8(msg, MT76_TM_ATTR_EEPROM_ACTION,
1322 MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE);
1323
1324 nla_nest_end(msg, ptr);
1325
1326 unl_genl_request(&nl_priv.unl, msg, NULL, NULL);
1327
1328 unl_free(&nl_priv.unl);
1329
1330 return 0;
1331}
1332