blob: f83d3493d983abdf9428fd3982f1b70f473d0062 [file] [log] [blame]
developerc992b602024-02-28 08:42:27 +08001From 2d5fc96468c8e2d8d27a2a85cc94dfac55d5aaa8 Mon Sep 17 00:00:00 2001
developer1bc2ce22023-03-25 00:47:41 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Wed, 1 Mar 2023 11:59:16 +0800
developer07b5baf2024-01-10 04:38:47 +08004Subject: [PATCH 1004/1044] mtk: wifi: mt76: testmode: add basic testmode
developer5f4e6c32023-12-20 06:12:53 +08005 support
developer1bc2ce22023-03-25 00:47:41 +08006
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
developer5f4e6c32023-12-20 06:12:53 +08008
9Add testmode eeprom buffer mode support
10
11Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
12
13Fix power & freq offset issue for iTest power cal & tx/rx verifcation
141. Wait for fw to tx. Otherwise, iTest testing tool cannot get the
15accurate tx power.
162. In crystal mode, freq offset is set in 6G band and forwarded to 5G
17and 2G band. Therefore, we should avoid reseting freq offset to 0 when
186G interface is off.
19
20Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
21
22edcca return err in testmode; therefore, bypass it when we are in testmode idle state or testmode bf is on
23
24Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
developer1bc2ce22023-03-25 00:47:41 +080025---
26 eeprom.c | 6 +-
27 mac80211.c | 3 +-
developer5f4e6c32023-12-20 06:12:53 +080028 mt76.h | 36 +++
developer1bc2ce22023-03-25 00:47:41 +080029 mt76_connac_mcu.h | 2 +
developerc2cfe0f2023-09-22 04:11:09 +080030 mt7996/Makefile | 1 +
developer1bc2ce22023-03-25 00:47:41 +080031 mt7996/eeprom.c | 35 ++-
32 mt7996/eeprom.h | 1 +
developer7e2761e2023-10-12 08:11:13 +080033 mt7996/init.c | 8 +
developerc2cfe0f2023-09-22 04:11:09 +080034 mt7996/mac.c | 3 +-
developer5f4e6c32023-12-20 06:12:53 +080035 mt7996/main.c | 26 ++
36 mt7996/mcu.c | 59 +++-
37 mt7996/mcu.h | 33 +++
38 mt7996/mt7996.h | 28 +-
39 mt7996/testmode.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++
40 mt7996/testmode.h | 299 +++++++++++++++++++
41 testmode.c | 123 ++++++--
42 testmode.h | 85 +++++-
developerc2cfe0f2023-09-22 04:11:09 +080043 tools/fields.c | 102 ++++++-
developer5f4e6c32023-12-20 06:12:53 +080044 18 files changed, 1542 insertions(+), 48 deletions(-)
developer1bc2ce22023-03-25 00:47:41 +080045 create mode 100644 mt7996/testmode.c
46 create mode 100644 mt7996/testmode.h
47
48diff --git a/eeprom.c b/eeprom.c
developer5f4e6c32023-12-20 06:12:53 +080049index 7d5cf28f..85bd2a29 100644
developer1bc2ce22023-03-25 00:47:41 +080050--- a/eeprom.c
51+++ b/eeprom.c
developer5f4e6c32023-12-20 06:12:53 +080052@@ -94,8 +94,10 @@ int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int l
developer1bc2ce22023-03-25 00:47:41 +080053 }
54
55 #ifdef CONFIG_NL80211_TESTMODE
56- dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
57- dev->test_mtd.offset = offset;
58+ if (len == dev->eeprom.size) {
59+ dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
60+ dev->test_mtd.offset = offset;
61+ }
62 #endif
63
64 out_put_node:
65diff --git a/mac80211.c b/mac80211.c
developer67bb1212024-02-04 16:58:38 +080066index 6e8ac6f4..fea19e19 100644
developer1bc2ce22023-03-25 00:47:41 +080067--- a/mac80211.c
68+++ b/mac80211.c
developer5f4e6c32023-12-20 06:12:53 +080069@@ -846,7 +846,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
developer1bc2ce22023-03-25 00:47:41 +080070 }
71
72 #ifdef CONFIG_NL80211_TESTMODE
73- if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
74+ if (!(phy->test.flag & MT_TM_FW_RX_COUNT) &&
75+ phy->test.state == MT76_TM_STATE_RX_FRAMES) {
76 phy->test.rx_stats.packets[q]++;
77 if (status->flag & RX_FLAG_FAILED_FCS_CRC)
78 phy->test.rx_stats.fcs_error[q]++;
79diff --git a/mt76.h b/mt76.h
developer67bb1212024-02-04 16:58:38 +080080index 5c50681a..ea051c03 100644
developer1bc2ce22023-03-25 00:47:41 +080081--- a/mt76.h
82+++ b/mt76.h
developer67bb1212024-02-04 16:58:38 +080083@@ -695,14 +695,21 @@ struct mt76_testmode_ops {
developer1bc2ce22023-03-25 00:47:41 +080084 int (*set_params)(struct mt76_phy *phy, struct nlattr **tb,
85 enum mt76_testmode_state new_state);
86 int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg);
87+ void (*reset_rx_stats)(struct mt76_phy *phy);
88+ void (*tx_stop)(struct mt76_phy *phy);
developer5f4e6c32023-12-20 06:12:53 +080089+ int (*set_eeprom)(struct mt76_phy *phy, u32 offset, u8 *val, u8 action);
developer1bc2ce22023-03-25 00:47:41 +080090 };
91
92+#define MT_TM_FW_RX_COUNT BIT(0)
93+
94 struct mt76_testmode_data {
95 enum mt76_testmode_state state;
96
developerc2cfe0f2023-09-22 04:11:09 +080097 u32 param_set[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)];
98 struct sk_buff *tx_skb;
99
100+ u8 sku_en;
101+
102 u32 tx_count;
103 u16 tx_mpdu_len;
104
developer67bb1212024-02-04 16:58:38 +0800105@@ -712,6 +719,7 @@ struct mt76_testmode_data {
developer1bc2ce22023-03-25 00:47:41 +0800106 u8 tx_rate_sgi;
107 u8 tx_rate_ldpc;
108 u8 tx_rate_stbc;
109+ u16 tx_preamble_puncture;
110 u8 tx_ltf;
111
112 u8 tx_antenna_mask;
developer67bb1212024-02-04 16:58:38 +0800113@@ -721,6 +729,9 @@ struct mt76_testmode_data {
developer1bc2ce22023-03-25 00:47:41 +0800114 u32 tx_time;
115 u32 tx_ipg;
116
117+ bool ibf;
118+ bool ebf;
119+
120 u32 freq_offset;
121
122 u8 tx_power[4];
developer67bb1212024-02-04 16:58:38 +0800123@@ -735,7 +746,16 @@ struct mt76_testmode_data {
developer1bc2ce22023-03-25 00:47:41 +0800124 struct {
125 u64 packets[__MT_RXQ_MAX];
126 u64 fcs_error[__MT_RXQ_MAX];
127+ u64 len_mismatch;
128 } rx_stats;
129+ u8 flag;
developerde9ecce2023-05-22 11:17:16 +0800130+
131+ struct {
132+ u8 type;
133+ u8 enable;
134+ } cfg;
135+
developer1bc2ce22023-03-25 00:47:41 +0800136+ u8 aid;
137 };
138
139 struct mt76_vif {
developer67bb1212024-02-04 16:58:38 +0800140@@ -1439,6 +1459,22 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
developerde9ecce2023-05-22 11:17:16 +0800141 int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state);
142 int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len);
143
144+static inline void
145+mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx)
146+{
147+#ifdef CONFIG_NL80211_TESTMODE
148+ td->param_set[idx / 32] |= BIT(idx % 32);
149+#endif
150+}
151+
152+static inline bool
153+mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx)
154+{
155+#ifdef CONFIG_NL80211_TESTMODE
156+ return td->param_set[idx / 32] & BIT(idx % 32);
157+#endif
158+}
159+
160 static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
161 {
162 #ifdef CONFIG_NL80211_TESTMODE
developer1bc2ce22023-03-25 00:47:41 +0800163diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developer67bb1212024-02-04 16:58:38 +0800164index 482782f7..2e148011 100644
developer1bc2ce22023-03-25 00:47:41 +0800165--- a/mt76_connac_mcu.h
166+++ b/mt76_connac_mcu.h
developer67bb1212024-02-04 16:58:38 +0800167@@ -1266,12 +1266,14 @@ enum {
developer1bc2ce22023-03-25 00:47:41 +0800168 MCU_UNI_CMD_EFUSE_CTRL = 0x2d,
169 MCU_UNI_CMD_RA = 0x2f,
170 MCU_UNI_CMD_MURU = 0x31,
171+ MCU_UNI_CMD_TESTMODE_RX_STAT = 0x32,
172 MCU_UNI_CMD_BF = 0x33,
173 MCU_UNI_CMD_CHANNEL_SWITCH = 0x34,
174 MCU_UNI_CMD_THERMAL = 0x35,
175 MCU_UNI_CMD_VOW = 0x37,
developer7e2761e2023-10-12 08:11:13 +0800176 MCU_UNI_CMD_PP = 0x38,
developerc2cfe0f2023-09-22 04:11:09 +0800177 MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
developer1bc2ce22023-03-25 00:47:41 +0800178+ MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
179 MCU_UNI_CMD_RRO = 0x57,
180 MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
developerc2cfe0f2023-09-22 04:11:09 +0800181 MCU_UNI_CMD_PER_STA_INFO = 0x6d,
developer1bc2ce22023-03-25 00:47:41 +0800182diff --git a/mt7996/Makefile b/mt7996/Makefile
developer5f4e6c32023-12-20 06:12:53 +0800183index a056b40e..7bb17f44 100644
developer1bc2ce22023-03-25 00:47:41 +0800184--- a/mt7996/Makefile
185+++ b/mt7996/Makefile
developerc2cfe0f2023-09-22 04:11:09 +0800186@@ -8,5 +8,6 @@ mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
developer1bc2ce22023-03-25 00:47:41 +0800187 debugfs.o mmio.o
developerde9ecce2023-05-22 11:17:16 +0800188
189 mt7996e-$(CONFIG_DEV_COREDUMP) += coredump.o
developer1bc2ce22023-03-25 00:47:41 +0800190+mt7996e-$(CONFIG_NL80211_TESTMODE) += testmode.o
developerc2cfe0f2023-09-22 04:11:09 +0800191
192 mt7996e-y += mtk_debugfs.o mtk_mcu.o
developer1bc2ce22023-03-25 00:47:41 +0800193diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
developer07b5baf2024-01-10 04:38:47 +0800194index 121a3c95..2299793d 100644
developer1bc2ce22023-03-25 00:47:41 +0800195--- a/mt7996/eeprom.c
196+++ b/mt7996/eeprom.c
197@@ -6,6 +6,11 @@
198 #include <linux/firmware.h>
199 #include "mt7996.h"
200 #include "eeprom.h"
201+#include <linux/moduleparam.h>
202+
203+static bool testmode_enable;
204+module_param(testmode_enable, bool, 0644);
205+MODULE_PARM_DESC(testmode_enable, "Enable testmode");
206
207 static int mt7996_check_eeprom(struct mt7996_dev *dev)
208 {
developer07b5baf2024-01-10 04:38:47 +0800209@@ -43,6 +48,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
developer5f4e6c32023-12-20 06:12:53 +0800210
developer1bc2ce22023-03-25 00:47:41 +0800211 static char *mt7996_eeprom_name(struct mt7996_dev *dev)
212 {
developer1bc2ce22023-03-25 00:47:41 +0800213+ if (dev->testmode_enable)
214+ return MT7996_EEPROM_DEFAULT_TM;
developer5f4e6c32023-12-20 06:12:53 +0800215+
216 switch (mt76_chip(&dev->mt76)) {
217 case 0x7990:
218 if (dev->chip_sku == MT7996_SKU_404)
developer07b5baf2024-01-10 04:38:47 +0800219@@ -92,21 +100,36 @@ out:
developer1bc2ce22023-03-25 00:47:41 +0800220 return ret;
221 }
222
223-static int mt7996_eeprom_load(struct mt7996_dev *dev)
224+int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev)
225 {
226+ u8 *eeprom;
227 int ret;
228
229+ /* load eeprom in flash or bin file mode to determine fw mode */
230 ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
231 if (ret < 0)
232 return ret;
233
234 if (ret) {
235 dev->flash_mode = true;
236- } else {
237- u8 free_block_num;
238- u32 block_num, i;
239- u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
240+ eeprom = dev->mt76.eeprom.data;
241+ /* testmode enable priority: eeprom field > module parameter */
242+ dev->testmode_enable = !mt7996_check_eeprom(dev) ? eeprom[MT_EE_TESTMODE_EN] :
243+ testmode_enable;
244+ }
245+
246+ return ret;
247+}
248+
249+static int mt7996_eeprom_load(struct mt7996_dev *dev)
250+{
251+ int ret;
252+ u8 free_block_num;
253+ u32 block_num, i;
254+ u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
255
256+ /* flash or bin file mode eeprom is loaded before mcu init */
257+ if (!dev->flash_mode) {
258 ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num);
259 if (ret < 0)
260 return ret;
developer07b5baf2024-01-10 04:38:47 +0800261@@ -118,7 +141,7 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
developer5f4e6c32023-12-20 06:12:53 +0800262 /* read eeprom data from efuse */
263 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
264 for (i = 0; i < block_num; i++) {
265- ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size);
266+ ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, NULL);
267 if (ret < 0)
268 return ret;
269 }
developer1bc2ce22023-03-25 00:47:41 +0800270diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
developer5f4e6c32023-12-20 06:12:53 +0800271index 72c38ad3..de3ff4e2 100644
developer1bc2ce22023-03-25 00:47:41 +0800272--- a/mt7996/eeprom.h
273+++ b/mt7996/eeprom.h
274@@ -14,6 +14,7 @@ enum mt7996_eeprom_field {
275 MT_EE_MAC_ADDR = 0x004,
276 MT_EE_MAC_ADDR2 = 0x00a,
277 MT_EE_WIFI_CONF = 0x190,
278+ MT_EE_TESTMODE_EN = 0x1af,
279 MT_EE_MAC_ADDR3 = 0x2c0,
280 MT_EE_RATE_DELTA_2G = 0x1400,
281 MT_EE_RATE_DELTA_5G = 0x147d,
282diff --git a/mt7996/init.c b/mt7996/init.c
developer67bb1212024-02-04 16:58:38 +0800283index 0e3cdc05..d4d1a60b 100644
developer1bc2ce22023-03-25 00:47:41 +0800284--- a/mt7996/init.c
285+++ b/mt7996/init.c
developer07b5baf2024-01-10 04:38:47 +0800286@@ -966,6 +966,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
developer1bc2ce22023-03-25 00:47:41 +0800287
288 set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
289
290+ ret = mt7996_eeprom_check_fw_mode(dev);
291+ if (ret < 0)
292+ return ret;
293+
294 ret = mt7996_mcu_init(dev);
295 if (ret)
296 return ret;
developer07b5baf2024-01-10 04:38:47 +0800297@@ -1384,6 +1388,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
developer1bc2ce22023-03-25 00:47:41 +0800298
developer7e2761e2023-10-12 08:11:13 +0800299 mt7996_init_wiphy(hw, &dev->mt76.mmio.wed);
developer1bc2ce22023-03-25 00:47:41 +0800300
301+#ifdef CONFIG_NL80211_TESTMODE
302+ dev->mt76.test_ops = &mt7996_testmode_ops;
303+#endif
developer7e2761e2023-10-12 08:11:13 +0800304+
developerc2cfe0f2023-09-22 04:11:09 +0800305 ret = mt76_register_device(&dev->mt76, true, mt76_rates,
306 ARRAY_SIZE(mt76_rates));
307 if (ret)
308diff --git a/mt7996/mac.c b/mt7996/mac.c
developer67bb1212024-02-04 16:58:38 +0800309index 89a03122..9a9d33e6 100644
developerc2cfe0f2023-09-22 04:11:09 +0800310--- a/mt7996/mac.c
311+++ b/mt7996/mac.c
developer7e2761e2023-10-12 08:11:13 +0800312@@ -685,7 +685,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
313 *info);
developerc2cfe0f2023-09-22 04:11:09 +0800314 }
315
316- if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
317+ if (rxv && mode >= MT_PHY_TYPE_HE_SU && mode < MT_PHY_TYPE_EHT_SU &&
318+ !(status->flag & RX_FLAG_8023))
319 mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
320
developer7e2761e2023-10-12 08:11:13 +0800321 if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
developer1bc2ce22023-03-25 00:47:41 +0800322diff --git a/mt7996/main.c b/mt7996/main.c
developer67bb1212024-02-04 16:58:38 +0800323index ad2c6a9d..40b5cee3 100644
developer1bc2ce22023-03-25 00:47:41 +0800324--- a/mt7996/main.c
325+++ b/mt7996/main.c
developer064da3c2023-06-13 15:57:26 +0800326@@ -23,6 +23,18 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
developer1bc2ce22023-03-25 00:47:41 +0800327 return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
328 }
329
330+static void mt7996_testmode_disable_all(struct mt7996_dev *dev)
331+{
332+ struct mt7996_phy *phy;
333+ int i;
334+
335+ for (i = 0; i < __MT_MAX_BAND; i++) {
336+ phy = __mt7996_phy(dev, i);
developer064da3c2023-06-13 15:57:26 +0800337+ if (phy)
338+ mt76_testmode_set_state(phy->mt76, MT76_TM_STATE_OFF);
developer1bc2ce22023-03-25 00:47:41 +0800339+ }
340+}
341+
342 int mt7996_run(struct ieee80211_hw *hw)
343 {
344 struct mt7996_dev *dev = mt7996_hw_dev(hw);
developer064da3c2023-06-13 15:57:26 +0800345@@ -37,6 +49,8 @@ int mt7996_run(struct ieee80211_hw *hw)
developer1bc2ce22023-03-25 00:47:41 +0800346 goto out;
347 }
348
349+ mt7996_testmode_disable_all(dev);
350+
351 mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
352
353 ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
developer5f4e6c32023-12-20 06:12:53 +0800354@@ -291,6 +305,11 @@ int mt7996_set_channel(struct mt7996_phy *phy)
355
356 mt76_set_channel(phy->mt76);
357
358+ if (mt76_testmode_enabled(phy->mt76) || phy->mt76->test.bf_en) {
359+ mt7996_tm_update_channel(phy);
360+ goto out;
361+ }
362+
363 ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
364 if (ret)
365 goto out;
366@@ -398,6 +417,11 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
367 int ret;
368
369 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
370+ if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
371+ ret = mt7996_mcu_edcca_enable(phy, true);
372+ if (ret)
373+ return ret;
374+ }
375 ieee80211_stop_queues(hw);
376 ret = mt7996_set_channel(phy);
377 if (ret)
378@@ -1507,6 +1531,8 @@ const struct ieee80211_ops mt7996_ops = {
developer1bc2ce22023-03-25 00:47:41 +0800379 .sta_set_decap_offload = mt7996_sta_set_decap_offload,
380 .add_twt_setup = mt7996_mac_add_twt_setup,
381 .twt_teardown_request = mt7996_twt_teardown_request,
382+ CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
383+ CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
384 #ifdef CONFIG_MAC80211_DEBUGFS
385 .sta_add_debugfs = mt7996_sta_add_debugfs,
386 #endif
387diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developerc992b602024-02-28 08:42:27 +0800388index b488a78f..d8795d30 100644
developer1bc2ce22023-03-25 00:47:41 +0800389--- a/mt7996/mcu.c
390+++ b/mt7996/mcu.c
developerc992b602024-02-28 08:42:27 +0800391@@ -2863,8 +2863,12 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
developer064da3c2023-06-13 15:57:26 +0800392 {
393 int ret;
developer1bc2ce22023-03-25 00:47:41 +0800394
developer5f4e6c32023-12-20 06:12:53 +0800395- ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM),
developer064da3c2023-06-13 15:57:26 +0800396- MT7996_RAM_TYPE_WM);
developer1bc2ce22023-03-25 00:47:41 +0800397+ if (dev->testmode_enable)
developer5f4e6c32023-12-20 06:12:53 +0800398+ ret = __mt7996_load_ram(dev, "WM_TM", fw_name(dev, FIRMWARE_WM_TM),
developer064da3c2023-06-13 15:57:26 +0800399+ MT7996_RAM_TYPE_WM_TM);
developer1bc2ce22023-03-25 00:47:41 +0800400+ else
developer5f4e6c32023-12-20 06:12:53 +0800401+ ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM),
developer064da3c2023-06-13 15:57:26 +0800402+ MT7996_RAM_TYPE_WM);
403 if (ret)
404 return ret;
405
developerc992b602024-02-28 08:42:27 +0800406@@ -3555,17 +3559,9 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
developer5f4e6c32023-12-20 06:12:53 +0800407 &req, sizeof(req), true);
408 }
409
410-int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
411+int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf)
412 {
413- struct {
414- u8 _rsv[4];
415-
416- __le16 tag;
417- __le16 len;
418- __le32 addr;
419- __le32 valid;
420- u8 data[16];
421- } __packed req = {
422+ struct mt7996_mcu_eeprom_info req = {
423 .tag = cpu_to_le16(UNI_EFUSE_ACCESS),
424 .len = cpu_to_le16(sizeof(req) - 4),
425 .addr = cpu_to_le32(round_down(offset,
developerc992b602024-02-28 08:42:27 +0800426@@ -3574,6 +3570,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
developer5f4e6c32023-12-20 06:12:53 +0800427 struct sk_buff *skb;
428 bool valid;
429 int ret;
430+ u8 *buf = read_buf;
431
432 ret = mt76_mcu_send_and_get_msg(&dev->mt76,
433 MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL),
developerc992b602024-02-28 08:42:27 +0800434@@ -3584,7 +3581,9 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
developer5f4e6c32023-12-20 06:12:53 +0800435 valid = le32_to_cpu(*(__le32 *)(skb->data + 16));
436 if (valid) {
437 u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12));
438- u8 *buf = (u8 *)dev->mt76.eeprom.data + addr;
439+
440+ if (!buf)
441+ buf = (u8 *)dev->mt76.eeprom.data + addr;
442
443 skb_pull(skb, 48);
444 memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE);
developerc992b602024-02-28 08:42:27 +0800445@@ -4577,3 +4576,37 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, bool auto_mode,
developer7e2761e2023-10-12 08:11:13 +0800446 return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PP),
developerc2cfe0f2023-09-22 04:11:09 +0800447 &req, sizeof(req), false);
developer1bc2ce22023-03-25 00:47:41 +0800448 }
449+
450+int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data)
451+{
452+ struct mt7996_dev *dev = phy->dev;
453+ struct tx_power_ctrl req = {
454+ .tag = cpu_to_le16(power_ctrl_id),
455+ .len = cpu_to_le16(sizeof(req) - 4),
456+ .power_ctrl_id = power_ctrl_id,
457+ .band_idx = phy->mt76->band_idx,
458+ };
459+
460+ switch (power_ctrl_id) {
461+ case UNI_TXPOWER_SKU_POWER_LIMIT_CTRL:
462+ req.sku_enable = !!data;
463+ break;
464+ case UNI_TXPOWER_PERCENTAGE_CTRL:
465+ req.percentage_ctrl_enable = !!data;
466+ break;
467+ case UNI_TXPOWER_PERCENTAGE_DROP_CTRL:
468+ req.power_drop_level = data;
469+ break;
470+ case UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL:
471+ req.bf_backoff_enable = !!data;
472+ break;
473+ case UNI_TXPOWER_ATE_MODE_CTRL:
474+ req.ate_mode_enable = !!data;
475+ break;
476+ default:
477+ req.sku_enable = !!data;
478+ }
479+
480+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER),
481+ &req, sizeof(req), false);
482+}
483diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developer5f4e6c32023-12-20 06:12:53 +0800484index 238c4c53..325c3c97 100644
developer1bc2ce22023-03-25 00:47:41 +0800485--- a/mt7996/mcu.h
486+++ b/mt7996/mcu.h
developer5f4e6c32023-12-20 06:12:53 +0800487@@ -157,6 +157,16 @@ struct mt7996_mcu_eeprom {
488 __le16 buf_len;
489 } __packed;
490
491+struct mt7996_mcu_eeprom_info {
492+ u8 _rsv[4];
493+
494+ __le16 tag;
495+ __le16 len;
496+ __le32 addr;
497+ __le32 valid;
498+ u8 data[MT7996_EEPROM_BLOCK_SIZE];
499+} __packed;
500+
501 struct mt7996_mcu_phy_rx_info {
502 u8 category;
503 u8 rate;
504@@ -889,8 +899,31 @@ enum {
developer1bc2ce22023-03-25 00:47:41 +0800505 UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
506 };
507
508+struct tx_power_ctrl {
509+ u8 _rsv[4];
510+
511+ __le16 tag;
512+ __le16 len;
513+
514+ u8 power_ctrl_id;
515+ union {
516+ bool sku_enable;
517+ bool ate_mode_enable;
518+ bool percentage_ctrl_enable;
519+ bool bf_backoff_enable;
520+ u8 power_drop_level;
521+ };
522+ u8 band_idx;
523+ u8 rsv[1];
524+} __packed;
525+
developer5f4e6c32023-12-20 06:12:53 +0800526 enum {
developer1bc2ce22023-03-25 00:47:41 +0800527+ UNI_TXPOWER_SKU_POWER_LIMIT_CTRL = 0,
528+ UNI_TXPOWER_PERCENTAGE_CTRL = 1,
529+ UNI_TXPOWER_PERCENTAGE_DROP_CTRL = 2,
530+ UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
developer5f4e6c32023-12-20 06:12:53 +0800531 UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
developer1bc2ce22023-03-25 00:47:41 +0800532+ UNI_TXPOWER_ATE_MODE_CTRL = 6,
developer5f4e6c32023-12-20 06:12:53 +0800533 };
534
developer1bc2ce22023-03-25 00:47:41 +0800535 enum {
developer1bc2ce22023-03-25 00:47:41 +0800536diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer5f4e6c32023-12-20 06:12:53 +0800537index 29976860..5af55492 100644
developer1bc2ce22023-03-25 00:47:41 +0800538--- a/mt7996/mt7996.h
539+++ b/mt7996/mt7996.h
developer5f4e6c32023-12-20 06:12:53 +0800540@@ -32,25 +32,30 @@
developer1bc2ce22023-03-25 00:47:41 +0800541 #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin"
542 #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin"
543 #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
544+#define MT7996_FIRMWARE_WM_TM "mediatek/mt7996/mt7996_wm_tm.bin"
545 #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
546
developer5f4e6c32023-12-20 06:12:53 +0800547 #define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin"
548 #define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin"
549 #define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin"
550+#define MT7992_FIRMWARE_WM_TM "mediatek/mt7996/mt7992_wm_tm.bin"
551 #define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin"
552
553 #define MT7992_FIRMWARE_WA_24 "mediatek/mt7996/mt7992_wa_24.bin"
554 #define MT7992_FIRMWARE_WM_24 "mediatek/mt7996/mt7992_wm_24.bin"
555 #define MT7992_FIRMWARE_DSP_24 "mediatek/mt7996/mt7992_dsp_24.bin"
556+#define MT7992_FIRMWARE_WM_TM_24 "mediatek/mt7996/mt7992_wm_tm_24.bin"
557 #define MT7992_ROM_PATCH_24 "mediatek/mt7996/mt7992_rom_patch_24.bin"
558
559 #define MT7992_FIRMWARE_WA_23 "mediatek/mt7996/mt7992_wa_23.bin"
560 #define MT7992_FIRMWARE_WM_23 "mediatek/mt7996/mt7992_wm_23.bin"
561 #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin"
562+#define MT7992_FIRMWARE_WM_TM_23 "mediatek/mt7996/mt7992_wm_tm_23.bin"
563 #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin"
564
developer1bc2ce22023-03-25 00:47:41 +0800565 #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
developer5f4e6c32023-12-20 06:12:53 +0800566 #define MT7996_EEPROM_DEFAULT_404 "mediatek/mt7996/mt7996_eeprom_dual_404.bin"
developer1bc2ce22023-03-25 00:47:41 +0800567+#define MT7996_EEPROM_DEFAULT_TM "mediatek/mt7996/mt7996_eeprom_tm.bin"
developer5f4e6c32023-12-20 06:12:53 +0800568 #define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom_2i5i.bin"
569 #define MT7992_EEPROM_DEFAULT_EXT "mediatek/mt7996/mt7992_eeprom_2e5e.bin"
570 #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin"
571@@ -126,6 +131,7 @@ enum mt7992_sku_type {
developer1bc2ce22023-03-25 00:47:41 +0800572
573 enum mt7996_ram_type {
developer064da3c2023-06-13 15:57:26 +0800574 MT7996_RAM_TYPE_WM,
developer1bc2ce22023-03-25 00:47:41 +0800575+ MT7996_RAM_TYPE_WM_TM = MT7996_RAM_TYPE_WM,
576 MT7996_RAM_TYPE_WA,
577 MT7996_RAM_TYPE_DSP,
developerc2cfe0f2023-09-22 04:11:09 +0800578 __MT7996_RAM_TYPE_MAX,
developer5f4e6c32023-12-20 06:12:53 +0800579@@ -273,6 +279,21 @@ struct mt7996_phy {
developer1bc2ce22023-03-25 00:47:41 +0800580 struct mt76_channel_state state_ts;
developerc2cfe0f2023-09-22 04:11:09 +0800581
582 bool has_aux_rx;
developer1bc2ce22023-03-25 00:47:41 +0800583+
584+#ifdef CONFIG_NL80211_TESTMODE
585+ struct {
586+ u32 *reg_backup;
587+
588+ s32 last_freq_offset;
589+ u8 last_rcpi[4];
developerc2cfe0f2023-09-22 04:11:09 +0800590+ s8 last_rssi[4];
developer1bc2ce22023-03-25 00:47:41 +0800591+ s8 last_ib_rssi[4];
592+ s8 last_wb_rssi[4];
593+ u8 last_snr;
594+
595+ u8 spe_idx;
596+ } test;
597+#endif
598 };
599
600 struct mt7996_dev {
developer5f4e6c32023-12-20 06:12:53 +0800601@@ -353,6 +374,8 @@ struct mt7996_dev {
602 spinlock_t lock;
developer7e2761e2023-10-12 08:11:13 +0800603 } wed_rro;
developer1bc2ce22023-03-25 00:47:41 +0800604
605+ bool testmode_enable;
606+
607 bool ibf;
608 u8 fw_debug_wm;
609 u8 fw_debug_wa;
developer5f4e6c32023-12-20 06:12:53 +0800610@@ -467,6 +490,7 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
developer1bc2ce22023-03-25 00:47:41 +0800611 extern const struct ieee80211_ops mt7996_ops;
612 extern struct pci_driver mt7996_pci_driver;
613 extern struct pci_driver mt7996_hif_driver;
614+extern const struct mt76_testmode_ops mt7996_testmode_ops;
615
616 struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
617 void __iomem *mem_base, u32 device_id);
developer5f4e6c32023-12-20 06:12:53 +0800618@@ -476,6 +500,7 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
developer1bc2ce22023-03-25 00:47:41 +0800619 int mt7996_register_device(struct mt7996_dev *dev);
620 void mt7996_unregister_device(struct mt7996_dev *dev);
621 int mt7996_eeprom_init(struct mt7996_dev *dev);
622+int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev);
623 int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
624 int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
625 struct ieee80211_channel *chan);
developer5f4e6c32023-12-20 06:12:53 +0800626@@ -528,7 +553,7 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
627 int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
628 struct ieee80211_sta *sta, void *data, u32 field);
629 int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
630-int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset);
631+int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf);
632 int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
633 int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap);
634 int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band);
635@@ -563,6 +588,7 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
developer1bc2ce22023-03-25 00:47:41 +0800636 void mt7996_mcu_exit(struct mt7996_dev *dev);
developer7e2761e2023-10-12 08:11:13 +0800637 int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
developer5f4e6c32023-12-20 06:12:53 +0800638 int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
developer1bc2ce22023-03-25 00:47:41 +0800639+int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
640
641 static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
642 {
643diff --git a/mt7996/testmode.c b/mt7996/testmode.c
644new file mode 100644
developer5f4e6c32023-12-20 06:12:53 +0800645index 00000000..96079c22
developer1bc2ce22023-03-25 00:47:41 +0800646--- /dev/null
647+++ b/mt7996/testmode.c
developer5f4e6c32023-12-20 06:12:53 +0800648@@ -0,0 +1,740 @@
developer1bc2ce22023-03-25 00:47:41 +0800649+// SPDX-License-Identifier: ISC
650+/*
651+ * Copyright (C) 2022 MediaTek Inc.
652+ */
653+
654+#include "mt7996.h"
655+#include "mac.h"
656+#include "mcu.h"
657+#include "testmode.h"
658+
659+enum {
660+ TM_CHANGED_TXPOWER,
661+ TM_CHANGED_FREQ_OFFSET,
developerc2cfe0f2023-09-22 04:11:09 +0800662+ TM_CHANGED_SKU_EN,
developer1bc2ce22023-03-25 00:47:41 +0800663+ TM_CHANGED_TX_LENGTH,
664+ TM_CHANGED_TX_TIME,
developerde9ecce2023-05-22 11:17:16 +0800665+ TM_CHANGED_CFG,
developer1bc2ce22023-03-25 00:47:41 +0800666+
667+ /* must be last */
668+ NUM_TM_CHANGED
669+};
670+
671+static const u8 tm_change_map[] = {
672+ [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER,
673+ [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,
developerc2cfe0f2023-09-22 04:11:09 +0800674+ [TM_CHANGED_SKU_EN] = MT76_TM_ATTR_SKU_EN,
developer1bc2ce22023-03-25 00:47:41 +0800675+ [TM_CHANGED_TX_LENGTH] = MT76_TM_ATTR_TX_LENGTH,
676+ [TM_CHANGED_TX_TIME] = MT76_TM_ATTR_TX_TIME,
developerde9ecce2023-05-22 11:17:16 +0800677+ [TM_CHANGED_CFG] = MT76_TM_ATTR_CFG,
developer1bc2ce22023-03-25 00:47:41 +0800678+};
679+
680+static u8 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_method method)
681+{
682+ static const u8 width_to_bw[][NUM_BW_MAP] = {
683+ [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ},
684+ [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ},
685+ [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ},
686+ [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ},
687+ [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ},
688+ [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ},
689+ [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
690+ [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
691+ [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ},
692+ };
693+
694+ if (width >= ARRAY_SIZE(width_to_bw))
695+ return 0;
696+
697+ return width_to_bw[width][method];
698+}
699+
700+static u8 mt7996_tm_rate_to_phy(u8 tx_rate_mode)
701+{
702+ static const u8 rate_to_phy[] = {
703+ [MT76_TM_TX_MODE_CCK] = MT_PHY_TYPE_CCK,
704+ [MT76_TM_TX_MODE_OFDM] = MT_PHY_TYPE_OFDM,
705+ [MT76_TM_TX_MODE_HT] = MT_PHY_TYPE_HT,
706+ [MT76_TM_TX_MODE_VHT] = MT_PHY_TYPE_VHT,
707+ [MT76_TM_TX_MODE_HE_SU] = MT_PHY_TYPE_HE_SU,
708+ [MT76_TM_TX_MODE_HE_EXT_SU] = MT_PHY_TYPE_HE_EXT_SU,
709+ [MT76_TM_TX_MODE_HE_TB] = MT_PHY_TYPE_HE_TB,
710+ [MT76_TM_TX_MODE_HE_MU] = MT_PHY_TYPE_HE_MU,
711+ [MT76_TM_TX_MODE_EHT_SU] = MT_PHY_TYPE_EHT_SU,
712+ [MT76_TM_TX_MODE_EHT_TRIG] = MT_PHY_TYPE_EHT_TRIG,
713+ [MT76_TM_TX_MODE_EHT_MU] = MT_PHY_TYPE_EHT_MU,
714+ };
715+
716+ if (tx_rate_mode > MT76_TM_TX_MODE_MAX)
717+ return -EINVAL;
718+
719+ return rate_to_phy[tx_rate_mode];
720+}
721+
722+static int
developer064da3c2023-06-13 15:57:26 +0800723+mt7996_tm_check_antenna(struct mt7996_phy *phy)
724+{
725+ struct mt76_testmode_data *td = &phy->mt76->test;
726+ struct mt7996_dev *dev = phy->dev;
727+ u8 band_idx = phy->mt76->band_idx;
728+ u32 chainmask = phy->mt76->chainmask;
729+ u32 aux_rx_mask;
730+
731+ chainmask = chainmask >> dev->chainshift[band_idx];
732+ aux_rx_mask = BIT(fls(chainmask)) * phy->has_aux_rx;
733+ if (td->tx_antenna_mask & ~(chainmask | aux_rx_mask)) {
734+ dev_err(dev->mt76.dev,
735+ "tx antenna mask 0x%x exceeds hw limit (chainmask 0x%x, has aux rx: %s)\n",
736+ td->tx_antenna_mask, chainmask, phy->has_aux_rx ? "yes" : "no");
737+ return -EINVAL;
738+ }
739+
740+ return 0;
741+}
742+
743+static int
developer1bc2ce22023-03-25 00:47:41 +0800744+mt7996_tm_set(struct mt7996_dev *dev, u32 func_idx, u32 data)
745+{
746+ struct mt7996_tm_req req = {
747+ .rf_test = {
748+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
749+ .len = cpu_to_le16(sizeof(req.rf_test)),
750+ .action = RF_ACTION_SET,
751+ .op.rf.func_idx = func_idx,
752+ .op.rf.param.func_data = cpu_to_le32(data),
753+ },
754+ };
developer5f4e6c32023-12-20 06:12:53 +0800755+ bool wait = (data == RF_CMD(START_TX)) ? true : false;
developer1bc2ce22023-03-25 00:47:41 +0800756+
757+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_CTRL), &req,
developer5f4e6c32023-12-20 06:12:53 +0800758+ sizeof(req), wait);
developer1bc2ce22023-03-25 00:47:41 +0800759+}
760+
761+static int
762+mt7996_tm_get(struct mt7996_dev *dev, u32 func_idx, u32 data, u32 *result)
763+{
764+ struct mt7996_tm_req req = {
765+ .rf_test = {
766+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
767+ .len = cpu_to_le16(sizeof(req.rf_test)),
768+ .action = RF_ACTION_GET,
769+ .op.rf.func_idx = func_idx,
770+ .op.rf.param.func_data = cpu_to_le32(data),
771+ },
772+ };
773+ struct mt7996_tm_event *event;
774+ struct sk_buff *skb;
775+ int ret;
776+
777+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(TESTMODE_CTRL),
778+ &req, sizeof(req), true, &skb);
779+ if (ret)
780+ return ret;
781+
782+ event = (struct mt7996_tm_event *)skb->data;
783+ *result = event->result.payload_length;
784+
785+ dev_kfree_skb(skb);
786+
787+ return ret;
788+}
789+
790+static void
791+mt7996_tm_set_antenna(struct mt7996_phy *phy, u32 func_idx)
792+{
793+#define SPE_INDEX_MASK BIT(31)
developer064da3c2023-06-13 15:57:26 +0800794+#define TX_ANTENNA_MASK GENMASK(3, 0)
developer1bc2ce22023-03-25 00:47:41 +0800795+#define RX_ANTENNA_MASK GENMASK(20, 16) /* RX antenna mask at most 5 bit */
796+ struct mt7996_dev *dev = phy->dev;
797+ struct mt76_testmode_data *td = &phy->mt76->test;
developerde9ecce2023-05-22 11:17:16 +0800798+ u32 antenna_mask;
developer1bc2ce22023-03-25 00:47:41 +0800799+
developerde9ecce2023-05-22 11:17:16 +0800800+ if (!mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA))
developer1bc2ce22023-03-25 00:47:41 +0800801+ return;
802+
803+ if (func_idx == SET_ID(TX_PATH))
804+ antenna_mask = td->tx_spe_idx ? (SPE_INDEX_MASK | td->tx_spe_idx) :
developer064da3c2023-06-13 15:57:26 +0800805+ td->tx_antenna_mask & TX_ANTENNA_MASK;
developer1bc2ce22023-03-25 00:47:41 +0800806+ else if (func_idx == SET_ID(RX_PATH))
807+ antenna_mask = u32_encode_bits(td->tx_antenna_mask, RX_ANTENNA_MASK);
808+ else
809+ return;
810+
811+ mt7996_tm_set(dev, func_idx, antenna_mask);
812+}
813+
814+static void
815+mt7996_tm_set_mac_addr(struct mt7996_dev *dev, u8 *addr, u32 func_idx)
816+{
817+#define REMAIN_PART_TAG BIT(18)
818+ u32 own_mac_first = 0, own_mac_remain = 0;
819+ int len = sizeof(u32);
820+
821+ memcpy(&own_mac_first, addr, len);
822+ mt7996_tm_set(dev, func_idx, own_mac_first);
823+ /* Set the remain part of mac address */
824+ memcpy(&own_mac_remain, addr + len, ETH_ALEN - len);
825+ mt7996_tm_set(dev, func_idx | REMAIN_PART_TAG, own_mac_remain);
826+}
827+
828+static int
829+mt7996_tm_rf_switch_mode(struct mt7996_dev *dev, u32 op_mode)
830+{
831+ struct mt7996_tm_req req = {
832+ .rf_test = {
833+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
834+ .len = cpu_to_le16(sizeof(req.rf_test)),
835+ .action = RF_ACTION_SWITCH_TO_RF_TEST,
836+ .op.op_mode = cpu_to_le32(op_mode),
837+ },
838+ };
839+
840+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_CTRL), &req,
841+ sizeof(req), false);
842+}
843+
844+static void
845+mt7996_tm_init(struct mt7996_phy *phy, bool en)
846+{
developer1bc2ce22023-03-25 00:47:41 +0800847+ struct mt7996_dev *dev = phy->dev;
848+ u8 rf_test_mode = en ? RF_OPER_RF_TEST : RF_OPER_NORMAL;
849+
850+ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
851+ return;
852+
853+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(ATE_MODE), en);
854+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(SKU_POWER_LIMIT), !en);
developer1bc2ce22023-03-25 00:47:41 +0800855+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(BACKOFF_POWER_LIMIT), !en);
856+
857+ mt7996_tm_rf_switch_mode(dev, rf_test_mode);
858+
859+ mt7996_mcu_add_bss_info(phy, phy->monitor_vif, en);
860+ mt7996_mcu_add_sta(dev, phy->monitor_vif, NULL, en);
861+
862+ mt7996_tm_set(dev, SET_ID(BAND_IDX), phy->mt76->band_idx);
863+
864+ /* use firmware counter for RX stats */
865+ phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
866+}
867+
868+static void
869+mt7996_tm_update_channel(struct mt7996_phy *phy)
870+{
871+#define CHAN_FREQ_BW_80P80_TAG (SET_ID(CHAN_FREQ) | BIT(16))
872+ struct mt7996_dev *dev = phy->dev;
873+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
874+ struct ieee80211_channel *chan = chandef->chan;
875+ u8 width = chandef->width;
876+ static const u8 ch_band[] = {
877+ [NL80211_BAND_2GHZ] = 0,
878+ [NL80211_BAND_5GHZ] = 1,
879+ [NL80211_BAND_6GHZ] = 2,
880+ };
881+
882+ if (!chan || !chandef) {
883+ dev_info(dev->mt76.dev, "chandef not found, channel update failed!\n");
884+ return;
885+ }
886+
887+ /* system bw */
888+ mt7996_tm_set(dev, SET_ID(CBW), mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
889+
890+ if (width == NL80211_CHAN_WIDTH_80P80) {
891+ width = NL80211_CHAN_WIDTH_160;
892+ mt7996_tm_set(dev, CHAN_FREQ_BW_80P80_TAG, chandef->center_freq2 * 1000);
893+ }
894+
895+ /* TODO: define per-packet bw */
896+ /* per-packet bw */
897+ mt7996_tm_set(dev, SET_ID(DBW), mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
898+
899+ /* control channel selection index */
900+ mt7996_tm_set(dev, SET_ID(PRIMARY_CH), 0);
901+ mt7996_tm_set(dev, SET_ID(BAND), ch_band[chan->band]);
902+
903+ /* trigger switch channel calibration */
904+ mt7996_tm_set(dev, SET_ID(CHAN_FREQ), chandef->center_freq1 * 1000);
905+
906+ // TODO: update power limit table
907+}
908+
909+static void
910+mt7996_tm_tx_stop(struct mt76_phy *mphy)
911+{
912+ struct mt76_testmode_data *td = &mphy->test;
913+ struct mt7996_phy *phy = mphy->priv;
914+ struct mt7996_dev *dev = phy->dev;
915+
916+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
917+ td->tx_pending = 0;
918+}
919+
920+static void
921+mt7996_tm_set_tx_frames(struct mt7996_phy *phy, bool en)
922+{
923+#define FRAME_CONTROL 0x88
924+ struct mt76_testmode_data *td = &phy->mt76->test;
925+ struct mt7996_dev *dev = phy->dev;
926+
927+ //TODO: RU operation, replace mcs, nss, and ldpc
928+ if (en) {
929+ mt7996_tm_set(dev, SET_ID(MAC_HEADER), FRAME_CONTROL);
930+ mt7996_tm_set(dev, SET_ID(SEQ_CTRL), 0);
931+ mt7996_tm_set(dev, SET_ID(TX_COUNT), td->tx_count);
932+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
933+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
developerde9ecce2023-05-22 11:17:16 +0800934+
935+ if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER))
936+ mt7996_tm_set(dev, SET_ID(POWER), td->tx_power[0]);
937+
938+ if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_TIME)) {
939+ mt7996_tm_set(dev, SET_ID(TX_LEN), 0);
940+ mt7996_tm_set(dev, SET_ID(TX_TIME), td->tx_time);
941+ } else {
942+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
943+ mt7996_tm_set(dev, SET_ID(TX_TIME), 0);
944+ }
945+
developer1bc2ce22023-03-25 00:47:41 +0800946+ mt7996_tm_set_antenna(phy, SET_ID(TX_PATH));
developer064da3c2023-06-13 15:57:26 +0800947+ mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
developer1bc2ce22023-03-25 00:47:41 +0800948+ mt7996_tm_set(dev, SET_ID(STBC), td->tx_rate_stbc);
949+ mt7996_tm_set(dev, SET_ID(ENCODE_MODE), td->tx_rate_ldpc);
950+ mt7996_tm_set(dev, SET_ID(IBF_ENABLE), td->ibf);
951+ mt7996_tm_set(dev, SET_ID(EBF_ENABLE), td->ebf);
952+ mt7996_tm_set(dev, SET_ID(IPG), td->tx_ipg);
953+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
954+ mt7996_tm_set(dev, SET_ID(NSS), td->tx_rate_nss);
955+ mt7996_tm_set(dev, SET_ID(AID_OFFSET), 0);
956+ mt7996_tm_set(dev, SET_ID(PUNCTURE), td->tx_preamble_puncture);
957+
958+ mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
959+ mt7996_tm_set(dev, SET_ID(HW_TX_MODE), 0);
960+ mt7996_tm_update_channel(phy);
961+
962+ /* trigger firmware to start TX */
963+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_TX));
964+ } else {
965+ mt7996_tm_tx_stop(phy->mt76);
966+ }
967+}
968+
969+static int
970+mt7996_tm_rx_stats_user_ctrl(struct mt7996_phy *phy, u16 user_idx)
971+{
972+ struct mt7996_dev *dev = phy->dev;
973+ struct mt7996_tm_rx_req req = {
974+ .band = phy->mt76->band_idx,
975+ .user_ctrl = {
976+ .tag = cpu_to_le16(UNI_TM_RX_STAT_SET_USER_CTRL),
977+ .len = cpu_to_le16(sizeof(req.user_ctrl)),
978+ .band_idx = phy->mt76->band_idx,
979+ .user_idx = cpu_to_le16(user_idx),
980+ },
981+ };
982+
983+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_RX_STAT), &req,
984+ sizeof(req), false);
985+}
986+
987+static void
988+mt7996_tm_set_rx_frames(struct mt7996_phy *phy, bool en)
989+{
990+#define RX_MU_DISABLE 0xf800
991+ struct mt76_testmode_data *td = &phy->mt76->test;
992+ struct mt7996_dev *dev = phy->dev;
993+ int ret;
994+
995+ if (en) {
996+ ret = mt7996_tm_rx_stats_user_ctrl(phy, td->aid);
997+ if (ret) {
998+ dev_info(dev->mt76.dev, "Set RX stats user control failed!\n");
999+ return;
1000+ }
1001+
1002+ mt7996_tm_update_channel(phy);
1003+
1004+ if (td->tx_rate_mode >= MT76_TM_TX_MODE_HE_MU) {
1005+ if (td->aid)
1006+ ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), td->aid);
1007+ else
1008+ ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), RX_MU_DISABLE);
1009+ }
1010+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1011+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
1012+ mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
1013+ mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
1014+
1015+ mt7996_tm_set_mac_addr(dev, td->addr[1], SET_ID(SA));
1016+
1017+ /* trigger firmware to start RX */
1018+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_RX));
1019+ } else {
1020+ /* trigger firmware to stop RX */
1021+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
1022+ }
1023+}
1024+
1025+static void
1026+mt7996_tm_set_tx_cont(struct mt7996_phy *phy, bool en)
1027+{
1028+#define CONT_WAVE_MODE_OFDM 3
1029+ struct mt76_testmode_data *td = &phy->mt76->test;
1030+ struct mt7996_dev *dev = phy->dev;
1031+
1032+ if (en) {
1033+ mt7996_tm_update_channel(phy);
1034+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1035+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
1036+ /* fix payload is OFDM */
1037+ mt7996_tm_set(dev, SET_ID(CONT_WAVE_MODE), CONT_WAVE_MODE_OFDM);
1038+ mt7996_tm_set(dev, SET_ID(ANT_MASK), td->tx_antenna_mask);
1039+
1040+ /* trigger firmware to start CONT TX */
1041+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(CONT_WAVE));
1042+ } else {
1043+ /* trigger firmware to stop CONT TX */
1044+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
1045+ }
1046+}
1047+
1048+static void
1049+mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
1050+{
1051+ struct mt76_testmode_data *td = &phy->mt76->test;
1052+ struct mt7996_dev *dev = phy->dev;
developer1bc2ce22023-03-25 00:47:41 +08001053+
developer5f4e6c32023-12-20 06:12:53 +08001054+ if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) {
1055+ mt7996_tm_set(dev, SET_ID(FREQ_OFFSET), td->freq_offset);
1056+ mt7996_tm_set(dev, SET_ID(FREQ_OFFSET_C2), td->freq_offset);
1057+ }
developer1bc2ce22023-03-25 00:47:41 +08001058+ if (changed & BIT(TM_CHANGED_TXPOWER))
1059+ mt7996_tm_set(dev, SET_ID(POWER), td->tx_power[0]);
developerc2cfe0f2023-09-22 04:11:09 +08001060+ if (changed & BIT(TM_CHANGED_SKU_EN)) {
1061+ mt7996_tm_update_channel(phy);
1062+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(SKU_POWER_LIMIT), td->sku_en);
1063+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(BACKOFF_POWER_LIMIT), td->sku_en);
1064+ mt7996_mcu_set_txpower_sku(phy);
1065+ }
developer1bc2ce22023-03-25 00:47:41 +08001066+ if (changed & BIT(TM_CHANGED_TX_LENGTH)) {
1067+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
1068+ mt7996_tm_set(dev, SET_ID(TX_TIME), 0);
1069+ }
1070+ if (changed & BIT(TM_CHANGED_TX_TIME)) {
1071+ mt7996_tm_set(dev, SET_ID(TX_LEN), 0);
1072+ mt7996_tm_set(dev, SET_ID(TX_TIME), td->tx_time);
1073+ }
developerde9ecce2023-05-22 11:17:16 +08001074+ if (changed & BIT(TM_CHANGED_CFG)) {
1075+ u32 func_idx = td->cfg.enable ? SET_ID(CFG_ON) : SET_ID(CFG_OFF);
1076+
1077+ mt7996_tm_set(dev, func_idx, td->cfg.type);
1078+ }
developer1bc2ce22023-03-25 00:47:41 +08001079+}
1080+
1081+static int
1082+mt7996_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
1083+{
1084+ struct mt76_testmode_data *td = &mphy->test;
1085+ struct mt7996_phy *phy = mphy->priv;
1086+ enum mt76_testmode_state prev_state = td->state;
1087+
1088+ mphy->test.state = state;
1089+
1090+ if (prev_state != MT76_TM_STATE_OFF)
1091+ mt7996_tm_set(phy->dev, SET_ID(BAND_IDX), mphy->band_idx);
1092+
1093+ if (prev_state == MT76_TM_STATE_TX_FRAMES ||
1094+ state == MT76_TM_STATE_TX_FRAMES)
1095+ mt7996_tm_set_tx_frames(phy, state == MT76_TM_STATE_TX_FRAMES);
1096+ else if (prev_state == MT76_TM_STATE_RX_FRAMES ||
1097+ state == MT76_TM_STATE_RX_FRAMES)
1098+ mt7996_tm_set_rx_frames(phy, state == MT76_TM_STATE_RX_FRAMES);
1099+ else if (prev_state == MT76_TM_STATE_TX_CONT ||
1100+ state == MT76_TM_STATE_TX_CONT)
1101+ mt7996_tm_set_tx_cont(phy, state == MT76_TM_STATE_TX_CONT);
1102+ else if (prev_state == MT76_TM_STATE_OFF ||
1103+ state == MT76_TM_STATE_OFF)
1104+ mt7996_tm_init(phy, !(state == MT76_TM_STATE_OFF));
1105+
1106+ if ((state == MT76_TM_STATE_IDLE &&
1107+ prev_state == MT76_TM_STATE_OFF) ||
1108+ (state == MT76_TM_STATE_OFF &&
1109+ prev_state == MT76_TM_STATE_IDLE)) {
1110+ u32 changed = 0;
developer064da3c2023-06-13 15:57:26 +08001111+ int i, ret;
developer1bc2ce22023-03-25 00:47:41 +08001112+
1113+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
1114+ u16 cur = tm_change_map[i];
1115+
developerde9ecce2023-05-22 11:17:16 +08001116+ if (mt76_testmode_param_present(td, cur))
developer1bc2ce22023-03-25 00:47:41 +08001117+ changed |= BIT(i);
1118+ }
1119+
developer064da3c2023-06-13 15:57:26 +08001120+ ret = mt7996_tm_check_antenna(phy);
1121+ if (ret)
1122+ return ret;
1123+
developer1bc2ce22023-03-25 00:47:41 +08001124+ mt7996_tm_update_params(phy, changed);
1125+ }
1126+
1127+ return 0;
1128+}
1129+
1130+static int
1131+mt7996_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
1132+ enum mt76_testmode_state new_state)
1133+{
1134+ struct mt76_testmode_data *td = &mphy->test;
1135+ struct mt7996_phy *phy = mphy->priv;
1136+ struct mt7996_dev *dev = phy->dev;
developer064da3c2023-06-13 15:57:26 +08001137+ u32 changed = 0;
1138+ int i, ret;
developer1bc2ce22023-03-25 00:47:41 +08001139+
1140+ BUILD_BUG_ON(NUM_TM_CHANGED >= 32);
1141+
1142+ if (new_state == MT76_TM_STATE_OFF ||
1143+ td->state == MT76_TM_STATE_OFF)
1144+ return 0;
1145+
developer064da3c2023-06-13 15:57:26 +08001146+ ret = mt7996_tm_check_antenna(phy);
1147+ if (ret)
1148+ return ret;
developer1bc2ce22023-03-25 00:47:41 +08001149+
1150+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
1151+ if (tb[tm_change_map[i]])
1152+ changed |= BIT(i);
1153+ }
1154+
1155+ mt7996_tm_set(dev, SET_ID(BAND_IDX), mphy->band_idx);
1156+ mt7996_tm_update_params(phy, changed);
1157+
1158+ return 0;
1159+}
1160+
1161+static int
1162+mt7996_tm_get_rx_stats(struct mt7996_phy *phy)
1163+{
1164+ struct mt7996_dev *dev = phy->dev;
1165+ struct mt7996_tm_rx_req req = {
1166+ .band = phy->mt76->band_idx,
1167+ .rx_stat_all = {
1168+ .tag = cpu_to_le16(UNI_TM_RX_STAT_GET_ALL_V2),
1169+ .len = cpu_to_le16(sizeof(req.rx_stat_all)),
1170+ .band_idx = phy->mt76->band_idx,
1171+ },
1172+ };
1173+ struct mt76_testmode_data *td = &phy->mt76->test;
1174+ struct mt7996_tm_rx_event *rx_stats;
1175+ struct mt7996_tm_rx_event_stat_all *rx_stats_all;
1176+ struct sk_buff *skb;
1177+ enum mt76_rxq_id qid;
1178+ int i, ret = 0;
1179+ u32 mac_rx_mdrdy_cnt;
1180+ u16 mac_rx_len_mismatch, fcs_err_count;
1181+
1182+ if (td->state != MT76_TM_STATE_RX_FRAMES)
1183+ return 0;
1184+
1185+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(TESTMODE_RX_STAT),
1186+ &req, sizeof(req), true, &skb);
1187+
1188+ if (ret)
1189+ return ret;
1190+
1191+ rx_stats = (struct mt7996_tm_rx_event *)skb->data;
1192+ rx_stats_all = &rx_stats->rx_stat_all;
1193+
1194+ phy->test.last_freq_offset = le32_to_cpu(rx_stats_all->user_info[0].freq_offset);
1195+ phy->test.last_snr = le32_to_cpu(rx_stats_all->user_info[0].snr);
1196+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) {
1197+ phy->test.last_rcpi[i] = le16_to_cpu(rx_stats_all->rxv_info[i].rcpi);
developerc2cfe0f2023-09-22 04:11:09 +08001198+ phy->test.last_rssi[i] = le16_to_cpu(rx_stats_all->rxv_info[i].rssi);
developer1bc2ce22023-03-25 00:47:41 +08001199+ phy->test.last_ib_rssi[i] = rx_stats_all->fagc[i].ib_rssi;
1200+ phy->test.last_wb_rssi[i] = rx_stats_all->fagc[i].wb_rssi;
1201+ }
1202+
1203+ if (phy->mt76->band_idx == 2)
1204+ qid = MT_RXQ_BAND2;
1205+ else if (phy->mt76->band_idx == 1)
1206+ qid = MT_RXQ_BAND1;
1207+ else
1208+ qid = MT_RXQ_MAIN;
1209+
1210+ fcs_err_count = le16_to_cpu(rx_stats_all->band_info.mac_rx_fcs_err_cnt);
1211+ mac_rx_len_mismatch = le16_to_cpu(rx_stats_all->band_info.mac_rx_len_mismatch);
1212+ mac_rx_mdrdy_cnt = le32_to_cpu(rx_stats_all->band_info.mac_rx_mdrdy_cnt);
1213+ td->rx_stats.packets[qid] += mac_rx_mdrdy_cnt;
1214+ td->rx_stats.packets[qid] += fcs_err_count;
1215+ td->rx_stats.fcs_error[qid] += fcs_err_count;
1216+ td->rx_stats.len_mismatch += mac_rx_len_mismatch;
1217+
1218+ dev_kfree_skb(skb);
1219+
1220+ return ret;
1221+}
1222+
1223+static void
developerde9ecce2023-05-22 11:17:16 +08001224+mt7996_tm_reset_trx_stats(struct mt76_phy *mphy)
developer1bc2ce22023-03-25 00:47:41 +08001225+{
1226+ struct mt7996_phy *phy = mphy->priv;
1227+ struct mt7996_dev *dev = phy->dev;
1228+
1229+ memset(&mphy->test.rx_stats, 0, sizeof(mphy->test.rx_stats));
1230+ mt7996_tm_set(dev, SET_ID(TRX_COUNTER_RESET), 0);
1231+}
1232+
1233+static int
1234+mt7996_tm_get_tx_stats(struct mt7996_phy *phy)
1235+{
1236+ struct mt7996_dev *dev = phy->dev;
1237+ struct mt76_testmode_data *td = &phy->mt76->test;
1238+ int ret;
1239+
1240+ if (td->state != MT76_TM_STATE_TX_FRAMES)
1241+ return 0;
1242+
1243+ ret = mt7996_tm_get(dev, GET_ID(TXED_COUNT), 0, &td->tx_done);
1244+ if (ret)
1245+ return ret;
1246+
1247+ td->tx_pending = td->tx_count - td->tx_done;
1248+
1249+ return ret;
1250+}
1251+
1252+static int
1253+mt7996_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
1254+{
1255+ struct mt7996_phy *phy = mphy->priv;
1256+ void *rx, *rssi;
1257+ int i;
1258+
1259+ mt7996_tm_set(phy->dev, SET_ID(BAND_IDX), mphy->band_idx);
1260+ mt7996_tm_get_rx_stats(phy);
1261+ mt7996_tm_get_tx_stats(phy);
1262+
1263+ rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);
1264+ if (!rx)
1265+ return -ENOMEM;
1266+
1267+ if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset))
1268+ return -ENOMEM;
1269+
1270+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
1271+ if (!rssi)
1272+ return -ENOMEM;
1273+
1274+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++)
1275+ if (nla_put_u8(msg, i, phy->test.last_rcpi[i]))
1276+ return -ENOMEM;
1277+
1278+ nla_nest_end(msg, rssi);
1279+
developerc2cfe0f2023-09-22 04:11:09 +08001280+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RSSI);
1281+ if (!rssi)
1282+ return -ENOMEM;
1283+
1284+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rssi); i++)
1285+ if (nla_put_s8(msg, i, phy->test.last_rssi[i]))
1286+ return -ENOMEM;
1287+
1288+ nla_nest_end(msg, rssi);
1289+
developer1bc2ce22023-03-25 00:47:41 +08001290+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
1291+ if (!rssi)
1292+ return -ENOMEM;
1293+
1294+ for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++)
1295+ if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i]))
1296+ return -ENOMEM;
1297+
1298+ nla_nest_end(msg, rssi);
1299+
1300+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
1301+ if (!rssi)
1302+ return -ENOMEM;
1303+
1304+ for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++)
1305+ if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i]))
1306+ return -ENOMEM;
1307+
1308+ nla_nest_end(msg, rssi);
1309+
1310+ if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, phy->test.last_snr))
1311+ return -ENOMEM;
1312+
1313+ nla_nest_end(msg, rx);
1314+
1315+ return 0;
1316+}
1317+
developer5f4e6c32023-12-20 06:12:53 +08001318+static int
1319+mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
1320+{
1321+ struct mt7996_mcu_eeprom_info req = {
1322+ .tag = cpu_to_le16(UNI_EFUSE_ACCESS),
1323+ .len = cpu_to_le16(sizeof(req) - 4),
1324+ };
1325+ u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
1326+ int i, ret = -EINVAL;
1327+
1328+ /* prevent from damaging chip id in efuse */
1329+ if (mt76_chip(&dev->mt76) != get_unaligned_le16(eeprom))
1330+ goto out;
1331+
1332+ for (i = 0; i < MT7996_EEPROM_SIZE; i += MT76_TM_EEPROM_BLOCK_SIZE) {
1333+ req.addr = cpu_to_le32(i);
1334+ memcpy(req.data, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
1335+
1336+ ret = mt7996_mcu_get_eeprom(dev, i, read_buf);
1337+ if (ret < 0)
1338+ return ret;
1339+
1340+ if (!memcmp(req.data, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
1341+ continue;
1342+
1343+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
1344+ &req, sizeof(req), true);
1345+ if (ret)
1346+ return ret;
1347+ }
1348+
1349+out:
1350+ return ret;
1351+}
1352+
1353+static int
1354+mt7996_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action)
1355+{
1356+ struct mt7996_phy *phy = mphy->priv;
1357+ struct mt7996_dev *dev = phy->dev;
1358+ u8 *eeprom = dev->mt76.eeprom.data;
1359+ int ret = 0;
1360+
1361+ if (offset >= MT7996_EEPROM_SIZE)
1362+ return -EINVAL;
1363+
1364+ switch (action) {
1365+ case MT76_TM_EEPROM_ACTION_UPDATE_DATA:
1366+ memcpy(eeprom + offset, val, MT76_TM_EEPROM_BLOCK_SIZE);
1367+ break;
1368+ case MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE:
1369+ ret = mt7996_mcu_set_eeprom(dev);
1370+ break;
1371+ case MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE:
1372+ ret = mt7996_tm_write_back_to_efuse(dev);
1373+ break;
1374+ default:
1375+ break;
1376+ }
1377+
1378+ return ret;
1379+}
1380+
developer1bc2ce22023-03-25 00:47:41 +08001381+const struct mt76_testmode_ops mt7996_testmode_ops = {
1382+ .set_state = mt7996_tm_set_state,
1383+ .set_params = mt7996_tm_set_params,
1384+ .dump_stats = mt7996_tm_dump_stats,
developerde9ecce2023-05-22 11:17:16 +08001385+ .reset_rx_stats = mt7996_tm_reset_trx_stats,
developer1bc2ce22023-03-25 00:47:41 +08001386+ .tx_stop = mt7996_tm_tx_stop,
developer5f4e6c32023-12-20 06:12:53 +08001387+ .set_eeprom = mt7996_tm_set_eeprom,
developer1bc2ce22023-03-25 00:47:41 +08001388+};
1389diff --git a/mt7996/testmode.h b/mt7996/testmode.h
1390new file mode 100644
developer5f4e6c32023-12-20 06:12:53 +08001391index 00000000..319ef257
developer1bc2ce22023-03-25 00:47:41 +08001392--- /dev/null
1393+++ b/mt7996/testmode.h
developer5f4e6c32023-12-20 06:12:53 +08001394@@ -0,0 +1,299 @@
developer1bc2ce22023-03-25 00:47:41 +08001395+/* SPDX-License-Identifier: ISC */
1396+/* Copyright (C) 2020 MediaTek Inc. */
1397+
1398+#ifndef __MT7996_TESTMODE_H
1399+#define __MT7996_TESTMODE_H
1400+
1401+enum {
1402+ TM_CBW_20MHZ,
1403+ TM_CBW_40MHZ,
1404+ TM_CBW_80MHZ,
1405+ TM_CBW_10MHZ,
1406+ TM_CBW_5MHZ,
1407+ TM_CBW_160MHZ,
1408+ TM_CBW_8080MHZ,
1409+ TM_CBW_320MHZ = 12,
1410+};
1411+
1412+/* BW defined in FW hal_cal_flow_rom.h */
1413+enum {
1414+ FW_CDBW_20MHZ,
1415+ FW_CDBW_40MHZ,
1416+ FW_CDBW_80MHZ,
1417+ FW_CDBW_160MHZ,
1418+ FW_CDBW_320MHZ,
1419+ FW_CDBW_5MHZ,
1420+ FW_CDBW_10MHZ,
1421+ FW_CDBW_8080MHZ,
1422+};
1423+
1424+enum bw_mapping_method {
1425+ BW_MAP_NL_TO_FW,
1426+ BW_MAP_NL_TO_TM,
1427+
1428+ NUM_BW_MAP,
1429+};
1430+
1431+struct mt7996_tm_rf_test {
1432+ __le16 tag;
1433+ __le16 len;
1434+
1435+ u8 action;
1436+ u8 icap_len;
1437+ u8 _rsv[2];
1438+ union {
1439+ __le32 op_mode;
1440+ __le32 freq;
1441+
1442+ struct {
1443+ __le32 func_idx;
1444+ union {
1445+ __le32 func_data;
1446+ __le32 cal_dump;
1447+
1448+ u8 _pad[80];
1449+ } param;
1450+ } rf;
1451+ } op;
1452+} __packed;
1453+
1454+struct mt7996_tm_req {
1455+ u8 _rsv[4];
1456+
1457+ struct mt7996_tm_rf_test rf_test;
1458+} __packed;
1459+
1460+struct mt7996_tm_rf_test_result {
1461+ __le32 func_idx;
1462+ __le32 payload_length;
1463+ u8 event[0];
1464+};
1465+
1466+struct mt7996_tm_event {
1467+ u8 _rsv[4];
1468+
1469+ __le16 tag;
1470+ __le16 len;
1471+ struct mt7996_tm_rf_test_result result;
1472+} __packed;
1473+
1474+enum {
1475+ RF_ACTION_SWITCH_TO_RF_TEST,
1476+ RF_ACTION_IN_RF_TEST,
1477+ RF_ACTION_SET = 3,
1478+ RF_ACTION_GET,
1479+};
1480+
1481+enum {
1482+ RF_OPER_NORMAL,
1483+ RF_OPER_RF_TEST,
1484+ RF_OPER_ICAP,
1485+ RF_OPER_ICAP_OVERLAP,
1486+ RF_OPER_WIFI_SPECTRUM,
1487+};
1488+
1489+enum {
1490+ UNI_RF_TEST_CTRL,
1491+};
1492+
1493+#define RF_CMD(cmd) RF_TEST_CMD_##cmd
1494+
1495+enum {
1496+ RF_TEST_CMD_STOP_TEST = 0,
1497+ RF_TEST_CMD_START_TX = 1,
1498+ RF_TEST_CMD_START_RX = 2,
1499+ RF_TEST_CMD_CONT_WAVE = 10,
1500+ RF_TEST_CMD_TX_COMMIT = 18,
1501+ RF_TEST_CMD_RX_COMMIT = 19,
1502+};
1503+
1504+#define SET_ID(id) RF_TEST_ID_SET_##id
1505+#define GET_ID(id) RF_TEST_ID_GET_##id
1506+
1507+enum {
1508+ RF_TEST_ID_SET_COMMAND = 1,
1509+ RF_TEST_ID_SET_POWER = 2,
1510+ RF_TEST_ID_SET_TX_RATE = 3,
1511+ RF_TEST_ID_SET_TX_MODE = 4,
1512+ RF_TEST_ID_SET_TX_LEN = 6,
1513+ RF_TEST_ID_SET_TX_COUNT = 7,
1514+ RF_TEST_ID_SET_IPG = 8,
1515+ RF_TEST_ID_SET_GI = 16,
1516+ RF_TEST_ID_SET_STBC = 17,
1517+ RF_TEST_ID_SET_CHAN_FREQ = 18,
1518+ RF_TEST_ID_GET_TXED_COUNT = 32,
1519+ RF_TEST_ID_SET_CONT_WAVE_MODE = 65,
1520+ RF_TEST_ID_SET_DA = 68,
1521+ RF_TEST_ID_SET_SA = 69,
1522+ RF_TEST_ID_SET_CBW = 71,
1523+ RF_TEST_ID_SET_DBW = 72,
1524+ RF_TEST_ID_SET_PRIMARY_CH = 73,
1525+ RF_TEST_ID_SET_ENCODE_MODE = 74,
1526+ RF_TEST_ID_SET_BAND = 90,
1527+ RF_TEST_ID_SET_TRX_COUNTER_RESET = 91,
1528+ RF_TEST_ID_SET_MAC_HEADER = 101,
1529+ RF_TEST_ID_SET_SEQ_CTRL = 102,
developerde9ecce2023-05-22 11:17:16 +08001530+ RF_TEST_ID_SET_PAYLOAD = 103,
developer1bc2ce22023-03-25 00:47:41 +08001531+ RF_TEST_ID_SET_BAND_IDX = 104,
1532+ RF_TEST_ID_SET_RX_PATH = 106,
1533+ RF_TEST_ID_SET_FREQ_OFFSET = 107,
1534+ RF_TEST_ID_GET_FREQ_OFFSET = 108,
1535+ RF_TEST_ID_SET_TX_PATH = 113,
1536+ RF_TEST_ID_SET_NSS = 114,
1537+ RF_TEST_ID_SET_ANT_MASK = 115,
1538+ RF_TEST_ID_SET_IBF_ENABLE = 126,
1539+ RF_TEST_ID_SET_EBF_ENABLE = 127,
1540+ RF_TEST_ID_GET_TX_POWER = 136,
1541+ RF_TEST_ID_SET_RX_MU_AID = 157,
1542+ RF_TEST_ID_SET_HW_TX_MODE = 167,
1543+ RF_TEST_ID_SET_PUNCTURE = 168,
developer5f4e6c32023-12-20 06:12:53 +08001544+ RF_TEST_ID_SET_FREQ_OFFSET_C2 = 171,
1545+ RF_TEST_ID_GET_FREQ_OFFSET_C2 = 172,
developerde9ecce2023-05-22 11:17:16 +08001546+ RF_TEST_ID_SET_CFG_ON = 176,
1547+ RF_TEST_ID_SET_CFG_OFF = 177,
developer1bc2ce22023-03-25 00:47:41 +08001548+ RF_TEST_ID_SET_BSSID = 189,
1549+ RF_TEST_ID_SET_TX_TIME = 190,
1550+ RF_TEST_ID_SET_MAX_PE = 191,
1551+ RF_TEST_ID_SET_AID_OFFSET = 204,
1552+};
1553+
developerc2cfe0f2023-09-22 04:11:09 +08001554+#define POWER_CTRL(type) UNI_TXPOWER_##type##_CTRL
1555+
developer1bc2ce22023-03-25 00:47:41 +08001556+struct mt7996_tm_rx_stat_user_ctrl {
1557+ __le16 tag;
1558+ __le16 len;
1559+
1560+ u8 band_idx;
1561+ u8 rsv;
1562+ __le16 user_idx;
1563+} __packed;
1564+
1565+struct mt7996_tm_rx_stat_all {
1566+ __le16 tag;
1567+ __le16 len;
1568+
1569+ u8 band_idx;
1570+ u8 rsv[3];
1571+} __packed;
1572+
1573+struct mt7996_tm_rx_req {
1574+ u8 band;
1575+ u8 _rsv[3];
1576+
1577+ union {
1578+ struct mt7996_tm_rx_stat_user_ctrl user_ctrl;
1579+ struct mt7996_tm_rx_stat_all rx_stat_all;
1580+ };
1581+} __packed;
1582+
1583+enum {
1584+ UNI_TM_RX_STAT_SET_USER_CTRL = 7,
1585+ UNI_TM_RX_STAT_GET_ALL_V2 = 9,
1586+};
1587+
1588+struct rx_band_info {
1589+ /* mac part */
1590+ __le16 mac_rx_fcs_err_cnt;
1591+ __le16 mac_rx_len_mismatch;
1592+ __le16 mac_rx_fcs_ok_cnt;
1593+ u8 rsv1[2];
1594+ __le32 mac_rx_mdrdy_cnt;
1595+
1596+ /* phy part */
1597+ __le16 phy_rx_fcs_err_cnt_cck;
1598+ __le16 phy_rx_fcs_err_cnt_ofdm;
1599+ __le16 phy_rx_pd_cck;
1600+ __le16 phy_rx_pd_ofdm;
1601+ __le16 phy_rx_sig_err_cck;
1602+ __le16 phy_rx_sfd_err_cck;
1603+ __le16 phy_rx_sig_err_ofdm;
1604+ __le16 phy_rx_tag_err_ofdm;
1605+ __le16 phy_rx_mdrdy_cnt_cck;
1606+ __le16 phy_rx_mdrdy_cnt_ofdm;
1607+} __packed;
1608+
1609+struct rx_band_info_ext {
1610+ /* mac part */
1611+ __le32 mac_rx_mpdu_cnt;
1612+
1613+ /* phy part */
1614+ u8 rsv[4];
1615+} __packed;
1616+
1617+struct rx_common_info {
1618+ __le16 rx_fifo_full;
1619+ u8 rsv[2];
1620+ __le32 aci_hit_low;
1621+ __le32 aci_hit_high;
1622+} __packed;
1623+
1624+struct rx_common_info_ext {
1625+ __le32 driver_rx_count;
1626+ __le32 sinr;
1627+ __le32 mu_pkt_count;
1628+
1629+ /* mac part */
1630+ u8 _rsv[4];
1631+
1632+ /* phy part */
1633+ u8 sig_mcs;
1634+ u8 rsv[3];
1635+} __packed;
1636+
1637+struct rx_rxv_info {
1638+ __le16 rcpi;
1639+ s16 rssi;
1640+ s16 snr;
1641+ s16 adc_rssi;
1642+} __packed;
1643+
1644+struct rx_rssi_info {
1645+ s8 ib_rssi;
1646+ s8 wb_rssi;
1647+ u8 rsv[2];
1648+} __packed;
1649+
1650+struct rx_user_info {
1651+ s32 freq_offset;
1652+ s32 snr;
1653+ __le32 fcs_err_count;
1654+} __packed;
1655+
1656+struct rx_user_info_ext {
1657+ s8 ne_var_db_all_user;
1658+ u8 rsv[3];
1659+} __packed;
1660+
1661+#define MAX_ANTENNA_NUM 8
1662+#define MAX_USER_NUM 16
1663+
1664+struct mt7996_tm_rx_event_stat_all {
1665+ __le16 tag;
1666+ __le16 len;
1667+
1668+ struct rx_band_info band_info;
1669+ struct rx_band_info_ext band_info_ext;
1670+ struct rx_common_info common_info;
1671+ struct rx_common_info_ext common_info_ext;
1672+
1673+ /* RXV info */
1674+ struct rx_rxv_info rxv_info[MAX_ANTENNA_NUM];
1675+
1676+ /* RSSI info */
1677+ struct rx_rssi_info fagc[MAX_ANTENNA_NUM];
1678+ struct rx_rssi_info inst[MAX_ANTENNA_NUM];
1679+
1680+ /* User info */
1681+ struct rx_user_info user_info[MAX_USER_NUM];
1682+ struct rx_user_info_ext user_info_ext[MAX_USER_NUM];
1683+} __packed;
1684+
1685+struct mt7996_tm_rx_event {
1686+ u8 _rsv[4];
1687+
1688+ union {
1689+ struct mt7996_tm_rx_event_stat_all rx_stat_all;
1690+ };
1691+} __packed;
1692+
1693+#endif
1694diff --git a/testmode.c b/testmode.c
developer5f4e6c32023-12-20 06:12:53 +08001695index 5c93aa6a..db2cc255 100644
developer1bc2ce22023-03-25 00:47:41 +08001696--- a/testmode.c
1697+++ b/testmode.c
developerc2cfe0f2023-09-22 04:11:09 +08001698@@ -2,11 +2,13 @@
developer1bc2ce22023-03-25 00:47:41 +08001699 /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
1700
1701 #include <linux/random.h>
1702+#include "mt76_connac.h"
1703 #include "mt76.h"
1704
1705 const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
developerc2cfe0f2023-09-22 04:11:09 +08001706 [MT76_TM_ATTR_RESET] = { .type = NLA_FLAG },
1707 [MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
1708+ [MT76_TM_ATTR_SKU_EN] = { .type = NLA_U8 },
1709 [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
1710 [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
1711 [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
1712@@ -82,6 +84,11 @@ mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode)
developer1bc2ce22023-03-25 00:47:41 +08001713 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991)
1714 return IEEE80211_MAX_MPDU_LEN_VHT_7991;
1715 return IEEE80211_MAX_MPDU_LEN_VHT_11454;
1716+ case MT76_TM_TX_MODE_EHT_SU:
1717+ case MT76_TM_TX_MODE_EHT_TRIG:
1718+ case MT76_TM_TX_MODE_EHT_MU:
1719+ /* TODO: check the limit */
1720+ return UINT_MAX;
1721 case MT76_TM_TX_MODE_CCK:
1722 case MT76_TM_TX_MODE_OFDM:
1723 default:
developerc2cfe0f2023-09-22 04:11:09 +08001724@@ -183,6 +190,9 @@ mt76_testmode_tx_init(struct mt76_phy *phy)
developer1bc2ce22023-03-25 00:47:41 +08001725 u8 max_nss = hweight8(phy->antenna_mask);
1726 int ret;
1727
1728+ if (is_mt7996(phy->dev))
1729+ return 0;
1730+
1731 ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len);
1732 if (ret)
1733 return ret;
developerc2cfe0f2023-09-22 04:11:09 +08001734@@ -275,7 +285,9 @@ mt76_testmode_tx_start(struct mt76_phy *phy)
developer1bc2ce22023-03-25 00:47:41 +08001735 td->tx_queued = 0;
1736 td->tx_done = 0;
1737 td->tx_pending = td->tx_count;
1738- mt76_worker_schedule(&dev->tx_worker);
1739+
1740+ if (!is_mt7996(dev))
1741+ mt76_worker_schedule(&dev->tx_worker);
1742 }
1743
1744 static void
developerc2cfe0f2023-09-22 04:11:09 +08001745@@ -284,6 +296,11 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
developer1bc2ce22023-03-25 00:47:41 +08001746 struct mt76_testmode_data *td = &phy->test;
1747 struct mt76_dev *dev = phy->dev;
1748
1749+ if (is_mt7996(dev) && dev->test_ops->tx_stop) {
1750+ dev->test_ops->tx_stop(phy);
1751+ return;
1752+ }
1753+
1754 mt76_worker_disable(&dev->tx_worker);
1755
1756 td->tx_pending = 0;
developerc2cfe0f2023-09-22 04:11:09 +08001757@@ -296,22 +313,11 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
developerde9ecce2023-05-22 11:17:16 +08001758 mt76_testmode_free_skb(phy);
1759 }
1760
1761-static inline void
1762-mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx)
1763-{
1764- td->param_set[idx / 32] |= BIT(idx % 32);
1765-}
1766-
1767-static inline bool
1768-mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx)
1769-{
1770- return td->param_set[idx / 32] & BIT(idx % 32);
1771-}
1772-
1773 static void
developer1bc2ce22023-03-25 00:47:41 +08001774 mt76_testmode_init_defaults(struct mt76_phy *phy)
1775 {
1776 struct mt76_testmode_data *td = &phy->test;
1777+ u8 addr[ETH_ALEN] = {phy->band_idx, 0x11, 0x22, 0xaa, 0xbb, 0xcc};
1778
1779 if (td->tx_mpdu_len > 0)
1780 return;
developerc2cfe0f2023-09-22 04:11:09 +08001781@@ -319,11 +325,18 @@ mt76_testmode_init_defaults(struct mt76_phy *phy)
developer1bc2ce22023-03-25 00:47:41 +08001782 td->tx_mpdu_len = 1024;
1783 td->tx_count = 1;
1784 td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;
1785+ td->tx_rate_idx = 7;
1786 td->tx_rate_nss = 1;
1787+ /* 0xffff for OFDMA no puncture */
1788+ td->tx_preamble_puncture = ~(td->tx_preamble_puncture & 0);
1789+ td->tx_ipg = 50;
1790
1791- memcpy(td->addr[0], phy->macaddr, ETH_ALEN);
1792- memcpy(td->addr[1], phy->macaddr, ETH_ALEN);
1793- memcpy(td->addr[2], phy->macaddr, ETH_ALEN);
developerc2cfe0f2023-09-22 04:11:09 +08001794+ /* rx stat user config */
1795+ td->aid = 1;
1796+
developer1bc2ce22023-03-25 00:47:41 +08001797+ memcpy(td->addr[0], addr, ETH_ALEN);
1798+ memcpy(td->addr[1], addr, ETH_ALEN);
1799+ memcpy(td->addr[2], addr, ETH_ALEN);
1800 }
1801
1802 static int
developerc2cfe0f2023-09-22 04:11:09 +08001803@@ -353,7 +366,7 @@ __mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state)
developer1bc2ce22023-03-25 00:47:41 +08001804 if (state == MT76_TM_STATE_TX_FRAMES)
1805 mt76_testmode_tx_start(phy);
1806 else if (state == MT76_TM_STATE_RX_FRAMES) {
1807- memset(&phy->test.rx_stats, 0, sizeof(phy->test.rx_stats));
1808+ dev->test_ops->reset_rx_stats(phy);
1809 }
1810
1811 phy->test.state = state;
developer5f4e6c32023-12-20 06:12:53 +08001812@@ -404,6 +417,44 @@ mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max)
1813 return 0;
1814 }
1815
1816+static int
1817+mt76_testmode_set_eeprom(struct mt76_phy *phy, struct nlattr **tb)
1818+{
1819+ struct mt76_dev *dev = phy->dev;
1820+ u8 action, val[MT76_TM_EEPROM_BLOCK_SIZE];
1821+ u32 offset = 0;
1822+ int err = -EINVAL;
1823+
1824+ if (!dev->test_ops->set_eeprom)
1825+ return -EOPNOTSUPP;
1826+
1827+ if (mt76_tm_get_u8(tb[MT76_TM_ATTR_EEPROM_ACTION], &action,
1828+ 0, MT76_TM_EEPROM_ACTION_MAX))
1829+ goto out;
1830+
1831+ if (tb[MT76_TM_ATTR_EEPROM_OFFSET]) {
1832+ struct nlattr *cur;
1833+ int rem, idx = 0;
1834+
1835+ offset = nla_get_u32(tb[MT76_TM_ATTR_EEPROM_OFFSET]);
1836+ if (!!(offset % MT76_TM_EEPROM_BLOCK_SIZE) ||
1837+ !tb[MT76_TM_ATTR_EEPROM_VAL])
1838+ goto out;
1839+
1840+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_EEPROM_VAL], rem) {
1841+ if (nla_len(cur) != 1 || idx >= ARRAY_SIZE(val))
1842+ goto out;
1843+
1844+ val[idx++] = nla_get_u8(cur);
1845+ }
1846+ }
1847+
1848+ err = dev->test_ops->set_eeprom(phy, offset, val, action);
1849+
1850+out:
1851+ return err;
1852+}
1853+
1854 int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1855 void *data, int len)
1856 {
1857@@ -427,6 +478,11 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1858
1859 mutex_lock(&dev->mutex);
1860
1861+ if (tb[MT76_TM_ATTR_EEPROM_ACTION]) {
1862+ err = mt76_testmode_set_eeprom(phy, tb);
1863+ goto out;
1864+ }
1865+
1866 if (tb[MT76_TM_ATTR_RESET]) {
1867 mt76_testmode_set_state(phy, MT76_TM_STATE_OFF);
1868 memset(td, 0, sizeof(*td));
1869@@ -434,6 +490,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developerc2cfe0f2023-09-22 04:11:09 +08001870
1871 mt76_testmode_init_defaults(phy);
1872
1873+ if (tb[MT76_TM_ATTR_SKU_EN])
1874+ td->sku_en = nla_get_u8(tb[MT76_TM_ATTR_SKU_EN]);
1875+
1876 if (tb[MT76_TM_ATTR_TX_COUNT])
1877 td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]);
1878
developer5f4e6c32023-12-20 06:12:53 +08001879@@ -454,7 +513,8 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developer1bc2ce22023-03-25 00:47:41 +08001880 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE],
1881 &td->tx_duty_cycle, 0, 99) ||
1882 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
1883- &td->tx_power_control, 0, 1))
1884+ &td->tx_power_control, 0, 1) ||
1885+ mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16))
1886 goto out;
1887
1888 if (tb[MT76_TM_ATTR_TX_LENGTH]) {
developer5f4e6c32023-12-20 06:12:53 +08001889@@ -494,7 +554,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developer1bc2ce22023-03-25 00:47:41 +08001890 idx >= ARRAY_SIZE(td->tx_power))
1891 goto out;
1892
1893- td->tx_power[idx++] = nla_get_u8(cur);
1894+ err = mt76_tm_get_u8(cur, &td->tx_power[idx++], 0, 63);
1895+ if (err)
1896+ return err;
1897 }
1898 }
1899
developer5f4e6c32023-12-20 06:12:53 +08001900@@ -512,6 +574,22 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developerde9ecce2023-05-22 11:17:16 +08001901 }
1902 }
1903
1904+ if (tb[MT76_TM_ATTR_CFG]) {
1905+ struct nlattr *cur;
1906+ int rem, idx = 0;
1907+
1908+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_CFG], rem) {
1909+ if (nla_len(cur) != 1 || idx >= 2)
1910+ goto out;
1911+
1912+ if (idx == 0)
1913+ td->cfg.type = nla_get_u8(cur);
1914+ else
1915+ td->cfg.enable = nla_get_u8(cur);
1916+ idx++;
1917+ }
1918+ }
1919+
1920 if (dev->test_ops->set_params) {
1921 err = dev->test_ops->set_params(phy, tb, state);
1922 if (err)
developer5f4e6c32023-12-20 06:12:53 +08001923@@ -561,6 +639,9 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)
developer1bc2ce22023-03-25 00:47:41 +08001924 nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets,
1925 MT76_TM_STATS_ATTR_PAD) ||
1926 nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error,
1927+ MT76_TM_STATS_ATTR_PAD) ||
1928+ nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_LEN_MISMATCH,
1929+ td->rx_stats.len_mismatch,
1930 MT76_TM_STATS_ATTR_PAD))
1931 return -EMSGSIZE;
1932
developer5f4e6c32023-12-20 06:12:53 +08001933@@ -625,6 +706,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
developer1bc2ce22023-03-25 00:47:41 +08001934 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
1935 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||
1936 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
developerc2cfe0f2023-09-22 04:11:09 +08001937+ nla_put_u8(msg, MT76_TM_ATTR_SKU_EN, td->sku_en) ||
developer1bc2ce22023-03-25 00:47:41 +08001938+ nla_put_u8(msg, MT76_TM_ATTR_AID, td->aid) ||
1939 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
1940 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
1941 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
developer5f4e6c32023-12-20 06:12:53 +08001942@@ -640,7 +723,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
1943 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&
1944 nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) ||
1945 (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) &&
1946- nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset)))
1947+ nla_put_u32(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset)))
1948 goto out;
1949
1950 if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) {
developer1bc2ce22023-03-25 00:47:41 +08001951diff --git a/testmode.h b/testmode.h
developer5f4e6c32023-12-20 06:12:53 +08001952index a40cd74b..96872e8c 100644
developer1bc2ce22023-03-25 00:47:41 +08001953--- a/testmode.h
1954+++ b/testmode.h
developer5f4e6c32023-12-20 06:12:53 +08001955@@ -5,7 +5,8 @@
1956 #ifndef __MT76_TESTMODE_H
1957 #define __MT76_TESTMODE_H
1958
1959-#define MT76_TM_TIMEOUT 10
1960+#define MT76_TM_TIMEOUT 10
1961+#define MT76_TM_EEPROM_BLOCK_SIZE 16
1962
1963 /**
1964 * enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA
1965@@ -19,6 +20,7 @@
developerc2cfe0f2023-09-22 04:11:09 +08001966 * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
1967 * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
1968 *
1969+ * @MT76_TM_ATTR_SKU_EN: config txpower sku is enabled or disabled in testmode (u8)
1970 * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
1971 * state to MT76_TM_STATE_TX_FRAMES (u32)
1972 * @MT76_TM_ATTR_TX_PENDING: pending frames during MT76_TM_STATE_TX_FRAMES (u32)
developer5f4e6c32023-12-20 06:12:53 +08001973@@ -39,6 +41,11 @@
developer1bc2ce22023-03-25 00:47:41 +08001974 *
1975 * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr)
1976 *
1977+ * @MT76_TM_ATTR_PRECAL: Pre-cal data (u8)
1978+ * @MT76_TM_ATTR_PRECAL_INFO: group size, dpd size, dpd_info, transmit size,
1979+ * eeprom cal indicator (u32),
1980+ * dpd_info = [dpd_per_chan_size, chan_num_2g,
1981+ * chan_num_5g, chan_num_6g]
1982 * @MT76_TM_ATTR_TX_SPE_IDX: tx spatial extension index (u8)
1983 *
1984 * @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8)
developer5f4e6c32023-12-20 06:12:53 +08001985@@ -48,6 +55,29 @@
developer1bc2ce22023-03-25 00:47:41 +08001986 * @MT76_TM_ATTR_DRV_DATA: driver specific netlink attrs (nested)
1987 *
1988 * @MT76_TM_ATTR_MAC_ADDRS: array of nested MAC addresses (nested)
1989+ *
1990+ * @MT76_TM_ATTR_EEPROM_ACTION: eeprom setting actions
1991+ * (u8, see &enum mt76_testmode_eeprom_action)
1992+ * @MT76_TM_ATTR_EEPROM_OFFSET: offset of eeprom data block for writing (u32)
1993+ * @MT76_TM_ATTR_EEPROM_VAL: values for writing into a 16-byte data block
1994+ * (nested, u8 attrs)
1995+ *
1996+ * @MT76_TM_ATTR_CFG: config testmode rf feature (nested, see &mt76_testmode_cfg)
1997+ * @MT76_TM_ATTR_TXBF_ACT: txbf setting actions (u8)
1998+ * @MT76_TM_ATTR_TXBF_PARAM: txbf parameters (nested)
1999+ *
2000+ * @MT76_TM_ATTR_OFF_CH_SCAN_CH: config the channel of background chain (ZWDFS) (u8)
2001+ * @MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH: config the center channel of background chain (ZWDFS) (u8)
2002+ * @MT76_TM_ATTR_OFF_CH_SCAN_BW: config the bandwidth of background chain (ZWDFS) (u8)
2003+ * @MT76_TM_ATTR_OFF_CH_SCAN_PATH: config the tx path of background chain (ZWDFS) (u8)
2004+ *
2005+ * @MT76_TM_ATTR_IPI_THRESHOLD: config the IPI index you want to read (u8)
2006+ * @MT76_TM_ATTR_IPI_PERIOD: config the time period for reading
2007+ * the histogram of specific IPI index (u8)
2008+ * @MT76_TM_ATTR_IPI_ANTENNA_INDEX: config the antenna index for reading
2009+ * the histogram of specific IPI index (u8)
2010+ * @MT76_TM_ATTR_IPI_RESET: Reset the IPI counter
2011+ *
2012 */
2013 enum mt76_testmode_attr {
2014 MT76_TM_ATTR_UNSPEC,
developer5f4e6c32023-12-20 06:12:53 +08002015@@ -59,6 +89,7 @@ enum mt76_testmode_attr {
developerc2cfe0f2023-09-22 04:11:09 +08002016 MT76_TM_ATTR_MTD_OFFSET,
2017 MT76_TM_ATTR_BAND_IDX,
2018
2019+ MT76_TM_ATTR_SKU_EN,
2020 MT76_TM_ATTR_TX_COUNT,
2021 MT76_TM_ATTR_TX_LENGTH,
2022 MT76_TM_ATTR_TX_RATE_MODE,
developer5f4e6c32023-12-20 06:12:53 +08002023@@ -76,6 +107,8 @@ enum mt76_testmode_attr {
developer1bc2ce22023-03-25 00:47:41 +08002024 MT76_TM_ATTR_FREQ_OFFSET,
2025
2026 MT76_TM_ATTR_STATS,
2027+ MT76_TM_ATTR_PRECAL,
2028+ MT76_TM_ATTR_PRECAL_INFO,
2029
2030 MT76_TM_ATTR_TX_SPE_IDX,
2031
developer5f4e6c32023-12-20 06:12:53 +08002032@@ -86,6 +119,27 @@ enum mt76_testmode_attr {
developer1bc2ce22023-03-25 00:47:41 +08002033 MT76_TM_ATTR_DRV_DATA,
2034
2035 MT76_TM_ATTR_MAC_ADDRS,
2036+ MT76_TM_ATTR_AID,
2037+ MT76_TM_ATTR_RU_ALLOC,
2038+ MT76_TM_ATTR_RU_IDX,
2039+
2040+ MT76_TM_ATTR_EEPROM_ACTION,
2041+ MT76_TM_ATTR_EEPROM_OFFSET,
2042+ MT76_TM_ATTR_EEPROM_VAL,
2043+
2044+ MT76_TM_ATTR_CFG,
2045+ MT76_TM_ATTR_TXBF_ACT,
2046+ MT76_TM_ATTR_TXBF_PARAM,
2047+
2048+ MT76_TM_ATTR_OFF_CH_SCAN_CH,
2049+ MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
2050+ MT76_TM_ATTR_OFF_CH_SCAN_BW,
2051+ MT76_TM_ATTR_OFF_CH_SCAN_PATH,
2052+
2053+ MT76_TM_ATTR_IPI_THRESHOLD,
2054+ MT76_TM_ATTR_IPI_PERIOD,
2055+ MT76_TM_ATTR_IPI_ANTENNA_INDEX,
2056+ MT76_TM_ATTR_IPI_RESET,
2057
2058 /* keep last */
2059 NUM_MT76_TM_ATTRS,
developer5f4e6c32023-12-20 06:12:53 +08002060@@ -103,6 +157,8 @@ enum mt76_testmode_attr {
developer1bc2ce22023-03-25 00:47:41 +08002061 * @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64)
2062 * @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet
2063 * see &enum mt76_testmode_rx_attr
2064+ * @MT76_TM_STATS_ATTR_RX_LEN_MISMATCH: number of rx packets with length
2065+ * mismatch error (u64)
2066 */
2067 enum mt76_testmode_stats_attr {
2068 MT76_TM_STATS_ATTR_UNSPEC,
developer5f4e6c32023-12-20 06:12:53 +08002069@@ -115,6 +171,7 @@ enum mt76_testmode_stats_attr {
developer1bc2ce22023-03-25 00:47:41 +08002070 MT76_TM_STATS_ATTR_RX_PACKETS,
2071 MT76_TM_STATS_ATTR_RX_FCS_ERROR,
2072 MT76_TM_STATS_ATTR_LAST_RX,
2073+ MT76_TM_STATS_ATTR_RX_LEN_MISMATCH,
2074
2075 /* keep last */
2076 NUM_MT76_TM_STATS_ATTRS,
developer5f4e6c32023-12-20 06:12:53 +08002077@@ -127,6 +184,7 @@ enum mt76_testmode_stats_attr {
developerc2cfe0f2023-09-22 04:11:09 +08002078 *
2079 * @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32)
2080 * @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8)
2081+ * @MT76_TM_RX_ATTR_RSSI: received signal strength indicator (array, s8)
2082 * @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (array, s8)
2083 * @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (array, s8)
2084 * @MT76_TM_RX_ATTR_SNR: signal-to-noise ratio (u8)
developer5f4e6c32023-12-20 06:12:53 +08002085@@ -136,6 +194,7 @@ enum mt76_testmode_rx_attr {
developerc2cfe0f2023-09-22 04:11:09 +08002086
2087 MT76_TM_RX_ATTR_FREQ_OFFSET,
2088 MT76_TM_RX_ATTR_RCPI,
2089+ MT76_TM_RX_ATTR_RSSI,
2090 MT76_TM_RX_ATTR_IB_RSSI,
2091 MT76_TM_RX_ATTR_WB_RSSI,
2092 MT76_TM_RX_ATTR_SNR,
developer5f4e6c32023-12-20 06:12:53 +08002093@@ -179,6 +238,9 @@ enum mt76_testmode_state {
developer1bc2ce22023-03-25 00:47:41 +08002094 * @MT76_TM_TX_MODE_HE_EXT_SU: 802.11ax extended-range SU
2095 * @MT76_TM_TX_MODE_HE_TB: 802.11ax trigger-based
2096 * @MT76_TM_TX_MODE_HE_MU: 802.11ax multi-user MIMO
2097+ * @MT76_TM_TX_MODE_EHT_SU: 802.11be single-user MIMO
2098+ * @MT76_TM_TX_MODE_EHT_TRIG: 802.11be trigger-based
2099+ * @MT76_TM_TX_MODE_EHT_MU: 802.11be multi-user MIMO
2100 */
2101 enum mt76_testmode_tx_mode {
2102 MT76_TM_TX_MODE_CCK,
developer5f4e6c32023-12-20 06:12:53 +08002103@@ -189,12 +251,33 @@ enum mt76_testmode_tx_mode {
developer1bc2ce22023-03-25 00:47:41 +08002104 MT76_TM_TX_MODE_HE_EXT_SU,
2105 MT76_TM_TX_MODE_HE_TB,
2106 MT76_TM_TX_MODE_HE_MU,
2107+ MT76_TM_TX_MODE_EHT_SU,
2108+ MT76_TM_TX_MODE_EHT_TRIG,
2109+ MT76_TM_TX_MODE_EHT_MU,
2110
2111 /* keep last */
2112 NUM_MT76_TM_TX_MODES,
developer5f4e6c32023-12-20 06:12:53 +08002113 MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1,
2114 };
2115
2116+/**
2117+ * enum mt76_testmode_eeprom_action - eeprom setting actions
2118+ *
2119+ * @MT76_TM_EEPROM_ACTION_UPDATE_DATA: update rf values to specific
2120+ * eeprom data block
2121+ * @MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE: send updated eeprom data to fw
2122+ * @MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE: write eeprom data back to efuse
2123+ */
2124+enum mt76_testmode_eeprom_action {
2125+ MT76_TM_EEPROM_ACTION_UPDATE_DATA,
2126+ MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE,
2127+ MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE,
2128+
2129+ /* keep last */
2130+ NUM_MT76_TM_EEPROM_ACTION,
2131+ MT76_TM_EEPROM_ACTION_MAX = NUM_MT76_TM_EEPROM_ACTION - 1,
2132+};
2133+
2134 extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS];
2135
2136 #endif
developer1bc2ce22023-03-25 00:47:41 +08002137diff --git a/tools/fields.c b/tools/fields.c
developer5f4e6c32023-12-20 06:12:53 +08002138index e3f69089..055f90f3 100644
developer1bc2ce22023-03-25 00:47:41 +08002139--- a/tools/fields.c
2140+++ b/tools/fields.c
2141@@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
2142 [MT76_TM_STATE_IDLE] = "idle",
2143 [MT76_TM_STATE_TX_FRAMES] = "tx_frames",
2144 [MT76_TM_STATE_RX_FRAMES] = "rx_frames",
2145+ [MT76_TM_STATE_TX_CONT] = "tx_cont",
2146 };
2147
2148 static const char * const testmode_tx_mode[] = {
2149@@ -21,6 +22,9 @@ static const char * const testmode_tx_mode[] = {
2150 [MT76_TM_TX_MODE_HE_EXT_SU] = "he_ext_su",
2151 [MT76_TM_TX_MODE_HE_TB] = "he_tb",
2152 [MT76_TM_TX_MODE_HE_MU] = "he_mu",
2153+ [MT76_TM_TX_MODE_EHT_SU] = "eht_su",
2154+ [MT76_TM_TX_MODE_EHT_TRIG] = "eht_tb",
2155+ [MT76_TM_TX_MODE_EHT_MU] = "eht_mu",
2156 };
2157
2158 static void print_enum(const struct tm_field *field, struct nlattr *attr)
developerc2cfe0f2023-09-22 04:11:09 +08002159@@ -65,7 +69,7 @@ static bool parse_u8(const struct tm_field *field, int idx,
2160
2161 static void print_u8(const struct tm_field *field, struct nlattr *attr)
2162 {
2163- printf("%d", nla_get_u8(attr));
2164+ printf("%u", nla_get_u8(attr));
2165 }
2166
2167 static void print_s8(const struct tm_field *field, struct nlattr *attr)
2168@@ -86,12 +90,12 @@ static void print_s32(const struct tm_field *field, struct nlattr *attr)
2169
2170 static void print_u32(const struct tm_field *field, struct nlattr *attr)
2171 {
2172- printf("%d", nla_get_u32(attr));
2173+ printf("%u", nla_get_u32(attr));
2174 }
2175
2176 static void print_u64(const struct tm_field *field, struct nlattr *attr)
2177 {
2178- printf("%lld", (unsigned long long)nla_get_u64(attr));
2179+ printf("%llu", (unsigned long long)nla_get_u64(attr));
2180 }
2181
2182 static bool parse_flag(const struct tm_field *field, int idx,
developer1bc2ce22023-03-25 00:47:41 +08002183@@ -201,6 +205,62 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb)
2184 printf("%srx_per=%.02f%%\n", prefix, 100 * failed / total);
2185 }
2186
2187+static bool parse_mac(const struct tm_field *field, int idx,
2188+ struct nl_msg *msg, const char *val)
2189+{
2190+#define ETH_ALEN 6
2191+ bool ret = true;
2192+ char *str, *cur, *ap;
2193+ void *a;
2194+
2195+ str = strdup(val);
2196+ ap = str;
2197+
2198+ a = nla_nest_start(msg, idx);
2199+
2200+ idx = 0;
2201+ while ((cur = strsep(&ap, ",")) != NULL) {
2202+ unsigned char addr[ETH_ALEN];
2203+ char *val, *tmp = cur;
2204+ int i = 0;
2205+
2206+ while ((val = strsep(&tmp, ":")) != NULL) {
2207+ if (i >= ETH_ALEN)
2208+ break;
2209+
2210+ addr[i++] = strtoul(val, NULL, 16);
2211+ }
2212+
2213+ nla_put(msg, idx, ETH_ALEN, addr);
2214+
2215+ idx++;
2216+ }
2217+
2218+ nla_nest_end(msg, a);
2219+
2220+ free(str);
2221+
2222+ return ret;
2223+}
2224+
2225+static void print_mac(const struct tm_field *field, struct nlattr *attr)
2226+{
2227+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
2228+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
2229+ unsigned char addr[3][6];
2230+ struct nlattr *cur;
2231+ int idx = 0;
2232+ int rem;
2233+
2234+ nla_for_each_nested(cur, attr, rem) {
2235+ if (nla_len(cur) != 6)
2236+ continue;
2237+ memcpy(addr[idx++], nla_data(cur), 6);
2238+ }
2239+
2240+ printf("" MACSTR "," MACSTR "," MACSTR "",
2241+ MAC2STR(addr[0]), MAC2STR(addr[1]), MAC2STR(addr[2]));
2242+}
2243
2244 #define FIELD_GENERIC(_field, _name, ...) \
2245 [FIELD_NAME(_field)] = { \
developerc2cfe0f2023-09-22 04:11:09 +08002246@@ -250,10 +310,18 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb)
developer1bc2ce22023-03-25 00:47:41 +08002247 ##__VA_ARGS__ \
2248 )
2249
2250+#define FIELD_MAC(_field, _name) \
2251+ [FIELD_NAME(_field)] = { \
2252+ .name = _name, \
2253+ .parse = parse_mac, \
2254+ .print = print_mac \
2255+ }
2256+
2257 #define FIELD_NAME(_field) MT76_TM_RX_ATTR_##_field
2258 static const struct tm_field rx_fields[NUM_MT76_TM_RX_ATTRS] = {
2259 FIELD_RO(s32, FREQ_OFFSET, "freq_offset"),
developerc2cfe0f2023-09-22 04:11:09 +08002260 FIELD_ARRAY_RO(u8, RCPI, "rcpi"),
2261+ FIELD_ARRAY_RO(s8, RSSI, "rssi"),
2262 FIELD_ARRAY_RO(s8, IB_RSSI, "ib_rssi"),
2263 FIELD_ARRAY_RO(s8, WB_RSSI, "wb_rssi"),
2264 FIELD_RO(s8, SNR, "snr"),
2265@@ -261,6 +329,7 @@ static const struct tm_field rx_fields[NUM_MT76_TM_RX_ATTRS] = {
2266 static struct nla_policy rx_policy[NUM_MT76_TM_RX_ATTRS] = {
2267 [MT76_TM_RX_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
2268 [MT76_TM_RX_ATTR_RCPI] = { .type = NLA_NESTED },
2269+ [MT76_TM_RX_ATTR_RSSI] = { .type = NLA_NESTED },
2270 [MT76_TM_RX_ATTR_IB_RSSI] = { .type = NLA_NESTED },
2271 [MT76_TM_RX_ATTR_WB_RSSI] = { .type = NLA_NESTED },
2272 [MT76_TM_RX_ATTR_SNR] = { .type = NLA_U8 },
2273@@ -274,6 +343,7 @@ static const struct tm_field stats_fields[NUM_MT76_TM_STATS_ATTRS] = {
developer1bc2ce22023-03-25 00:47:41 +08002274 FIELD_RO(u32, TX_DONE, "tx_done"),
2275 FIELD_RO(u64, RX_PACKETS, "rx_packets"),
2276 FIELD_RO(u64, RX_FCS_ERROR, "rx_fcs_error"),
2277+ FIELD_RO(u64, RX_LEN_MISMATCH, "rx_len_mismatch"),
2278 FIELD_NESTED_RO(LAST_RX, rx, "last_"),
2279 };
2280 static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
developerc2cfe0f2023-09-22 04:11:09 +08002281@@ -282,6 +352,7 @@ static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
developer1bc2ce22023-03-25 00:47:41 +08002282 [MT76_TM_STATS_ATTR_TX_DONE] = { .type = NLA_U32 },
2283 [MT76_TM_STATS_ATTR_RX_PACKETS] = { .type = NLA_U64 },
2284 [MT76_TM_STATS_ATTR_RX_FCS_ERROR] = { .type = NLA_U64 },
2285+ [MT76_TM_STATS_ATTR_RX_LEN_MISMATCH] = { .type = NLA_U64 },
2286 };
2287 #undef FIELD_NAME
2288
developerc2cfe0f2023-09-22 04:11:09 +08002289@@ -291,6 +362,7 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
2290 FIELD_ENUM(STATE, "state", testmode_state),
2291 FIELD_RO(string, MTD_PART, "mtd_part"),
2292 FIELD_RO(u32, MTD_OFFSET, "mtd_offset"),
2293+ FIELD(u8, SKU_EN, "sku_en"),
2294 FIELD(u32, TX_COUNT, "tx_count"),
2295 FIELD(u32, TX_LENGTH, "tx_length"),
2296 FIELD_ENUM(TX_RATE_MODE, "tx_rate_mode", testmode_tx_mode),
2297@@ -300,12 +372,20 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
developer1bc2ce22023-03-25 00:47:41 +08002298 FIELD(u8, TX_RATE_LDPC, "tx_rate_ldpc"),
2299 FIELD(u8, TX_RATE_STBC, "tx_rate_stbc"),
2300 FIELD(u8, TX_LTF, "tx_ltf"),
2301+ FIELD(u8, TX_DUTY_CYCLE, "tx_duty_cycle"),
2302+ FIELD(u32, TX_IPG, "tx_ipg"),
2303+ FIELD(u32, TX_TIME, "tx_time"),
2304 FIELD(u8, TX_POWER_CONTROL, "tx_power_control"),
2305 FIELD_ARRAY(u8, TX_POWER, "tx_power"),
2306 FIELD(u8, TX_ANTENNA, "tx_antenna"),
2307 FIELD(u32, FREQ_OFFSET, "freq_offset"),
2308+ FIELD(u8, AID, "aid"),
2309+ FIELD(u8, RU_ALLOC, "ru_alloc"),
2310+ FIELD(u8, RU_IDX, "ru_idx"),
2311+ FIELD_MAC(MAC_ADDRS, "mac_addrs"),
2312 FIELD_NESTED_RO(STATS, stats, "",
2313 .print_extra = print_extra_stats),
2314+
2315 };
2316 #undef FIELD_NAME
2317
developerc2cfe0f2023-09-22 04:11:09 +08002318@@ -313,6 +393,7 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
2319 [MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
2320 [MT76_TM_ATTR_MTD_PART] = { .type = NLA_STRING },
2321 [MT76_TM_ATTR_MTD_OFFSET] = { .type = NLA_U32 },
2322+ [MT76_TM_ATTR_SKU_EN] = { .type = NLA_U8 },
2323 [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
2324 [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
2325 [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
2326@@ -322,10 +403,25 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
developer1bc2ce22023-03-25 00:47:41 +08002327 [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },
2328 [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },
2329 [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },
2330+ [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 },
2331+ [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 },
2332+ [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
2333 [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
2334 [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },
2335+ [MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 },
2336 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
2337+ [MT76_TM_ATTR_AID] = { .type = NLA_U8 },
2338+ [MT76_TM_ATTR_RU_ALLOC] = { .type = NLA_U8 },
2339+ [MT76_TM_ATTR_RU_IDX] = { .type = NLA_U8 },
2340 [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED },
2341+ [MT76_TM_ATTR_TXBF_ACT] = { .type = NLA_U8 },
2342+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
2343+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
2344+ [MT76_TM_ATTR_OFF_CH_SCAN_BW] = { .type = NLA_U8 },
2345+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
2346+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
2347+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
2348+ [MT76_TM_ATTR_IPI_RESET] = { .type = NLA_U8 },
2349 };
2350
2351 const struct tm_field msg_field = {
2352--
developer7e2761e2023-10-12 08:11:13 +080023532.18.0
developer1bc2ce22023-03-25 00:47:41 +08002354