blob: b47f160833d3091f5244cb26236d8ccc680190a4 [file] [log] [blame]
developer78848c62023-04-06 13:44:00 +08001From ead183c5143c45e4f188d0bb0214b0d41c113ed2 Mon Sep 17 00:00:00 2001
developerd5789dc2023-03-27 11:22:06 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Wed, 1 Mar 2023 11:59:16 +0800
developer78848c62023-04-06 13:44:00 +08004Subject: [PATCH 27/29] wifi: mt76: testmode: add basic testmode support
developerd5789dc2023-03-27 11:22:06 +08005
6Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
7---
8 eeprom.c | 6 +-
9 mac80211.c | 3 +-
10 mt76.h | 11 +
11 mt76_connac_mcu.h | 2 +
12 mt7996/Makefile | 2 +
13 mt7996/eeprom.c | 35 ++-
14 mt7996/eeprom.h | 1 +
15 mt7996/init.c | 7 +
16 mt7996/main.c | 15 ++
17 mt7996/mcu.c | 39 ++-
18 mt7996/mcu.h | 27 ++
19 mt7996/mt7996.h | 22 ++
20 mt7996/testmode.c | 615 ++++++++++++++++++++++++++++++++++++++++++++++
21 mt7996/testmode.h | 292 ++++++++++++++++++++++
22 testmode.c | 45 +++-
23 testmode.h | 60 +++++
24 tools/fields.c | 92 +++++++
25 17 files changed, 1257 insertions(+), 17 deletions(-)
26 create mode 100644 mt7996/testmode.c
27 create mode 100644 mt7996/testmode.h
28
29diff --git a/eeprom.c b/eeprom.c
developer78848c62023-04-06 13:44:00 +080030index ea54b7a..263e508 100644
developerd5789dc2023-03-27 11:22:06 +080031--- a/eeprom.c
32+++ b/eeprom.c
33@@ -89,8 +89,10 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
34 }
35
36 #ifdef CONFIG_NL80211_TESTMODE
37- dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
38- dev->test_mtd.offset = offset;
39+ if (len == dev->eeprom.size) {
40+ dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
41+ dev->test_mtd.offset = offset;
42+ }
43 #endif
44
45 out_put_node:
46diff --git a/mac80211.c b/mac80211.c
developer78848c62023-04-06 13:44:00 +080047index e53166f..a4b3d34 100644
developerd5789dc2023-03-27 11:22:06 +080048--- a/mac80211.c
49+++ b/mac80211.c
50@@ -826,7 +826,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
51 }
52
53 #ifdef CONFIG_NL80211_TESTMODE
54- if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
55+ if (!(phy->test.flag & MT_TM_FW_RX_COUNT) &&
56+ phy->test.state == MT76_TM_STATE_RX_FRAMES) {
57 phy->test.rx_stats.packets[q]++;
58 if (status->flag & RX_FLAG_FAILED_FCS_CRC)
59 phy->test.rx_stats.fcs_error[q]++;
60diff --git a/mt76.h b/mt76.h
developer78848c62023-04-06 13:44:00 +080061index c3d1313..343bd91 100644
developerd5789dc2023-03-27 11:22:06 +080062--- a/mt76.h
63+++ b/mt76.h
64@@ -652,8 +652,12 @@ struct mt76_testmode_ops {
65 int (*set_params)(struct mt76_phy *phy, struct nlattr **tb,
66 enum mt76_testmode_state new_state);
67 int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg);
68+ void (*reset_rx_stats)(struct mt76_phy *phy);
69+ void (*tx_stop)(struct mt76_phy *phy);
70 };
71
72+#define MT_TM_FW_RX_COUNT BIT(0)
73+
74 struct mt76_testmode_data {
75 enum mt76_testmode_state state;
76
77@@ -669,6 +673,7 @@ struct mt76_testmode_data {
78 u8 tx_rate_sgi;
79 u8 tx_rate_ldpc;
80 u8 tx_rate_stbc;
81+ u16 tx_preamble_puncture;
82 u8 tx_ltf;
83
84 u8 tx_antenna_mask;
85@@ -678,6 +683,9 @@ struct mt76_testmode_data {
86 u32 tx_time;
87 u32 tx_ipg;
88
89+ bool ibf;
90+ bool ebf;
91+
92 u32 freq_offset;
93
94 u8 tx_power[4];
95@@ -692,7 +700,10 @@ struct mt76_testmode_data {
96 struct {
97 u64 packets[__MT_RXQ_MAX];
98 u64 fcs_error[__MT_RXQ_MAX];
99+ u64 len_mismatch;
100 } rx_stats;
101+ u8 flag;
102+ u8 aid;
103 };
104
105 struct mt76_vif {
106diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developer78848c62023-04-06 13:44:00 +0800107index 79dde31..bfbf18d 100644
developerd5789dc2023-03-27 11:22:06 +0800108--- a/mt76_connac_mcu.h
109+++ b/mt76_connac_mcu.h
110@@ -1218,10 +1218,12 @@ enum {
111 MCU_UNI_CMD_EFUSE_CTRL = 0x2d,
112 MCU_UNI_CMD_RA = 0x2f,
113 MCU_UNI_CMD_MURU = 0x31,
114+ MCU_UNI_CMD_TESTMODE_RX_STAT = 0x32,
115 MCU_UNI_CMD_BF = 0x33,
116 MCU_UNI_CMD_CHANNEL_SWITCH = 0x34,
117 MCU_UNI_CMD_THERMAL = 0x35,
118 MCU_UNI_CMD_VOW = 0x37,
119+ MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
120 MCU_UNI_CMD_RRO = 0x57,
121 MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
122 };
123diff --git a/mt7996/Makefile b/mt7996/Makefile
developer78848c62023-04-06 13:44:00 +0800124index bcb9a3c..f9fb1b0 100644
developerd5789dc2023-03-27 11:22:06 +0800125--- a/mt7996/Makefile
126+++ b/mt7996/Makefile
127@@ -4,3 +4,5 @@ obj-$(CONFIG_MT7996E) += mt7996e.o
128
129 mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
130 debugfs.o mmio.o
131+
132+mt7996e-$(CONFIG_NL80211_TESTMODE) += testmode.o
133diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
developer78848c62023-04-06 13:44:00 +0800134index 2e48c5a..64e3c4e 100644
developerd5789dc2023-03-27 11:22:06 +0800135--- a/mt7996/eeprom.c
136+++ b/mt7996/eeprom.c
137@@ -6,6 +6,11 @@
138 #include <linux/firmware.h>
139 #include "mt7996.h"
140 #include "eeprom.h"
141+#include <linux/moduleparam.h>
142+
143+static bool testmode_enable;
144+module_param(testmode_enable, bool, 0644);
145+MODULE_PARM_DESC(testmode_enable, "Enable testmode");
146
147 static int mt7996_check_eeprom(struct mt7996_dev *dev)
148 {
149@@ -23,7 +28,10 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
150 static char *mt7996_eeprom_name(struct mt7996_dev *dev)
151 {
152 /* reserve for future variants */
153- return MT7996_EEPROM_DEFAULT;
154+ if (dev->testmode_enable)
155+ return MT7996_EEPROM_DEFAULT_TM;
156+ else
157+ return MT7996_EEPROM_DEFAULT;
158 }
159
160 static int
161@@ -52,21 +60,36 @@ out:
162 return ret;
163 }
164
165-static int mt7996_eeprom_load(struct mt7996_dev *dev)
166+int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev)
167 {
168+ u8 *eeprom;
169 int ret;
170
171+ /* load eeprom in flash or bin file mode to determine fw mode */
172 ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
173 if (ret < 0)
174 return ret;
175
176 if (ret) {
177 dev->flash_mode = true;
178- } else {
179- u8 free_block_num;
180- u32 block_num, i;
181- u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
182+ eeprom = dev->mt76.eeprom.data;
183+ /* testmode enable priority: eeprom field > module parameter */
184+ dev->testmode_enable = !mt7996_check_eeprom(dev) ? eeprom[MT_EE_TESTMODE_EN] :
185+ testmode_enable;
186+ }
187+
188+ return ret;
189+}
190+
191+static int mt7996_eeprom_load(struct mt7996_dev *dev)
192+{
193+ int ret;
194+ u8 free_block_num;
195+ u32 block_num, i;
196+ u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
197
198+ /* flash or bin file mode eeprom is loaded before mcu init */
199+ if (!dev->flash_mode) {
200 ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num);
201 if (ret < 0)
202 return ret;
203diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
developer78848c62023-04-06 13:44:00 +0800204index cfc4869..f7497c9 100644
developerd5789dc2023-03-27 11:22:06 +0800205--- a/mt7996/eeprom.h
206+++ b/mt7996/eeprom.h
207@@ -14,6 +14,7 @@ enum mt7996_eeprom_field {
208 MT_EE_MAC_ADDR = 0x004,
209 MT_EE_MAC_ADDR2 = 0x00a,
210 MT_EE_WIFI_CONF = 0x190,
211+ MT_EE_TESTMODE_EN = 0x1af,
212 MT_EE_MAC_ADDR3 = 0x2c0,
213 MT_EE_RATE_DELTA_2G = 0x1400,
214 MT_EE_RATE_DELTA_5G = 0x147d,
215diff --git a/mt7996/init.c b/mt7996/init.c
developer78848c62023-04-06 13:44:00 +0800216index 381917a..29a6783 100644
developerd5789dc2023-03-27 11:22:06 +0800217--- a/mt7996/init.c
218+++ b/mt7996/init.c
219@@ -621,6 +621,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
220
221 set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
222
223+ ret = mt7996_eeprom_check_fw_mode(dev);
224+ if (ret < 0)
225+ return ret;
226+
227 ret = mt7996_mcu_init(dev);
228 if (ret)
229 return ret;
230@@ -1055,6 +1059,9 @@ int mt7996_register_device(struct mt7996_dev *dev)
231
232 mt7996_init_wiphy(hw);
233
234+#ifdef CONFIG_NL80211_TESTMODE
235+ dev->mt76.test_ops = &mt7996_testmode_ops;
236+#endif
237 /* init led callbacks */
238 if (IS_ENABLED(CONFIG_MT76_LEDS)) {
239 dev->mphy.leds.cdev.brightness_set = mt7996_led_set_brightness;
240diff --git a/mt7996/main.c b/mt7996/main.c
developer78848c62023-04-06 13:44:00 +0800241index 4e9536e..b24c75a 100644
developerd5789dc2023-03-27 11:22:06 +0800242--- a/mt7996/main.c
243+++ b/mt7996/main.c
244@@ -22,6 +22,17 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
245 return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
246 }
247
248+static void mt7996_testmode_disable_all(struct mt7996_dev *dev)
249+{
250+ struct mt7996_phy *phy;
251+ int i;
252+
253+ for (i = 0; i < __MT_MAX_BAND; i++) {
254+ phy = __mt7996_phy(dev, i);
255+ mt76_testmode_set_state(phy->mt76, MT76_TM_STATE_OFF);
256+ }
257+}
258+
259 int mt7996_run(struct ieee80211_hw *hw)
260 {
261 struct mt7996_dev *dev = mt7996_hw_dev(hw);
262@@ -36,6 +47,8 @@ int mt7996_run(struct ieee80211_hw *hw)
263 goto out;
264 }
265
266+ mt7996_testmode_disable_all(dev);
267+
268 mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
269
270 ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
271@@ -1343,6 +1356,8 @@ const struct ieee80211_ops mt7996_ops = {
272 .sta_set_decap_offload = mt7996_sta_set_decap_offload,
273 .add_twt_setup = mt7996_mac_add_twt_setup,
274 .twt_teardown_request = mt7996_twt_teardown_request,
275+ CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
276+ CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
277 #ifdef CONFIG_MAC80211_DEBUGFS
278 .sta_add_debugfs = mt7996_sta_add_debugfs,
279 #endif
280diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer78848c62023-04-06 13:44:00 +0800281index deb6e1e..0a52afd 100644
developerd5789dc2023-03-27 11:22:06 +0800282--- a/mt7996/mcu.c
283+++ b/mt7996/mcu.c
284@@ -2580,7 +2580,10 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
285 release_firmware(fw); \
286 } while (0)
287
288- LOAD_RAM(WM);
289+ if (dev->testmode_enable)
290+ LOAD_RAM(WM_TM);
291+ else
292+ LOAD_RAM(WM);
293 LOAD_RAM(DSP);
294 LOAD_RAM(WA);
295 #undef LOAD_RAM
296@@ -4109,3 +4112,37 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
297 return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
298 sizeof(req), true);
299 }
300+
301+int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data)
302+{
303+ struct mt7996_dev *dev = phy->dev;
304+ struct tx_power_ctrl req = {
305+ .tag = cpu_to_le16(power_ctrl_id),
306+ .len = cpu_to_le16(sizeof(req) - 4),
307+ .power_ctrl_id = power_ctrl_id,
308+ .band_idx = phy->mt76->band_idx,
309+ };
310+
311+ switch (power_ctrl_id) {
312+ case UNI_TXPOWER_SKU_POWER_LIMIT_CTRL:
313+ req.sku_enable = !!data;
314+ break;
315+ case UNI_TXPOWER_PERCENTAGE_CTRL:
316+ req.percentage_ctrl_enable = !!data;
317+ break;
318+ case UNI_TXPOWER_PERCENTAGE_DROP_CTRL:
319+ req.power_drop_level = data;
320+ break;
321+ case UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL:
322+ req.bf_backoff_enable = !!data;
323+ break;
324+ case UNI_TXPOWER_ATE_MODE_CTRL:
325+ req.ate_mode_enable = !!data;
326+ break;
327+ default:
328+ req.sku_enable = !!data;
329+ }
330+
331+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER),
332+ &req, sizeof(req), false);
333+}
334diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developer78848c62023-04-06 13:44:00 +0800335index 778deed..ebc6271 100644
developerd5789dc2023-03-27 11:22:06 +0800336--- a/mt7996/mcu.h
337+++ b/mt7996/mcu.h
338@@ -686,6 +686,33 @@ enum {
339 UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
340 };
341
342+struct tx_power_ctrl {
343+ u8 _rsv[4];
344+
345+ __le16 tag;
346+ __le16 len;
347+
348+ u8 power_ctrl_id;
349+ union {
350+ bool sku_enable;
351+ bool ate_mode_enable;
352+ bool percentage_ctrl_enable;
353+ bool bf_backoff_enable;
354+ u8 power_drop_level;
355+ };
356+ u8 band_idx;
357+ u8 rsv[1];
358+} __packed;
359+
360+enum {
361+ UNI_TXPOWER_SKU_POWER_LIMIT_CTRL = 0,
362+ UNI_TXPOWER_PERCENTAGE_CTRL = 1,
363+ UNI_TXPOWER_PERCENTAGE_DROP_CTRL = 2,
364+ UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
365+ UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
366+ UNI_TXPOWER_ATE_MODE_CTRL = 6,
367+};
368+
369 enum {
370 UNI_CMD_ACCESS_REG_BASIC = 0x0,
371 UNI_CMD_ACCESS_RF_REG_BASIC,
372diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer78848c62023-04-06 13:44:00 +0800373index c2f8900..e3fd50f 100644
developerd5789dc2023-03-27 11:22:06 +0800374--- a/mt7996/mt7996.h
375+++ b/mt7996/mt7996.h
376@@ -30,9 +30,11 @@
377 #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin"
378 #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin"
379 #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
380+#define MT7996_FIRMWARE_WM_TM "mediatek/mt7996/mt7996_wm_tm.bin"
381 #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
382
383 #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
384+#define MT7996_EEPROM_DEFAULT_TM "mediatek/mt7996/mt7996_eeprom_tm.bin"
385 #define MT7996_EEPROM_SIZE 7680
386 #define MT7996_EEPROM_BLOCK_SIZE 16
387 #define MT7996_TOKEN_SIZE 8192
388@@ -58,6 +60,7 @@ struct mt7996_dfs_pattern;
389
390 enum mt7996_ram_type {
391 MT7996_RAM_TYPE_WM = 0,
392+ MT7996_RAM_TYPE_WM_TM = MT7996_RAM_TYPE_WM,
393 MT7996_RAM_TYPE_WA,
394 MT7996_RAM_TYPE_DSP,
395 };
396@@ -245,6 +248,20 @@ struct mt7996_phy {
397
398 struct mib_stats mib;
399 struct mt76_channel_state state_ts;
400+
401+#ifdef CONFIG_NL80211_TESTMODE
402+ struct {
403+ u32 *reg_backup;
404+
405+ s32 last_freq_offset;
406+ u8 last_rcpi[4];
407+ s8 last_ib_rssi[4];
408+ s8 last_wb_rssi[4];
409+ u8 last_snr;
410+
411+ u8 spe_idx;
412+ } test;
413+#endif
414 };
415
416 struct mt7996_dev {
417@@ -296,6 +313,8 @@ struct mt7996_dev {
418 bool flash_mode:1;
419 bool has_eht:1;
420
421+ bool testmode_enable;
422+
423 bool ibf;
424 u8 fw_debug_wm;
425 u8 fw_debug_wa;
426@@ -401,6 +420,7 @@ mt7996_phy3(struct mt7996_dev *dev)
427 extern const struct ieee80211_ops mt7996_ops;
428 extern struct pci_driver mt7996_pci_driver;
429 extern struct pci_driver mt7996_hif_driver;
430+extern const struct mt76_testmode_ops mt7996_testmode_ops;
431
432 struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
433 void __iomem *mem_base, u32 device_id);
434@@ -410,6 +430,7 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
435 int mt7996_register_device(struct mt7996_dev *dev);
436 void mt7996_unregister_device(struct mt7996_dev *dev);
437 int mt7996_eeprom_init(struct mt7996_dev *dev);
438+int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev);
439 int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
440 int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
441 struct ieee80211_channel *chan);
442@@ -485,6 +506,7 @@ int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
443 int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
444 void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
445 void mt7996_mcu_exit(struct mt7996_dev *dev);
446+int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
447
448 static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
449 {
450diff --git a/mt7996/testmode.c b/mt7996/testmode.c
451new file mode 100644
developer78848c62023-04-06 13:44:00 +0800452index 0000000..5dbbb78
developerd5789dc2023-03-27 11:22:06 +0800453--- /dev/null
454+++ b/mt7996/testmode.c
455@@ -0,0 +1,615 @@
456+// SPDX-License-Identifier: ISC
457+/*
458+ * Copyright (C) 2022 MediaTek Inc.
459+ */
460+
461+#include "mt7996.h"
462+#include "mac.h"
463+#include "mcu.h"
464+#include "testmode.h"
465+
466+enum {
467+ TM_CHANGED_TXPOWER,
468+ TM_CHANGED_FREQ_OFFSET,
469+ TM_CHANGED_TX_LENGTH,
470+ TM_CHANGED_TX_TIME,
471+
472+ /* must be last */
473+ NUM_TM_CHANGED
474+};
475+
476+static const u8 tm_change_map[] = {
477+ [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER,
478+ [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,
479+ [TM_CHANGED_TX_LENGTH] = MT76_TM_ATTR_TX_LENGTH,
480+ [TM_CHANGED_TX_TIME] = MT76_TM_ATTR_TX_TIME,
481+};
482+
483+static u8 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_method method)
484+{
485+ static const u8 width_to_bw[][NUM_BW_MAP] = {
486+ [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ},
487+ [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ},
488+ [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ},
489+ [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ},
490+ [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ},
491+ [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ},
492+ [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
493+ [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
494+ [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ},
495+ };
496+
497+ if (width >= ARRAY_SIZE(width_to_bw))
498+ return 0;
499+
500+ return width_to_bw[width][method];
501+}
502+
503+static u8 mt7996_tm_rate_to_phy(u8 tx_rate_mode)
504+{
505+ static const u8 rate_to_phy[] = {
506+ [MT76_TM_TX_MODE_CCK] = MT_PHY_TYPE_CCK,
507+ [MT76_TM_TX_MODE_OFDM] = MT_PHY_TYPE_OFDM,
508+ [MT76_TM_TX_MODE_HT] = MT_PHY_TYPE_HT,
509+ [MT76_TM_TX_MODE_VHT] = MT_PHY_TYPE_VHT,
510+ [MT76_TM_TX_MODE_HE_SU] = MT_PHY_TYPE_HE_SU,
511+ [MT76_TM_TX_MODE_HE_EXT_SU] = MT_PHY_TYPE_HE_EXT_SU,
512+ [MT76_TM_TX_MODE_HE_TB] = MT_PHY_TYPE_HE_TB,
513+ [MT76_TM_TX_MODE_HE_MU] = MT_PHY_TYPE_HE_MU,
514+ [MT76_TM_TX_MODE_EHT_SU] = MT_PHY_TYPE_EHT_SU,
515+ [MT76_TM_TX_MODE_EHT_TRIG] = MT_PHY_TYPE_EHT_TRIG,
516+ [MT76_TM_TX_MODE_EHT_MU] = MT_PHY_TYPE_EHT_MU,
517+ };
518+
519+ if (tx_rate_mode > MT76_TM_TX_MODE_MAX)
520+ return -EINVAL;
521+
522+ return rate_to_phy[tx_rate_mode];
523+}
524+
525+static int
526+mt7996_tm_set(struct mt7996_dev *dev, u32 func_idx, u32 data)
527+{
528+ struct mt7996_tm_req req = {
529+ .rf_test = {
530+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
531+ .len = cpu_to_le16(sizeof(req.rf_test)),
532+ .action = RF_ACTION_SET,
533+ .op.rf.func_idx = func_idx,
534+ .op.rf.param.func_data = cpu_to_le32(data),
535+ },
536+ };
537+
538+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_CTRL), &req,
539+ sizeof(req), false);
540+}
541+
542+static int
543+mt7996_tm_get(struct mt7996_dev *dev, u32 func_idx, u32 data, u32 *result)
544+{
545+ struct mt7996_tm_req req = {
546+ .rf_test = {
547+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
548+ .len = cpu_to_le16(sizeof(req.rf_test)),
549+ .action = RF_ACTION_GET,
550+ .op.rf.func_idx = func_idx,
551+ .op.rf.param.func_data = cpu_to_le32(data),
552+ },
553+ };
554+ struct mt7996_tm_event *event;
555+ struct sk_buff *skb;
556+ int ret;
557+
558+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(TESTMODE_CTRL),
559+ &req, sizeof(req), true, &skb);
560+ if (ret)
561+ return ret;
562+
563+ event = (struct mt7996_tm_event *)skb->data;
564+ *result = event->result.payload_length;
565+
566+ dev_kfree_skb(skb);
567+
568+ return ret;
569+}
570+
571+static void
572+mt7996_tm_set_antenna(struct mt7996_phy *phy, u32 func_idx)
573+{
574+#define SPE_INDEX_MASK BIT(31)
575+#define RX_ANTENNA_MASK GENMASK(20, 16) /* RX antenna mask at most 5 bit */
576+ struct mt7996_dev *dev = phy->dev;
577+ struct mt76_testmode_data *td = &phy->mt76->test;
578+ u32 antenna_mask, idx = MT76_TM_ATTR_TX_ANTENNA;
579+ bool is_antenna_set = td->param_set[idx / 32] & BIT(idx % 32);
580+
581+ if (!is_antenna_set)
582+ return;
583+
584+ if (func_idx == SET_ID(TX_PATH))
585+ antenna_mask = td->tx_spe_idx ? (SPE_INDEX_MASK | td->tx_spe_idx) :
586+ td->tx_antenna_mask;
587+ else if (func_idx == SET_ID(RX_PATH))
588+ antenna_mask = u32_encode_bits(td->tx_antenna_mask, RX_ANTENNA_MASK);
589+ else
590+ return;
591+
592+ mt7996_tm_set(dev, func_idx, antenna_mask);
593+}
594+
595+static void
596+mt7996_tm_set_mac_addr(struct mt7996_dev *dev, u8 *addr, u32 func_idx)
597+{
598+#define REMAIN_PART_TAG BIT(18)
599+ u32 own_mac_first = 0, own_mac_remain = 0;
600+ int len = sizeof(u32);
601+
602+ memcpy(&own_mac_first, addr, len);
603+ mt7996_tm_set(dev, func_idx, own_mac_first);
604+ /* Set the remain part of mac address */
605+ memcpy(&own_mac_remain, addr + len, ETH_ALEN - len);
606+ mt7996_tm_set(dev, func_idx | REMAIN_PART_TAG, own_mac_remain);
607+}
608+
609+static int
610+mt7996_tm_rf_switch_mode(struct mt7996_dev *dev, u32 op_mode)
611+{
612+ struct mt7996_tm_req req = {
613+ .rf_test = {
614+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
615+ .len = cpu_to_le16(sizeof(req.rf_test)),
616+ .action = RF_ACTION_SWITCH_TO_RF_TEST,
617+ .op.op_mode = cpu_to_le32(op_mode),
618+ },
619+ };
620+
621+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_CTRL), &req,
622+ sizeof(req), false);
623+}
624+
625+static void
626+mt7996_tm_init(struct mt7996_phy *phy, bool en)
627+{
628+#define POWER_CTRL(type) UNI_TXPOWER_##type##_CTRL
629+ struct mt7996_dev *dev = phy->dev;
630+ u8 rf_test_mode = en ? RF_OPER_RF_TEST : RF_OPER_NORMAL;
631+
632+ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
633+ return;
634+
635+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(ATE_MODE), en);
636+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(SKU_POWER_LIMIT), !en);
637+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(PERCENTAGE_DROP), 100);
638+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(PERCENTAGE), !en);
639+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(BACKOFF_POWER_LIMIT), !en);
640+
641+ mt7996_tm_rf_switch_mode(dev, rf_test_mode);
642+
643+ mt7996_mcu_add_bss_info(phy, phy->monitor_vif, en);
644+ mt7996_mcu_add_sta(dev, phy->monitor_vif, NULL, en);
645+
646+ mt7996_tm_set(dev, SET_ID(BAND_IDX), phy->mt76->band_idx);
647+
648+ /* use firmware counter for RX stats */
649+ phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
650+}
651+
652+static void
653+mt7996_tm_update_channel(struct mt7996_phy *phy)
654+{
655+#define CHAN_FREQ_BW_80P80_TAG (SET_ID(CHAN_FREQ) | BIT(16))
656+ struct mt7996_dev *dev = phy->dev;
657+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
658+ struct ieee80211_channel *chan = chandef->chan;
659+ u8 width = chandef->width;
660+ static const u8 ch_band[] = {
661+ [NL80211_BAND_2GHZ] = 0,
662+ [NL80211_BAND_5GHZ] = 1,
663+ [NL80211_BAND_6GHZ] = 2,
664+ };
665+
666+ if (!chan || !chandef) {
667+ dev_info(dev->mt76.dev, "chandef not found, channel update failed!\n");
668+ return;
669+ }
670+
671+ /* system bw */
672+ mt7996_tm_set(dev, SET_ID(CBW), mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
673+
674+ if (width == NL80211_CHAN_WIDTH_80P80) {
675+ width = NL80211_CHAN_WIDTH_160;
676+ mt7996_tm_set(dev, CHAN_FREQ_BW_80P80_TAG, chandef->center_freq2 * 1000);
677+ }
678+
679+ /* TODO: define per-packet bw */
680+ /* per-packet bw */
681+ mt7996_tm_set(dev, SET_ID(DBW), mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
682+
683+ /* control channel selection index */
684+ mt7996_tm_set(dev, SET_ID(PRIMARY_CH), 0);
685+ mt7996_tm_set(dev, SET_ID(BAND), ch_band[chan->band]);
686+
687+ /* trigger switch channel calibration */
688+ mt7996_tm_set(dev, SET_ID(CHAN_FREQ), chandef->center_freq1 * 1000);
689+
690+ // TODO: update power limit table
691+}
692+
693+static void
694+mt7996_tm_tx_stop(struct mt76_phy *mphy)
695+{
696+ struct mt76_testmode_data *td = &mphy->test;
697+ struct mt7996_phy *phy = mphy->priv;
698+ struct mt7996_dev *dev = phy->dev;
699+
700+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
701+ td->tx_pending = 0;
702+}
703+
704+static void
705+mt7996_tm_set_tx_frames(struct mt7996_phy *phy, bool en)
706+{
707+#define FRAME_CONTROL 0x88
708+ struct mt76_testmode_data *td = &phy->mt76->test;
709+ struct mt7996_dev *dev = phy->dev;
710+
711+ //TODO: RU operation, replace mcs, nss, and ldpc
712+ if (en) {
713+ mt7996_tm_set(dev, SET_ID(MAC_HEADER), FRAME_CONTROL);
714+ mt7996_tm_set(dev, SET_ID(SEQ_CTRL), 0);
715+ mt7996_tm_set(dev, SET_ID(TX_COUNT), td->tx_count);
716+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
717+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
718+ mt7996_tm_set(dev, SET_ID(POWER), td->tx_power[0]);
719+ mt7996_tm_set_antenna(phy, SET_ID(TX_PATH));
720+ mt7996_tm_set(dev, SET_ID(STBC), td->tx_rate_stbc);
721+ mt7996_tm_set(dev, SET_ID(ENCODE_MODE), td->tx_rate_ldpc);
722+ mt7996_tm_set(dev, SET_ID(IBF_ENABLE), td->ibf);
723+ mt7996_tm_set(dev, SET_ID(EBF_ENABLE), td->ebf);
724+ mt7996_tm_set(dev, SET_ID(IPG), td->tx_ipg);
725+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
726+ mt7996_tm_set(dev, SET_ID(NSS), td->tx_rate_nss);
727+ mt7996_tm_set(dev, SET_ID(AID_OFFSET), 0);
728+ mt7996_tm_set(dev, SET_ID(PUNCTURE), td->tx_preamble_puncture);
729+
730+ mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
731+ mt7996_tm_set(dev, SET_ID(HW_TX_MODE), 0);
732+ mt7996_tm_update_channel(phy);
733+
734+ /* trigger firmware to start TX */
735+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_TX));
736+ } else {
737+ mt7996_tm_tx_stop(phy->mt76);
738+ }
739+}
740+
741+static int
742+mt7996_tm_rx_stats_user_ctrl(struct mt7996_phy *phy, u16 user_idx)
743+{
744+ struct mt7996_dev *dev = phy->dev;
745+ struct mt7996_tm_rx_req req = {
746+ .band = phy->mt76->band_idx,
747+ .user_ctrl = {
748+ .tag = cpu_to_le16(UNI_TM_RX_STAT_SET_USER_CTRL),
749+ .len = cpu_to_le16(sizeof(req.user_ctrl)),
750+ .band_idx = phy->mt76->band_idx,
751+ .user_idx = cpu_to_le16(user_idx),
752+ },
753+ };
754+
755+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_RX_STAT), &req,
756+ sizeof(req), false);
757+}
758+
759+static void
760+mt7996_tm_set_rx_frames(struct mt7996_phy *phy, bool en)
761+{
762+#define RX_MU_DISABLE 0xf800
763+ struct mt76_testmode_data *td = &phy->mt76->test;
764+ struct mt7996_dev *dev = phy->dev;
765+ int ret;
766+
767+ if (en) {
768+ ret = mt7996_tm_rx_stats_user_ctrl(phy, td->aid);
769+ if (ret) {
770+ dev_info(dev->mt76.dev, "Set RX stats user control failed!\n");
771+ return;
772+ }
773+
774+ mt7996_tm_update_channel(phy);
775+
776+ if (td->tx_rate_mode >= MT76_TM_TX_MODE_HE_MU) {
777+ if (td->aid)
778+ ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), td->aid);
779+ else
780+ ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), RX_MU_DISABLE);
781+ }
782+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
783+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
784+ mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
785+ mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
786+
787+ mt7996_tm_set_mac_addr(dev, td->addr[1], SET_ID(SA));
788+
789+ /* trigger firmware to start RX */
790+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_RX));
791+ } else {
792+ /* trigger firmware to stop RX */
793+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
794+ }
795+}
796+
797+static void
798+mt7996_tm_set_tx_cont(struct mt7996_phy *phy, bool en)
799+{
800+#define CONT_WAVE_MODE_OFDM 3
801+ struct mt76_testmode_data *td = &phy->mt76->test;
802+ struct mt7996_dev *dev = phy->dev;
803+
804+ if (en) {
805+ mt7996_tm_update_channel(phy);
806+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
807+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
808+ /* fix payload is OFDM */
809+ mt7996_tm_set(dev, SET_ID(CONT_WAVE_MODE), CONT_WAVE_MODE_OFDM);
810+ mt7996_tm_set(dev, SET_ID(ANT_MASK), td->tx_antenna_mask);
811+
812+ /* trigger firmware to start CONT TX */
813+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(CONT_WAVE));
814+ } else {
815+ /* trigger firmware to stop CONT TX */
816+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
817+ }
818+}
819+
820+static void
821+mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
822+{
823+ struct mt76_testmode_data *td = &phy->mt76->test;
824+ struct mt7996_dev *dev = phy->dev;
825+ bool en = td->state != MT76_TM_STATE_OFF;
826+
827+ if (changed & BIT(TM_CHANGED_FREQ_OFFSET))
828+ mt7996_tm_set(dev, SET_ID(FREQ_OFFSET), en ? td->freq_offset : 0);
829+ if (changed & BIT(TM_CHANGED_TXPOWER))
830+ mt7996_tm_set(dev, SET_ID(POWER), td->tx_power[0]);
831+ if (changed & BIT(TM_CHANGED_TX_LENGTH)) {
832+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
833+ mt7996_tm_set(dev, SET_ID(TX_TIME), 0);
834+ }
835+ if (changed & BIT(TM_CHANGED_TX_TIME)) {
836+ mt7996_tm_set(dev, SET_ID(TX_LEN), 0);
837+ mt7996_tm_set(dev, SET_ID(TX_TIME), td->tx_time);
838+ }
839+}
840+
841+static int
842+mt7996_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
843+{
844+ struct mt76_testmode_data *td = &mphy->test;
845+ struct mt7996_phy *phy = mphy->priv;
846+ enum mt76_testmode_state prev_state = td->state;
847+
848+ mphy->test.state = state;
849+
850+ if (prev_state != MT76_TM_STATE_OFF)
851+ mt7996_tm_set(phy->dev, SET_ID(BAND_IDX), mphy->band_idx);
852+
853+ if (prev_state == MT76_TM_STATE_TX_FRAMES ||
854+ state == MT76_TM_STATE_TX_FRAMES)
855+ mt7996_tm_set_tx_frames(phy, state == MT76_TM_STATE_TX_FRAMES);
856+ else if (prev_state == MT76_TM_STATE_RX_FRAMES ||
857+ state == MT76_TM_STATE_RX_FRAMES)
858+ mt7996_tm_set_rx_frames(phy, state == MT76_TM_STATE_RX_FRAMES);
859+ else if (prev_state == MT76_TM_STATE_TX_CONT ||
860+ state == MT76_TM_STATE_TX_CONT)
861+ mt7996_tm_set_tx_cont(phy, state == MT76_TM_STATE_TX_CONT);
862+ else if (prev_state == MT76_TM_STATE_OFF ||
863+ state == MT76_TM_STATE_OFF)
864+ mt7996_tm_init(phy, !(state == MT76_TM_STATE_OFF));
865+
866+ if ((state == MT76_TM_STATE_IDLE &&
867+ prev_state == MT76_TM_STATE_OFF) ||
868+ (state == MT76_TM_STATE_OFF &&
869+ prev_state == MT76_TM_STATE_IDLE)) {
870+ u32 changed = 0;
871+ int i;
872+
873+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
874+ u16 cur = tm_change_map[i];
875+
876+ if (td->param_set[cur / 32] & BIT(cur % 32))
877+ changed |= BIT(i);
878+ }
879+
880+ mt7996_tm_update_params(phy, changed);
881+ }
882+
883+ return 0;
884+}
885+
886+static int
887+mt7996_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
888+ enum mt76_testmode_state new_state)
889+{
890+ struct mt76_testmode_data *td = &mphy->test;
891+ struct mt7996_phy *phy = mphy->priv;
892+ struct mt7996_dev *dev = phy->dev;
893+ u32 chainmask = mphy->chainmask, changed = 0;
894+ u8 band_idx = phy->mt76->band_idx;
895+ int i;
896+
897+ BUILD_BUG_ON(NUM_TM_CHANGED >= 32);
898+
899+ if (new_state == MT76_TM_STATE_OFF ||
900+ td->state == MT76_TM_STATE_OFF)
901+ return 0;
902+
903+ chainmask = chainmask >> dev->chainshift[band_idx];
904+ if (td->tx_antenna_mask > chainmask)
905+ return -EINVAL;
906+
907+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
908+ if (tb[tm_change_map[i]])
909+ changed |= BIT(i);
910+ }
911+
912+ mt7996_tm_set(dev, SET_ID(BAND_IDX), mphy->band_idx);
913+ mt7996_tm_update_params(phy, changed);
914+
915+ return 0;
916+}
917+
918+static int
919+mt7996_tm_get_rx_stats(struct mt7996_phy *phy)
920+{
921+ struct mt7996_dev *dev = phy->dev;
922+ struct mt7996_tm_rx_req req = {
923+ .band = phy->mt76->band_idx,
924+ .rx_stat_all = {
925+ .tag = cpu_to_le16(UNI_TM_RX_STAT_GET_ALL_V2),
926+ .len = cpu_to_le16(sizeof(req.rx_stat_all)),
927+ .band_idx = phy->mt76->band_idx,
928+ },
929+ };
930+ struct mt76_testmode_data *td = &phy->mt76->test;
931+ struct mt7996_tm_rx_event *rx_stats;
932+ struct mt7996_tm_rx_event_stat_all *rx_stats_all;
933+ struct sk_buff *skb;
934+ enum mt76_rxq_id qid;
935+ int i, ret = 0;
936+ u32 mac_rx_mdrdy_cnt;
937+ u16 mac_rx_len_mismatch, fcs_err_count;
938+
939+ if (td->state != MT76_TM_STATE_RX_FRAMES)
940+ return 0;
941+
942+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(TESTMODE_RX_STAT),
943+ &req, sizeof(req), true, &skb);
944+
945+ if (ret)
946+ return ret;
947+
948+ rx_stats = (struct mt7996_tm_rx_event *)skb->data;
949+ rx_stats_all = &rx_stats->rx_stat_all;
950+
951+ phy->test.last_freq_offset = le32_to_cpu(rx_stats_all->user_info[0].freq_offset);
952+ phy->test.last_snr = le32_to_cpu(rx_stats_all->user_info[0].snr);
953+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) {
954+ phy->test.last_rcpi[i] = le16_to_cpu(rx_stats_all->rxv_info[i].rcpi);
955+ phy->test.last_ib_rssi[i] = rx_stats_all->fagc[i].ib_rssi;
956+ phy->test.last_wb_rssi[i] = rx_stats_all->fagc[i].wb_rssi;
957+ }
958+
959+ if (phy->mt76->band_idx == 2)
960+ qid = MT_RXQ_BAND2;
961+ else if (phy->mt76->band_idx == 1)
962+ qid = MT_RXQ_BAND1;
963+ else
964+ qid = MT_RXQ_MAIN;
965+
966+ fcs_err_count = le16_to_cpu(rx_stats_all->band_info.mac_rx_fcs_err_cnt);
967+ mac_rx_len_mismatch = le16_to_cpu(rx_stats_all->band_info.mac_rx_len_mismatch);
968+ mac_rx_mdrdy_cnt = le32_to_cpu(rx_stats_all->band_info.mac_rx_mdrdy_cnt);
969+ td->rx_stats.packets[qid] += mac_rx_mdrdy_cnt;
970+ td->rx_stats.packets[qid] += fcs_err_count;
971+ td->rx_stats.fcs_error[qid] += fcs_err_count;
972+ td->rx_stats.len_mismatch += mac_rx_len_mismatch;
973+
974+ dev_kfree_skb(skb);
975+
976+ return ret;
977+}
978+
979+static void
980+mt7996_tm_reset_rx_stats(struct mt76_phy *mphy)
981+{
982+ struct mt7996_phy *phy = mphy->priv;
983+ struct mt7996_dev *dev = phy->dev;
984+
985+ memset(&mphy->test.rx_stats, 0, sizeof(mphy->test.rx_stats));
986+ mt7996_tm_set(dev, SET_ID(TRX_COUNTER_RESET), 0);
987+}
988+
989+static int
990+mt7996_tm_get_tx_stats(struct mt7996_phy *phy)
991+{
992+ struct mt7996_dev *dev = phy->dev;
993+ struct mt76_testmode_data *td = &phy->mt76->test;
994+ int ret;
995+
996+ if (td->state != MT76_TM_STATE_TX_FRAMES)
997+ return 0;
998+
999+ ret = mt7996_tm_get(dev, GET_ID(TXED_COUNT), 0, &td->tx_done);
1000+ if (ret)
1001+ return ret;
1002+
1003+ td->tx_pending = td->tx_count - td->tx_done;
1004+
1005+ return ret;
1006+}
1007+
1008+static int
1009+mt7996_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
1010+{
1011+ struct mt7996_phy *phy = mphy->priv;
1012+ void *rx, *rssi;
1013+ int i;
1014+
1015+ mt7996_tm_set(phy->dev, SET_ID(BAND_IDX), mphy->band_idx);
1016+ mt7996_tm_get_rx_stats(phy);
1017+ mt7996_tm_get_tx_stats(phy);
1018+
1019+ rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);
1020+ if (!rx)
1021+ return -ENOMEM;
1022+
1023+ if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset))
1024+ return -ENOMEM;
1025+
1026+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
1027+ if (!rssi)
1028+ return -ENOMEM;
1029+
1030+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++)
1031+ if (nla_put_u8(msg, i, phy->test.last_rcpi[i]))
1032+ return -ENOMEM;
1033+
1034+ nla_nest_end(msg, rssi);
1035+
1036+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
1037+ if (!rssi)
1038+ return -ENOMEM;
1039+
1040+ for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++)
1041+ if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i]))
1042+ return -ENOMEM;
1043+
1044+ nla_nest_end(msg, rssi);
1045+
1046+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
1047+ if (!rssi)
1048+ return -ENOMEM;
1049+
1050+ for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++)
1051+ if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i]))
1052+ return -ENOMEM;
1053+
1054+ nla_nest_end(msg, rssi);
1055+
1056+ if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, phy->test.last_snr))
1057+ return -ENOMEM;
1058+
1059+ nla_nest_end(msg, rx);
1060+
1061+ return 0;
1062+}
1063+
1064+const struct mt76_testmode_ops mt7996_testmode_ops = {
1065+ .set_state = mt7996_tm_set_state,
1066+ .set_params = mt7996_tm_set_params,
1067+ .dump_stats = mt7996_tm_dump_stats,
1068+ .reset_rx_stats = mt7996_tm_reset_rx_stats,
1069+ .tx_stop = mt7996_tm_tx_stop,
1070+};
1071diff --git a/mt7996/testmode.h b/mt7996/testmode.h
1072new file mode 100644
developer78848c62023-04-06 13:44:00 +08001073index 0000000..f381da5
developerd5789dc2023-03-27 11:22:06 +08001074--- /dev/null
1075+++ b/mt7996/testmode.h
1076@@ -0,0 +1,292 @@
1077+/* SPDX-License-Identifier: ISC */
1078+/* Copyright (C) 2020 MediaTek Inc. */
1079+
1080+#ifndef __MT7996_TESTMODE_H
1081+#define __MT7996_TESTMODE_H
1082+
1083+enum {
1084+ TM_CBW_20MHZ,
1085+ TM_CBW_40MHZ,
1086+ TM_CBW_80MHZ,
1087+ TM_CBW_10MHZ,
1088+ TM_CBW_5MHZ,
1089+ TM_CBW_160MHZ,
1090+ TM_CBW_8080MHZ,
1091+ TM_CBW_320MHZ = 12,
1092+};
1093+
1094+/* BW defined in FW hal_cal_flow_rom.h */
1095+enum {
1096+ FW_CDBW_20MHZ,
1097+ FW_CDBW_40MHZ,
1098+ FW_CDBW_80MHZ,
1099+ FW_CDBW_160MHZ,
1100+ FW_CDBW_320MHZ,
1101+ FW_CDBW_5MHZ,
1102+ FW_CDBW_10MHZ,
1103+ FW_CDBW_8080MHZ,
1104+};
1105+
1106+enum bw_mapping_method {
1107+ BW_MAP_NL_TO_FW,
1108+ BW_MAP_NL_TO_TM,
1109+
1110+ NUM_BW_MAP,
1111+};
1112+
1113+struct mt7996_tm_rf_test {
1114+ __le16 tag;
1115+ __le16 len;
1116+
1117+ u8 action;
1118+ u8 icap_len;
1119+ u8 _rsv[2];
1120+ union {
1121+ __le32 op_mode;
1122+ __le32 freq;
1123+
1124+ struct {
1125+ __le32 func_idx;
1126+ union {
1127+ __le32 func_data;
1128+ __le32 cal_dump;
1129+
1130+ u8 _pad[80];
1131+ } param;
1132+ } rf;
1133+ } op;
1134+} __packed;
1135+
1136+struct mt7996_tm_req {
1137+ u8 _rsv[4];
1138+
1139+ struct mt7996_tm_rf_test rf_test;
1140+} __packed;
1141+
1142+struct mt7996_tm_rf_test_result {
1143+ __le32 func_idx;
1144+ __le32 payload_length;
1145+ u8 event[0];
1146+};
1147+
1148+struct mt7996_tm_event {
1149+ u8 _rsv[4];
1150+
1151+ __le16 tag;
1152+ __le16 len;
1153+ struct mt7996_tm_rf_test_result result;
1154+} __packed;
1155+
1156+enum {
1157+ RF_ACTION_SWITCH_TO_RF_TEST,
1158+ RF_ACTION_IN_RF_TEST,
1159+ RF_ACTION_SET = 3,
1160+ RF_ACTION_GET,
1161+};
1162+
1163+enum {
1164+ RF_OPER_NORMAL,
1165+ RF_OPER_RF_TEST,
1166+ RF_OPER_ICAP,
1167+ RF_OPER_ICAP_OVERLAP,
1168+ RF_OPER_WIFI_SPECTRUM,
1169+};
1170+
1171+enum {
1172+ UNI_RF_TEST_CTRL,
1173+};
1174+
1175+#define RF_CMD(cmd) RF_TEST_CMD_##cmd
1176+
1177+enum {
1178+ RF_TEST_CMD_STOP_TEST = 0,
1179+ RF_TEST_CMD_START_TX = 1,
1180+ RF_TEST_CMD_START_RX = 2,
1181+ RF_TEST_CMD_CONT_WAVE = 10,
1182+ RF_TEST_CMD_TX_COMMIT = 18,
1183+ RF_TEST_CMD_RX_COMMIT = 19,
1184+};
1185+
1186+#define SET_ID(id) RF_TEST_ID_SET_##id
1187+#define GET_ID(id) RF_TEST_ID_GET_##id
1188+
1189+enum {
1190+ RF_TEST_ID_SET_COMMAND = 1,
1191+ RF_TEST_ID_SET_POWER = 2,
1192+ RF_TEST_ID_SET_TX_RATE = 3,
1193+ RF_TEST_ID_SET_TX_MODE = 4,
1194+ RF_TEST_ID_SET_TX_LEN = 6,
1195+ RF_TEST_ID_SET_TX_COUNT = 7,
1196+ RF_TEST_ID_SET_IPG = 8,
1197+ RF_TEST_ID_SET_GI = 16,
1198+ RF_TEST_ID_SET_STBC = 17,
1199+ RF_TEST_ID_SET_CHAN_FREQ = 18,
1200+ RF_TEST_ID_GET_TXED_COUNT = 32,
1201+ RF_TEST_ID_SET_CONT_WAVE_MODE = 65,
1202+ RF_TEST_ID_SET_DA = 68,
1203+ RF_TEST_ID_SET_SA = 69,
1204+ RF_TEST_ID_SET_CBW = 71,
1205+ RF_TEST_ID_SET_DBW = 72,
1206+ RF_TEST_ID_SET_PRIMARY_CH = 73,
1207+ RF_TEST_ID_SET_ENCODE_MODE = 74,
1208+ RF_TEST_ID_SET_BAND = 90,
1209+ RF_TEST_ID_SET_TRX_COUNTER_RESET = 91,
1210+ RF_TEST_ID_SET_MAC_HEADER = 101,
1211+ RF_TEST_ID_SET_SEQ_CTRL = 102,
1212+ RF_TEST_ID_SET_BAND_IDX = 104,
1213+ RF_TEST_ID_SET_RX_PATH = 106,
1214+ RF_TEST_ID_SET_FREQ_OFFSET = 107,
1215+ RF_TEST_ID_GET_FREQ_OFFSET = 108,
1216+ RF_TEST_ID_SET_TX_PATH = 113,
1217+ RF_TEST_ID_SET_NSS = 114,
1218+ RF_TEST_ID_SET_ANT_MASK = 115,
1219+ RF_TEST_ID_SET_IBF_ENABLE = 126,
1220+ RF_TEST_ID_SET_EBF_ENABLE = 127,
1221+ RF_TEST_ID_GET_TX_POWER = 136,
1222+ RF_TEST_ID_SET_RX_MU_AID = 157,
1223+ RF_TEST_ID_SET_HW_TX_MODE = 167,
1224+ RF_TEST_ID_SET_PUNCTURE = 168,
1225+ RF_TEST_ID_SET_BSSID = 189,
1226+ RF_TEST_ID_SET_TX_TIME = 190,
1227+ RF_TEST_ID_SET_MAX_PE = 191,
1228+ RF_TEST_ID_SET_AID_OFFSET = 204,
1229+};
1230+
1231+struct mt7996_tm_rx_stat_user_ctrl {
1232+ __le16 tag;
1233+ __le16 len;
1234+
1235+ u8 band_idx;
1236+ u8 rsv;
1237+ __le16 user_idx;
1238+} __packed;
1239+
1240+struct mt7996_tm_rx_stat_all {
1241+ __le16 tag;
1242+ __le16 len;
1243+
1244+ u8 band_idx;
1245+ u8 rsv[3];
1246+} __packed;
1247+
1248+struct mt7996_tm_rx_req {
1249+ u8 band;
1250+ u8 _rsv[3];
1251+
1252+ union {
1253+ struct mt7996_tm_rx_stat_user_ctrl user_ctrl;
1254+ struct mt7996_tm_rx_stat_all rx_stat_all;
1255+ };
1256+} __packed;
1257+
1258+enum {
1259+ UNI_TM_RX_STAT_SET_USER_CTRL = 7,
1260+ UNI_TM_RX_STAT_GET_ALL_V2 = 9,
1261+};
1262+
1263+struct rx_band_info {
1264+ /* mac part */
1265+ __le16 mac_rx_fcs_err_cnt;
1266+ __le16 mac_rx_len_mismatch;
1267+ __le16 mac_rx_fcs_ok_cnt;
1268+ u8 rsv1[2];
1269+ __le32 mac_rx_mdrdy_cnt;
1270+
1271+ /* phy part */
1272+ __le16 phy_rx_fcs_err_cnt_cck;
1273+ __le16 phy_rx_fcs_err_cnt_ofdm;
1274+ __le16 phy_rx_pd_cck;
1275+ __le16 phy_rx_pd_ofdm;
1276+ __le16 phy_rx_sig_err_cck;
1277+ __le16 phy_rx_sfd_err_cck;
1278+ __le16 phy_rx_sig_err_ofdm;
1279+ __le16 phy_rx_tag_err_ofdm;
1280+ __le16 phy_rx_mdrdy_cnt_cck;
1281+ __le16 phy_rx_mdrdy_cnt_ofdm;
1282+} __packed;
1283+
1284+struct rx_band_info_ext {
1285+ /* mac part */
1286+ __le32 mac_rx_mpdu_cnt;
1287+
1288+ /* phy part */
1289+ u8 rsv[4];
1290+} __packed;
1291+
1292+struct rx_common_info {
1293+ __le16 rx_fifo_full;
1294+ u8 rsv[2];
1295+ __le32 aci_hit_low;
1296+ __le32 aci_hit_high;
1297+} __packed;
1298+
1299+struct rx_common_info_ext {
1300+ __le32 driver_rx_count;
1301+ __le32 sinr;
1302+ __le32 mu_pkt_count;
1303+
1304+ /* mac part */
1305+ u8 _rsv[4];
1306+
1307+ /* phy part */
1308+ u8 sig_mcs;
1309+ u8 rsv[3];
1310+} __packed;
1311+
1312+struct rx_rxv_info {
1313+ __le16 rcpi;
1314+ s16 rssi;
1315+ s16 snr;
1316+ s16 adc_rssi;
1317+} __packed;
1318+
1319+struct rx_rssi_info {
1320+ s8 ib_rssi;
1321+ s8 wb_rssi;
1322+ u8 rsv[2];
1323+} __packed;
1324+
1325+struct rx_user_info {
1326+ s32 freq_offset;
1327+ s32 snr;
1328+ __le32 fcs_err_count;
1329+} __packed;
1330+
1331+struct rx_user_info_ext {
1332+ s8 ne_var_db_all_user;
1333+ u8 rsv[3];
1334+} __packed;
1335+
1336+#define MAX_ANTENNA_NUM 8
1337+#define MAX_USER_NUM 16
1338+
1339+struct mt7996_tm_rx_event_stat_all {
1340+ __le16 tag;
1341+ __le16 len;
1342+
1343+ struct rx_band_info band_info;
1344+ struct rx_band_info_ext band_info_ext;
1345+ struct rx_common_info common_info;
1346+ struct rx_common_info_ext common_info_ext;
1347+
1348+ /* RXV info */
1349+ struct rx_rxv_info rxv_info[MAX_ANTENNA_NUM];
1350+
1351+ /* RSSI info */
1352+ struct rx_rssi_info fagc[MAX_ANTENNA_NUM];
1353+ struct rx_rssi_info inst[MAX_ANTENNA_NUM];
1354+
1355+ /* User info */
1356+ struct rx_user_info user_info[MAX_USER_NUM];
1357+ struct rx_user_info_ext user_info_ext[MAX_USER_NUM];
1358+} __packed;
1359+
1360+struct mt7996_tm_rx_event {
1361+ u8 _rsv[4];
1362+
1363+ union {
1364+ struct mt7996_tm_rx_event_stat_all rx_stat_all;
1365+ };
1366+} __packed;
1367+
1368+#endif
1369diff --git a/testmode.c b/testmode.c
developer78848c62023-04-06 13:44:00 +08001370index 0d2bae9..007358b 100644
developerd5789dc2023-03-27 11:22:06 +08001371--- a/testmode.c
1372+++ b/testmode.c
1373@@ -2,6 +2,7 @@
1374 /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
1375
1376 #include <linux/random.h>
1377+#include "mt76_connac.h"
1378 #include "mt76.h"
1379
1380 const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
1381@@ -81,6 +82,11 @@ mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode)
1382 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991)
1383 return IEEE80211_MAX_MPDU_LEN_VHT_7991;
1384 return IEEE80211_MAX_MPDU_LEN_VHT_11454;
1385+ case MT76_TM_TX_MODE_EHT_SU:
1386+ case MT76_TM_TX_MODE_EHT_TRIG:
1387+ case MT76_TM_TX_MODE_EHT_MU:
1388+ /* TODO: check the limit */
1389+ return UINT_MAX;
1390 case MT76_TM_TX_MODE_CCK:
1391 case MT76_TM_TX_MODE_OFDM:
1392 default:
1393@@ -182,6 +188,9 @@ mt76_testmode_tx_init(struct mt76_phy *phy)
1394 u8 max_nss = hweight8(phy->antenna_mask);
1395 int ret;
1396
1397+ if (is_mt7996(phy->dev))
1398+ return 0;
1399+
1400 ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len);
1401 if (ret)
1402 return ret;
1403@@ -274,7 +283,9 @@ mt76_testmode_tx_start(struct mt76_phy *phy)
1404 td->tx_queued = 0;
1405 td->tx_done = 0;
1406 td->tx_pending = td->tx_count;
1407- mt76_worker_schedule(&dev->tx_worker);
1408+
1409+ if (!is_mt7996(dev))
1410+ mt76_worker_schedule(&dev->tx_worker);
1411 }
1412
1413 static void
1414@@ -283,6 +294,11 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
1415 struct mt76_testmode_data *td = &phy->test;
1416 struct mt76_dev *dev = phy->dev;
1417
1418+ if (is_mt7996(dev) && dev->test_ops->tx_stop) {
1419+ dev->test_ops->tx_stop(phy);
1420+ return;
1421+ }
1422+
1423 mt76_worker_disable(&dev->tx_worker);
1424
1425 td->tx_pending = 0;
1426@@ -311,6 +327,7 @@ static void
1427 mt76_testmode_init_defaults(struct mt76_phy *phy)
1428 {
1429 struct mt76_testmode_data *td = &phy->test;
1430+ u8 addr[ETH_ALEN] = {phy->band_idx, 0x11, 0x22, 0xaa, 0xbb, 0xcc};
1431
1432 if (td->tx_mpdu_len > 0)
1433 return;
1434@@ -318,11 +335,18 @@ mt76_testmode_init_defaults(struct mt76_phy *phy)
1435 td->tx_mpdu_len = 1024;
1436 td->tx_count = 1;
1437 td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;
1438+ td->tx_rate_idx = 7;
1439 td->tx_rate_nss = 1;
1440+ /* 0xffff for OFDMA no puncture */
1441+ td->tx_preamble_puncture = ~(td->tx_preamble_puncture & 0);
1442+ td->tx_ipg = 50;
1443
1444- memcpy(td->addr[0], phy->macaddr, ETH_ALEN);
1445- memcpy(td->addr[1], phy->macaddr, ETH_ALEN);
1446- memcpy(td->addr[2], phy->macaddr, ETH_ALEN);
1447+ /* rx stat user config */
1448+ td->aid = 1;
1449+
1450+ memcpy(td->addr[0], addr, ETH_ALEN);
1451+ memcpy(td->addr[1], addr, ETH_ALEN);
1452+ memcpy(td->addr[2], addr, ETH_ALEN);
1453 }
1454
1455 static int
1456@@ -352,7 +376,7 @@ __mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state)
1457 if (state == MT76_TM_STATE_TX_FRAMES)
1458 mt76_testmode_tx_start(phy);
1459 else if (state == MT76_TM_STATE_RX_FRAMES) {
1460- memset(&phy->test.rx_stats, 0, sizeof(phy->test.rx_stats));
1461+ dev->test_ops->reset_rx_stats(phy);
1462 }
1463
1464 phy->test.state = state;
1465@@ -453,7 +477,8 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1466 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE],
1467 &td->tx_duty_cycle, 0, 99) ||
1468 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
1469- &td->tx_power_control, 0, 1))
1470+ &td->tx_power_control, 0, 1) ||
1471+ mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16))
1472 goto out;
1473
1474 if (tb[MT76_TM_ATTR_TX_LENGTH]) {
1475@@ -493,7 +518,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1476 idx >= ARRAY_SIZE(td->tx_power))
1477 goto out;
1478
1479- td->tx_power[idx++] = nla_get_u8(cur);
1480+ err = mt76_tm_get_u8(cur, &td->tx_power[idx++], 0, 63);
1481+ if (err)
1482+ return err;
1483 }
1484 }
1485
1486@@ -560,6 +587,9 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)
1487 nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets,
1488 MT76_TM_STATS_ATTR_PAD) ||
1489 nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error,
1490+ MT76_TM_STATS_ATTR_PAD) ||
1491+ nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_LEN_MISMATCH,
1492+ td->rx_stats.len_mismatch,
1493 MT76_TM_STATS_ATTR_PAD))
1494 return -EMSGSIZE;
1495
1496@@ -624,6 +654,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
1497 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
1498 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||
1499 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
1500+ nla_put_u8(msg, MT76_TM_ATTR_AID, td->aid) ||
1501 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
1502 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
1503 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
1504diff --git a/testmode.h b/testmode.h
developer78848c62023-04-06 13:44:00 +08001505index a40cd74..8d0b970 100644
developerd5789dc2023-03-27 11:22:06 +08001506--- a/testmode.h
1507+++ b/testmode.h
1508@@ -39,6 +39,11 @@
1509 *
1510 * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr)
1511 *
1512+ * @MT76_TM_ATTR_PRECAL: Pre-cal data (u8)
1513+ * @MT76_TM_ATTR_PRECAL_INFO: group size, dpd size, dpd_info, transmit size,
1514+ * eeprom cal indicator (u32),
1515+ * dpd_info = [dpd_per_chan_size, chan_num_2g,
1516+ * chan_num_5g, chan_num_6g]
1517 * @MT76_TM_ATTR_TX_SPE_IDX: tx spatial extension index (u8)
1518 *
1519 * @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8)
1520@@ -48,6 +53,29 @@
1521 * @MT76_TM_ATTR_DRV_DATA: driver specific netlink attrs (nested)
1522 *
1523 * @MT76_TM_ATTR_MAC_ADDRS: array of nested MAC addresses (nested)
1524+ *
1525+ * @MT76_TM_ATTR_EEPROM_ACTION: eeprom setting actions
1526+ * (u8, see &enum mt76_testmode_eeprom_action)
1527+ * @MT76_TM_ATTR_EEPROM_OFFSET: offset of eeprom data block for writing (u32)
1528+ * @MT76_TM_ATTR_EEPROM_VAL: values for writing into a 16-byte data block
1529+ * (nested, u8 attrs)
1530+ *
1531+ * @MT76_TM_ATTR_CFG: config testmode rf feature (nested, see &mt76_testmode_cfg)
1532+ * @MT76_TM_ATTR_TXBF_ACT: txbf setting actions (u8)
1533+ * @MT76_TM_ATTR_TXBF_PARAM: txbf parameters (nested)
1534+ *
1535+ * @MT76_TM_ATTR_OFF_CH_SCAN_CH: config the channel of background chain (ZWDFS) (u8)
1536+ * @MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH: config the center channel of background chain (ZWDFS) (u8)
1537+ * @MT76_TM_ATTR_OFF_CH_SCAN_BW: config the bandwidth of background chain (ZWDFS) (u8)
1538+ * @MT76_TM_ATTR_OFF_CH_SCAN_PATH: config the tx path of background chain (ZWDFS) (u8)
1539+ *
1540+ * @MT76_TM_ATTR_IPI_THRESHOLD: config the IPI index you want to read (u8)
1541+ * @MT76_TM_ATTR_IPI_PERIOD: config the time period for reading
1542+ * the histogram of specific IPI index (u8)
1543+ * @MT76_TM_ATTR_IPI_ANTENNA_INDEX: config the antenna index for reading
1544+ * the histogram of specific IPI index (u8)
1545+ * @MT76_TM_ATTR_IPI_RESET: Reset the IPI counter
1546+ *
1547 */
1548 enum mt76_testmode_attr {
1549 MT76_TM_ATTR_UNSPEC,
1550@@ -76,6 +104,8 @@ enum mt76_testmode_attr {
1551 MT76_TM_ATTR_FREQ_OFFSET,
1552
1553 MT76_TM_ATTR_STATS,
1554+ MT76_TM_ATTR_PRECAL,
1555+ MT76_TM_ATTR_PRECAL_INFO,
1556
1557 MT76_TM_ATTR_TX_SPE_IDX,
1558
1559@@ -86,6 +116,27 @@ enum mt76_testmode_attr {
1560 MT76_TM_ATTR_DRV_DATA,
1561
1562 MT76_TM_ATTR_MAC_ADDRS,
1563+ MT76_TM_ATTR_AID,
1564+ MT76_TM_ATTR_RU_ALLOC,
1565+ MT76_TM_ATTR_RU_IDX,
1566+
1567+ MT76_TM_ATTR_EEPROM_ACTION,
1568+ MT76_TM_ATTR_EEPROM_OFFSET,
1569+ MT76_TM_ATTR_EEPROM_VAL,
1570+
1571+ MT76_TM_ATTR_CFG,
1572+ MT76_TM_ATTR_TXBF_ACT,
1573+ MT76_TM_ATTR_TXBF_PARAM,
1574+
1575+ MT76_TM_ATTR_OFF_CH_SCAN_CH,
1576+ MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
1577+ MT76_TM_ATTR_OFF_CH_SCAN_BW,
1578+ MT76_TM_ATTR_OFF_CH_SCAN_PATH,
1579+
1580+ MT76_TM_ATTR_IPI_THRESHOLD,
1581+ MT76_TM_ATTR_IPI_PERIOD,
1582+ MT76_TM_ATTR_IPI_ANTENNA_INDEX,
1583+ MT76_TM_ATTR_IPI_RESET,
1584
1585 /* keep last */
1586 NUM_MT76_TM_ATTRS,
1587@@ -103,6 +154,8 @@ enum mt76_testmode_attr {
1588 * @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64)
1589 * @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet
1590 * see &enum mt76_testmode_rx_attr
1591+ * @MT76_TM_STATS_ATTR_RX_LEN_MISMATCH: number of rx packets with length
1592+ * mismatch error (u64)
1593 */
1594 enum mt76_testmode_stats_attr {
1595 MT76_TM_STATS_ATTR_UNSPEC,
1596@@ -115,6 +168,7 @@ enum mt76_testmode_stats_attr {
1597 MT76_TM_STATS_ATTR_RX_PACKETS,
1598 MT76_TM_STATS_ATTR_RX_FCS_ERROR,
1599 MT76_TM_STATS_ATTR_LAST_RX,
1600+ MT76_TM_STATS_ATTR_RX_LEN_MISMATCH,
1601
1602 /* keep last */
1603 NUM_MT76_TM_STATS_ATTRS,
1604@@ -179,6 +233,9 @@ enum mt76_testmode_state {
1605 * @MT76_TM_TX_MODE_HE_EXT_SU: 802.11ax extended-range SU
1606 * @MT76_TM_TX_MODE_HE_TB: 802.11ax trigger-based
1607 * @MT76_TM_TX_MODE_HE_MU: 802.11ax multi-user MIMO
1608+ * @MT76_TM_TX_MODE_EHT_SU: 802.11be single-user MIMO
1609+ * @MT76_TM_TX_MODE_EHT_TRIG: 802.11be trigger-based
1610+ * @MT76_TM_TX_MODE_EHT_MU: 802.11be multi-user MIMO
1611 */
1612 enum mt76_testmode_tx_mode {
1613 MT76_TM_TX_MODE_CCK,
1614@@ -189,6 +246,9 @@ enum mt76_testmode_tx_mode {
1615 MT76_TM_TX_MODE_HE_EXT_SU,
1616 MT76_TM_TX_MODE_HE_TB,
1617 MT76_TM_TX_MODE_HE_MU,
1618+ MT76_TM_TX_MODE_EHT_SU,
1619+ MT76_TM_TX_MODE_EHT_TRIG,
1620+ MT76_TM_TX_MODE_EHT_MU,
1621
1622 /* keep last */
1623 NUM_MT76_TM_TX_MODES,
1624diff --git a/tools/fields.c b/tools/fields.c
developer78848c62023-04-06 13:44:00 +08001625index e3f6908..e5cf7c5 100644
developerd5789dc2023-03-27 11:22:06 +08001626--- a/tools/fields.c
1627+++ b/tools/fields.c
1628@@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
1629 [MT76_TM_STATE_IDLE] = "idle",
1630 [MT76_TM_STATE_TX_FRAMES] = "tx_frames",
1631 [MT76_TM_STATE_RX_FRAMES] = "rx_frames",
1632+ [MT76_TM_STATE_TX_CONT] = "tx_cont",
1633 };
1634
1635 static const char * const testmode_tx_mode[] = {
1636@@ -21,6 +22,9 @@ static const char * const testmode_tx_mode[] = {
1637 [MT76_TM_TX_MODE_HE_EXT_SU] = "he_ext_su",
1638 [MT76_TM_TX_MODE_HE_TB] = "he_tb",
1639 [MT76_TM_TX_MODE_HE_MU] = "he_mu",
1640+ [MT76_TM_TX_MODE_EHT_SU] = "eht_su",
1641+ [MT76_TM_TX_MODE_EHT_TRIG] = "eht_tb",
1642+ [MT76_TM_TX_MODE_EHT_MU] = "eht_mu",
1643 };
1644
1645 static void print_enum(const struct tm_field *field, struct nlattr *attr)
1646@@ -201,6 +205,62 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb)
1647 printf("%srx_per=%.02f%%\n", prefix, 100 * failed / total);
1648 }
1649
1650+static bool parse_mac(const struct tm_field *field, int idx,
1651+ struct nl_msg *msg, const char *val)
1652+{
1653+#define ETH_ALEN 6
1654+ bool ret = true;
1655+ char *str, *cur, *ap;
1656+ void *a;
1657+
1658+ str = strdup(val);
1659+ ap = str;
1660+
1661+ a = nla_nest_start(msg, idx);
1662+
1663+ idx = 0;
1664+ while ((cur = strsep(&ap, ",")) != NULL) {
1665+ unsigned char addr[ETH_ALEN];
1666+ char *val, *tmp = cur;
1667+ int i = 0;
1668+
1669+ while ((val = strsep(&tmp, ":")) != NULL) {
1670+ if (i >= ETH_ALEN)
1671+ break;
1672+
1673+ addr[i++] = strtoul(val, NULL, 16);
1674+ }
1675+
1676+ nla_put(msg, idx, ETH_ALEN, addr);
1677+
1678+ idx++;
1679+ }
1680+
1681+ nla_nest_end(msg, a);
1682+
1683+ free(str);
1684+
1685+ return ret;
1686+}
1687+
1688+static void print_mac(const struct tm_field *field, struct nlattr *attr)
1689+{
1690+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
1691+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
1692+ unsigned char addr[3][6];
1693+ struct nlattr *cur;
1694+ int idx = 0;
1695+ int rem;
1696+
1697+ nla_for_each_nested(cur, attr, rem) {
1698+ if (nla_len(cur) != 6)
1699+ continue;
1700+ memcpy(addr[idx++], nla_data(cur), 6);
1701+ }
1702+
1703+ printf("" MACSTR "," MACSTR "," MACSTR "",
1704+ MAC2STR(addr[0]), MAC2STR(addr[1]), MAC2STR(addr[2]));
1705+}
1706
1707 #define FIELD_GENERIC(_field, _name, ...) \
1708 [FIELD_NAME(_field)] = { \
1709@@ -250,6 +310,13 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb)
1710 ##__VA_ARGS__ \
1711 )
1712
1713+#define FIELD_MAC(_field, _name) \
1714+ [FIELD_NAME(_field)] = { \
1715+ .name = _name, \
1716+ .parse = parse_mac, \
1717+ .print = print_mac \
1718+ }
1719+
1720 #define FIELD_NAME(_field) MT76_TM_RX_ATTR_##_field
1721 static const struct tm_field rx_fields[NUM_MT76_TM_RX_ATTRS] = {
1722 FIELD_RO(s32, FREQ_OFFSET, "freq_offset"),
1723@@ -274,6 +341,7 @@ static const struct tm_field stats_fields[NUM_MT76_TM_STATS_ATTRS] = {
1724 FIELD_RO(u32, TX_DONE, "tx_done"),
1725 FIELD_RO(u64, RX_PACKETS, "rx_packets"),
1726 FIELD_RO(u64, RX_FCS_ERROR, "rx_fcs_error"),
1727+ FIELD_RO(u64, RX_LEN_MISMATCH, "rx_len_mismatch"),
1728 FIELD_NESTED_RO(LAST_RX, rx, "last_"),
1729 };
1730 static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
1731@@ -282,6 +350,7 @@ static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
1732 [MT76_TM_STATS_ATTR_TX_DONE] = { .type = NLA_U32 },
1733 [MT76_TM_STATS_ATTR_RX_PACKETS] = { .type = NLA_U64 },
1734 [MT76_TM_STATS_ATTR_RX_FCS_ERROR] = { .type = NLA_U64 },
1735+ [MT76_TM_STATS_ATTR_RX_LEN_MISMATCH] = { .type = NLA_U64 },
1736 };
1737 #undef FIELD_NAME
1738
1739@@ -300,12 +369,20 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
1740 FIELD(u8, TX_RATE_LDPC, "tx_rate_ldpc"),
1741 FIELD(u8, TX_RATE_STBC, "tx_rate_stbc"),
1742 FIELD(u8, TX_LTF, "tx_ltf"),
1743+ FIELD(u8, TX_DUTY_CYCLE, "tx_duty_cycle"),
1744+ FIELD(u32, TX_IPG, "tx_ipg"),
1745+ FIELD(u32, TX_TIME, "tx_time"),
1746 FIELD(u8, TX_POWER_CONTROL, "tx_power_control"),
1747 FIELD_ARRAY(u8, TX_POWER, "tx_power"),
1748 FIELD(u8, TX_ANTENNA, "tx_antenna"),
1749 FIELD(u32, FREQ_OFFSET, "freq_offset"),
1750+ FIELD(u8, AID, "aid"),
1751+ FIELD(u8, RU_ALLOC, "ru_alloc"),
1752+ FIELD(u8, RU_IDX, "ru_idx"),
1753+ FIELD_MAC(MAC_ADDRS, "mac_addrs"),
1754 FIELD_NESTED_RO(STATS, stats, "",
1755 .print_extra = print_extra_stats),
1756+
1757 };
1758 #undef FIELD_NAME
1759
1760@@ -322,10 +399,25 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
1761 [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },
1762 [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },
1763 [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },
1764+ [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 },
1765+ [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 },
1766+ [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
1767 [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
1768 [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },
1769+ [MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 },
1770 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
1771+ [MT76_TM_ATTR_AID] = { .type = NLA_U8 },
1772+ [MT76_TM_ATTR_RU_ALLOC] = { .type = NLA_U8 },
1773+ [MT76_TM_ATTR_RU_IDX] = { .type = NLA_U8 },
1774 [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED },
1775+ [MT76_TM_ATTR_TXBF_ACT] = { .type = NLA_U8 },
1776+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
1777+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
1778+ [MT76_TM_ATTR_OFF_CH_SCAN_BW] = { .type = NLA_U8 },
1779+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
1780+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
1781+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
1782+ [MT76_TM_ATTR_IPI_RESET] = { .type = NLA_U8 },
1783 };
1784
1785 const struct tm_field msg_field = {
1786--
developer78848c62023-04-06 13:44:00 +080017872.18.0
developerd5789dc2023-03-27 11:22:06 +08001788