blob: bc959c319f7bfec263e88f4c85cd8b068a30ba2c [file] [log] [blame]
developer1f55fcf2024-10-17 14:52:33 +08001From a745353842ae1ca764abb6c9a24b43594799c3d0 Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
developerd0c89452024-10-11 16:53:27 +08003Date: Thu, 26 Sep 2024 14:54:11 +0800
developer1f55fcf2024-10-17 14:52:33 +08004Subject: [PATCH 015/193] mtk: mt76: mt7996: add basic testmode support
developer66e89bc2024-04-23 14:50:01 +08005
6Add testmode eeprom buffer mode support
7
developer66e89bc2024-04-23 14:50:01 +08008Fix power & freq offset issue for iTest power cal & tx/rx verifcation
91. Wait for fw to tx. Otherwise, iTest testing tool cannot get the
10accurate tx power.
112. In crystal mode, freq offset is set in 6G band and forwarded to 5G
12and 2G band. Therefore, we should avoid reseting freq offset to 0 when
136G interface is off.
14
developer66e89bc2024-04-23 14:50:01 +080015edcca return err in testmode; therefore, bypass it when we are in testmode idle state or testmode bf is on
16
developerd0c89452024-10-11 16:53:27 +080017Change-Id: I0e09e7f5bc0fb9aa4e4ec906a0f5f169bcc261cb
18Change-Id: I849b11b4ccdecd2b7b525b29801c02b5207bbf91
developer66e89bc2024-04-23 14:50:01 +080019Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
20---
21 eeprom.c | 6 +-
22 mac80211.c | 3 +-
23 mt76.h | 36 +++
24 mt76_connac_mcu.h | 2 +
25 mt7996/Makefile | 1 +
developerd0c89452024-10-11 16:53:27 +080026 mt7996/eeprom.c | 86 +++++-
developer66e89bc2024-04-23 14:50:01 +080027 mt7996/eeprom.h | 1 +
28 mt7996/init.c | 8 +
29 mt7996/mac.c | 3 +-
developerd0c89452024-10-11 16:53:27 +080030 mt7996/main.c | 35 +++
31 mt7996/mcu.c | 53 +++-
developer66e89bc2024-04-23 14:50:01 +080032 mt7996/mcu.h | 33 +++
developerd0c89452024-10-11 16:53:27 +080033 mt7996/mt7996.h | 27 ++
developer66e89bc2024-04-23 14:50:01 +080034 mt7996/testmode.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++
35 mt7996/testmode.h | 299 +++++++++++++++++++
36 testmode.c | 126 ++++++--
37 testmode.h | 87 +++++-
38 tools/fields.c | 102 ++++++-
developerd0c89452024-10-11 16:53:27 +080039 18 files changed, 1602 insertions(+), 46 deletions(-)
developer66e89bc2024-04-23 14:50:01 +080040 create mode 100644 mt7996/testmode.c
41 create mode 100644 mt7996/testmode.h
42
43diff --git a/eeprom.c b/eeprom.c
developer1f55fcf2024-10-17 14:52:33 +080044index ab4fab1..6bd2cc1 100644
developer66e89bc2024-04-23 14:50:01 +080045--- a/eeprom.c
46+++ b/eeprom.c
47@@ -94,8 +94,10 @@ int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int l
48 }
49
50 #ifdef CONFIG_NL80211_TESTMODE
51- dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
52- dev->test_mtd.offset = offset;
53+ if (len == dev->eeprom.size) {
54+ dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
55+ dev->test_mtd.offset = offset;
56+ }
57 #endif
58
59 out_put_node:
60diff --git a/mac80211.c b/mac80211.c
developer1f55fcf2024-10-17 14:52:33 +080061index dc1ef40..5d9512d 100644
developer66e89bc2024-04-23 14:50:01 +080062--- a/mac80211.c
63+++ b/mac80211.c
developer9237f442024-06-14 17:13:04 +080064@@ -846,7 +846,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
developer66e89bc2024-04-23 14:50:01 +080065 }
66
67 #ifdef CONFIG_NL80211_TESTMODE
68- if (phy->test.state == MT76_TM_STATE_RX_FRAMES) {
69+ if (!(phy->test.flag & MT_TM_FW_RX_COUNT) &&
70+ phy->test.state == MT76_TM_STATE_RX_FRAMES) {
71 phy->test.rx_stats.packets[q]++;
72 if (status->flag & RX_FLAG_FAILED_FCS_CRC)
73 phy->test.rx_stats.fcs_error[q]++;
74diff --git a/mt76.h b/mt76.h
developer1f55fcf2024-10-17 14:52:33 +080075index f50f211..f6ffcca 100644
developer66e89bc2024-04-23 14:50:01 +080076--- a/mt76.h
77+++ b/mt76.h
developerd0c89452024-10-11 16:53:27 +080078@@ -718,14 +718,21 @@ struct mt76_testmode_ops {
developer66e89bc2024-04-23 14:50:01 +080079 int (*set_params)(struct mt76_phy *phy, struct nlattr **tb,
80 enum mt76_testmode_state new_state);
81 int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg);
82+ void (*reset_rx_stats)(struct mt76_phy *phy);
83+ void (*tx_stop)(struct mt76_phy *phy);
84+ int (*set_eeprom)(struct mt76_phy *phy, u32 offset, u8 *val, u8 action);
85 };
86
87+#define MT_TM_FW_RX_COUNT BIT(0)
88+
89 struct mt76_testmode_data {
90 enum mt76_testmode_state state;
91
92 u32 param_set[DIV_ROUND_UP(NUM_MT76_TM_ATTRS, 32)];
93 struct sk_buff *tx_skb;
94
95+ u8 sku_en;
96+
97 u32 tx_count;
98 u16 tx_mpdu_len;
99
developerd0c89452024-10-11 16:53:27 +0800100@@ -735,6 +742,7 @@ struct mt76_testmode_data {
developer66e89bc2024-04-23 14:50:01 +0800101 u8 tx_rate_sgi;
102 u8 tx_rate_ldpc;
103 u8 tx_rate_stbc;
104+ u16 tx_preamble_puncture;
105 u8 tx_ltf;
106
107 u8 tx_antenna_mask;
developerd0c89452024-10-11 16:53:27 +0800108@@ -744,6 +752,9 @@ struct mt76_testmode_data {
developer66e89bc2024-04-23 14:50:01 +0800109 u32 tx_time;
110 u32 tx_ipg;
111
112+ bool ibf;
113+ bool ebf;
114+
115 u32 freq_offset;
116
117 u8 tx_power[4];
developerd0c89452024-10-11 16:53:27 +0800118@@ -758,7 +769,16 @@ struct mt76_testmode_data {
developer66e89bc2024-04-23 14:50:01 +0800119 struct {
120 u64 packets[__MT_RXQ_MAX];
121 u64 fcs_error[__MT_RXQ_MAX];
122+ u64 len_mismatch;
123 } rx_stats;
124+ u8 flag;
125+
126+ struct {
127+ u8 type;
128+ u8 enable;
129+ } cfg;
130+
131+ u8 aid;
132 };
133
134 struct mt76_vif {
developerd0c89452024-10-11 16:53:27 +0800135@@ -1466,6 +1486,22 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
developer66e89bc2024-04-23 14:50:01 +0800136 int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state);
137 int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len);
138
139+static inline void
140+mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx)
141+{
142+#ifdef CONFIG_NL80211_TESTMODE
143+ td->param_set[idx / 32] |= BIT(idx % 32);
144+#endif
145+}
146+
147+static inline bool
148+mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx)
149+{
150+#ifdef CONFIG_NL80211_TESTMODE
151+ return td->param_set[idx / 32] & BIT(idx % 32);
152+#endif
153+}
154+
155 static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
156 {
157 #ifdef CONFIG_NL80211_TESTMODE
158diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developer1f55fcf2024-10-17 14:52:33 +0800159index 200eace..873f59f 100644
developer66e89bc2024-04-23 14:50:01 +0800160--- a/mt76_connac_mcu.h
161+++ b/mt76_connac_mcu.h
developerd0c89452024-10-11 16:53:27 +0800162@@ -1284,12 +1284,14 @@ enum {
developer66e89bc2024-04-23 14:50:01 +0800163 MCU_UNI_CMD_EFUSE_CTRL = 0x2d,
164 MCU_UNI_CMD_RA = 0x2f,
165 MCU_UNI_CMD_MURU = 0x31,
166+ MCU_UNI_CMD_TESTMODE_RX_STAT = 0x32,
167 MCU_UNI_CMD_BF = 0x33,
168 MCU_UNI_CMD_CHANNEL_SWITCH = 0x34,
169 MCU_UNI_CMD_THERMAL = 0x35,
170 MCU_UNI_CMD_VOW = 0x37,
171 MCU_UNI_CMD_PP = 0x38,
172 MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
173+ MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
174 MCU_UNI_CMD_RRO = 0x57,
175 MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
176 MCU_UNI_CMD_PER_STA_INFO = 0x6d,
177diff --git a/mt7996/Makefile b/mt7996/Makefile
developer1f55fcf2024-10-17 14:52:33 +0800178index a056b40..7bb17f4 100644
developer66e89bc2024-04-23 14:50:01 +0800179--- a/mt7996/Makefile
180+++ b/mt7996/Makefile
181@@ -8,5 +8,6 @@ mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
182 debugfs.o mmio.o
183
184 mt7996e-$(CONFIG_DEV_COREDUMP) += coredump.o
185+mt7996e-$(CONFIG_NL80211_TESTMODE) += testmode.o
186
187 mt7996e-y += mtk_debugfs.o mtk_mcu.o
188diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
developer1f55fcf2024-10-17 14:52:33 +0800189index 21379ce..cb4fb70 100644
developer66e89bc2024-04-23 14:50:01 +0800190--- a/mt7996/eeprom.c
191+++ b/mt7996/eeprom.c
192@@ -6,6 +6,11 @@
193 #include <linux/firmware.h>
194 #include "mt7996.h"
195 #include "eeprom.h"
196+#include <linux/moduleparam.h>
197+
198+static bool testmode_enable;
199+module_param(testmode_enable, bool, 0644);
200+MODULE_PARM_DESC(testmode_enable, "Enable testmode");
201
202 static int mt7996_check_eeprom(struct mt7996_dev *dev)
203 {
204@@ -43,6 +48,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
205
206 static char *mt7996_eeprom_name(struct mt7996_dev *dev)
207 {
208+ if (dev->testmode_enable)
209+ return MT7996_EEPROM_DEFAULT_TM;
210+
211 switch (mt76_chip(&dev->mt76)) {
developerd0c89452024-10-11 16:53:27 +0800212 case 0x7992:
213 switch (dev->var.type) {
214@@ -171,6 +179,8 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default)
215 dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
216 memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
217 dev->flash_mode = true;
218+ dev->eeprom_mode = DEFAULT_BIN_MODE;
219+ eeprom[MT_EE_TESTMODE_EN] = dev->testmode_enable;
220
221 out:
222 release_firmware(fw);
223@@ -178,20 +188,84 @@ out:
developer66e89bc2024-04-23 14:50:01 +0800224 return ret;
225 }
226
227-static int mt7996_eeprom_load(struct mt7996_dev *dev)
developerd0c89452024-10-11 16:53:27 +0800228+static int
229+mt7996_eeprom_load_bin(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +0800230 {
developerd0c89452024-10-11 16:53:27 +0800231- bool use_default = false;
232+ u8 *eeprom = dev->mt76.eeprom.data;
233+ const struct firmware *fw = NULL;
developer66e89bc2024-04-23 14:50:01 +0800234 int ret;
235
developerd0c89452024-10-11 16:53:27 +0800236- ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
237- if (ret < 0)
238+ ret = request_firmware(&fw, dev->mt76.bin_file_name, dev->mt76.dev);
239+ if (ret)
developer66e89bc2024-04-23 14:50:01 +0800240 return ret;
241
developerd0c89452024-10-11 16:53:27 +0800242- if (ret && !mt7996_check_eeprom(dev)) {
243- dev->flash_mode = true;
244+ if (!fw || !fw->data) {
245+ dev_err(dev->mt76.dev, "Invalid bin %s\n", dev->mt76.bin_file_name);
246+ ret = -EINVAL;
247 goto out;
248 }
249
250+ memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
251+ dev->flash_mode = true;
252+
253+out:
254+ release_firmware(fw);
255+ return ret;
256+}
257+
258+static int mt7996_eeprom_load_flash(struct mt7996_dev *dev)
259+{
260+ int ret = 1;
261+
262+ /* return > 0 for load success, return 0 for load failed, return < 0 for no memory */
263+ dev->bin_file_mode = mt76_check_bin_file_mode(&dev->mt76);
264+ if (dev->bin_file_mode) {
265+ dev->mt76.eeprom.size = MT7996_EEPROM_SIZE;
266+ dev->mt76.eeprom.data = devm_kzalloc(dev->mt76.dev, dev->mt76.eeprom.size,
267+ GFP_KERNEL);
268+ if (!dev->mt76.eeprom.data)
269+ return -ENOMEM;
270+
271+ if (mt7996_eeprom_load_bin(dev))
272+ return 0;
273+ } else {
274+ ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
developer66e89bc2024-04-23 14:50:01 +0800275+ }
276+
developerd0c89452024-10-11 16:53:27 +0800277+ if (mt7996_check_eeprom(dev))
278+ return 0;
279+
280+ return ret;
281+}
282+
283+int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev)
284+{
285+ u8 *eeprom;
286+ int ret;
287+
288+ dev->testmode_enable = testmode_enable;
289+
290+ /* load eeprom in flash or bin file mode to determine fw mode */
291+ ret = mt7996_eeprom_load_flash(dev);
292+ if (ret <= 0)
293+ goto out;
294+
295+ dev->flash_mode = true;
296+ dev->eeprom_mode = dev->bin_file_mode ? BIN_FILE_MODE : FLASH_MODE;
297+ eeprom = dev->mt76.eeprom.data;
298+ /* testmode enable priority: eeprom field > module parameter */
299+ dev->testmode_enable = eeprom[MT_EE_TESTMODE_EN];
300+
301+out:
developer66e89bc2024-04-23 14:50:01 +0800302+ return ret;
303+}
304+
305+static int mt7996_eeprom_load(struct mt7996_dev *dev)
306+{
developerd0c89452024-10-11 16:53:27 +0800307+ bool use_default = false;
developer66e89bc2024-04-23 14:50:01 +0800308+ int ret;
developerd0c89452024-10-11 16:53:27 +0800309+
developer66e89bc2024-04-23 14:50:01 +0800310+ /* flash or bin file mode eeprom is loaded before mcu init */
developerd0c89452024-10-11 16:53:27 +0800311 if (!dev->flash_mode) {
312 u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
313 u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
developer66e89bc2024-04-23 14:50:01 +0800314diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
developer1f55fcf2024-10-17 14:52:33 +0800315index 8074a0a..7f7a718 100644
developer66e89bc2024-04-23 14:50:01 +0800316--- a/mt7996/eeprom.h
317+++ b/mt7996/eeprom.h
318@@ -14,6 +14,7 @@ enum mt7996_eeprom_field {
319 MT_EE_MAC_ADDR = 0x004,
320 MT_EE_MAC_ADDR2 = 0x00a,
321 MT_EE_WIFI_CONF = 0x190,
322+ MT_EE_TESTMODE_EN = 0x1af,
323 MT_EE_MAC_ADDR3 = 0x2c0,
324 MT_EE_RATE_DELTA_2G = 0x1400,
325 MT_EE_RATE_DELTA_5G = 0x147d,
326diff --git a/mt7996/init.c b/mt7996/init.c
developer1f55fcf2024-10-17 14:52:33 +0800327index c553a19..4958897 100644
developer66e89bc2024-04-23 14:50:01 +0800328--- a/mt7996/init.c
329+++ b/mt7996/init.c
developer1f55fcf2024-10-17 14:52:33 +0800330@@ -980,6 +980,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +0800331
332 set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
333
334+ ret = mt7996_eeprom_check_fw_mode(dev);
335+ if (ret < 0)
336+ return ret;
337+
338 ret = mt7996_mcu_init(dev);
339 if (ret)
340 return ret;
developer1f55fcf2024-10-17 14:52:33 +0800341@@ -1433,6 +1437,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +0800342
343 mt7996_init_wiphy(hw, &dev->mt76.mmio.wed);
344
345+#ifdef CONFIG_NL80211_TESTMODE
346+ dev->mt76.test_ops = &mt7996_testmode_ops;
347+#endif
348+
349 ret = mt76_register_device(&dev->mt76, true, mt76_rates,
350 ARRAY_SIZE(mt76_rates));
351 if (ret)
352diff --git a/mt7996/mac.c b/mt7996/mac.c
developer1f55fcf2024-10-17 14:52:33 +0800353index d1d45c9..d73644f 100644
developer66e89bc2024-04-23 14:50:01 +0800354--- a/mt7996/mac.c
355+++ b/mt7996/mac.c
developerd0c89452024-10-11 16:53:27 +0800356@@ -686,7 +686,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
developer66e89bc2024-04-23 14:50:01 +0800357 *info);
358 }
359
developerd0c89452024-10-11 16:53:27 +0800360- if (rxv && !(status->flag & RX_FLAG_8023)) {
361+ if (rxv && !(status->flag & RX_FLAG_8023) &&
362+ (mode >= MT_PHY_TYPE_HE_SU && mode < MT_PHY_TYPE_EHT_SU)) {
363 switch (status->encoding) {
364 case RX_ENC_EHT:
365 mt76_connac3_mac_decode_eht_radiotap(skb, rxv, mode);
developer66e89bc2024-04-23 14:50:01 +0800366diff --git a/mt7996/main.c b/mt7996/main.c
developer1f55fcf2024-10-17 14:52:33 +0800367index f4a1788..da47faf 100644
developer66e89bc2024-04-23 14:50:01 +0800368--- a/mt7996/main.c
369+++ b/mt7996/main.c
370@@ -23,6 +23,18 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
371 return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
372 }
373
374+static void mt7996_testmode_disable_all(struct mt7996_dev *dev)
375+{
376+ struct mt7996_phy *phy;
377+ int i;
378+
379+ for (i = 0; i < __MT_MAX_BAND; i++) {
380+ phy = __mt7996_phy(dev, i);
381+ if (phy)
382+ mt76_testmode_set_state(phy->mt76, MT76_TM_STATE_OFF);
383+ }
384+}
385+
386 int mt7996_run(struct ieee80211_hw *hw)
387 {
388 struct mt7996_dev *dev = mt7996_hw_dev(hw);
389@@ -45,6 +57,8 @@ int mt7996_run(struct ieee80211_hw *hw)
390 }
391 }
392
393+ mt7996_testmode_disable_all(dev);
394+
395 mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
396
397 ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
developerd0c89452024-10-11 16:53:27 +0800398@@ -188,6 +202,10 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
developer66e89bc2024-04-23 14:50:01 +0800399
developerd0c89452024-10-11 16:53:27 +0800400 mutex_lock(&dev->mt76.mutex);
401
402+ if (vif->type == NL80211_IFTYPE_MONITOR &&
403+ is_zero_ether_addr(vif->addr))
404+ phy->monitor_vif = vif;
405+
406 mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask);
407 if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) {
408 ret = -ENOSPC;
409@@ -266,6 +284,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
410
411 mt7996_mcu_add_sta(dev, vif, NULL, false, false);
412 mt7996_mcu_add_bss_info(phy, vif, false);
413+
414+ if (vif == phy->monitor_vif)
415+ phy->monitor_vif = NULL;
416+
417 mt7996_mcu_add_dev_info(phy, vif, false);
418
419 rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
420@@ -288,6 +310,11 @@ int mt7996_set_channel(struct mt76_phy *mphy)
421 struct mt7996_phy *phy = mphy->priv;
422 int ret;
developer66e89bc2024-04-23 14:50:01 +0800423
424+ if (mt76_testmode_enabled(phy->mt76) || phy->mt76->test.bf_en) {
425+ mt7996_tm_update_channel(phy);
426+ goto out;
427+ }
428+
429 ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
430 if (ret)
431 goto out;
developerd0c89452024-10-11 16:53:27 +0800432@@ -394,6 +421,12 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
developer66e89bc2024-04-23 14:50:01 +0800433 int ret;
434
435 if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
436+ if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
437+ ret = mt7996_mcu_edcca_enable(phy, true);
438+ if (ret)
439+ return ret;
440+ }
441+
442 ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE,
443 phy->mt76->chandef.punctured);
444 if (ret)
developer1f55fcf2024-10-17 14:52:33 +0800445@@ -1507,6 +1540,8 @@ const struct ieee80211_ops mt7996_ops = {
developer66e89bc2024-04-23 14:50:01 +0800446 .sta_set_decap_offload = mt7996_sta_set_decap_offload,
447 .add_twt_setup = mt7996_mac_add_twt_setup,
448 .twt_teardown_request = mt7996_twt_teardown_request,
449+ CFG80211_TESTMODE_CMD(mt76_testmode_cmd)
450+ CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
451 #ifdef CONFIG_MAC80211_DEBUGFS
452 .sta_add_debugfs = mt7996_sta_add_debugfs,
453 #endif
454diff --git a/mt7996/mcu.c b/mt7996/mcu.c
developer1f55fcf2024-10-17 14:52:33 +0800455index 0b96b30..2f3e547 100644
developer66e89bc2024-04-23 14:50:01 +0800456--- a/mt7996/mcu.c
457+++ b/mt7996/mcu.c
developerd0c89452024-10-11 16:53:27 +0800458@@ -2880,8 +2880,12 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +0800459 {
460 int ret;
461
462- ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM),
463- MT7996_RAM_TYPE_WM);
464+ if (dev->testmode_enable)
465+ ret = __mt7996_load_ram(dev, "WM_TM", fw_name(dev, FIRMWARE_WM_TM),
466+ MT7996_RAM_TYPE_WM_TM);
467+ else
468+ ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM),
469+ MT7996_RAM_TYPE_WM);
470 if (ret)
471 return ret;
472
developerd0c89452024-10-11 16:53:27 +0800473@@ -3574,15 +3578,7 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +0800474
developerd0c89452024-10-11 16:53:27 +0800475 int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len)
developer66e89bc2024-04-23 14:50:01 +0800476 {
477- struct {
478- u8 _rsv[4];
479-
480- __le16 tag;
481- __le16 len;
482- __le32 addr;
483- __le32 valid;
484- u8 data[16];
485- } __packed req = {
486+ struct mt7996_mcu_eeprom_info req = {
487 .tag = cpu_to_le16(UNI_EFUSE_ACCESS),
488 .len = cpu_to_le16(sizeof(req) - 4),
489 .addr = cpu_to_le32(round_down(offset,
developerd0c89452024-10-11 16:53:27 +0800490@@ -3604,6 +3600,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l
developer66e89bc2024-04-23 14:50:01 +0800491
developerd0c89452024-10-11 16:53:27 +0800492 if (!buf)
493 buf = (u8 *)dev->mt76.eeprom.data + addr;
developer66e89bc2024-04-23 14:50:01 +0800494+
developerd0c89452024-10-11 16:53:27 +0800495 if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE)
496 buf_len = MT7996_EEPROM_BLOCK_SIZE;
developer66e89bc2024-04-23 14:50:01 +0800497
developerd0c89452024-10-11 16:53:27 +0800498@@ -4630,3 +4627,37 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap)
developer66e89bc2024-04-23 14:50:01 +0800499 return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PP),
500 &req, sizeof(req), false);
501 }
502+
503+int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data)
504+{
505+ struct mt7996_dev *dev = phy->dev;
506+ struct tx_power_ctrl req = {
507+ .tag = cpu_to_le16(power_ctrl_id),
508+ .len = cpu_to_le16(sizeof(req) - 4),
509+ .power_ctrl_id = power_ctrl_id,
510+ .band_idx = phy->mt76->band_idx,
511+ };
512+
513+ switch (power_ctrl_id) {
514+ case UNI_TXPOWER_SKU_POWER_LIMIT_CTRL:
515+ req.sku_enable = !!data;
516+ break;
517+ case UNI_TXPOWER_PERCENTAGE_CTRL:
518+ req.percentage_ctrl_enable = !!data;
519+ break;
520+ case UNI_TXPOWER_PERCENTAGE_DROP_CTRL:
521+ req.power_drop_level = data;
522+ break;
523+ case UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL:
524+ req.bf_backoff_enable = !!data;
525+ break;
526+ case UNI_TXPOWER_ATE_MODE_CTRL:
527+ req.ate_mode_enable = !!data;
528+ break;
529+ default:
530+ req.sku_enable = !!data;
531+ }
532+
533+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER),
534+ &req, sizeof(req), false);
535+}
536diff --git a/mt7996/mcu.h b/mt7996/mcu.h
developer1f55fcf2024-10-17 14:52:33 +0800537index df42c0f..abf8ef4 100644
developer66e89bc2024-04-23 14:50:01 +0800538--- a/mt7996/mcu.h
539+++ b/mt7996/mcu.h
540@@ -157,6 +157,16 @@ struct mt7996_mcu_eeprom {
541 __le16 buf_len;
542 } __packed;
543
544+struct mt7996_mcu_eeprom_info {
545+ u8 _rsv[4];
546+
547+ __le16 tag;
548+ __le16 len;
549+ __le32 addr;
550+ __le32 valid;
551+ u8 data[MT7996_EEPROM_BLOCK_SIZE];
552+} __packed;
553+
554 struct mt7996_mcu_phy_rx_info {
555 u8 category;
556 u8 rate;
557@@ -889,8 +899,31 @@ enum {
558 UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
559 };
560
561+struct tx_power_ctrl {
562+ u8 _rsv[4];
563+
564+ __le16 tag;
565+ __le16 len;
566+
567+ u8 power_ctrl_id;
568+ union {
569+ bool sku_enable;
570+ bool ate_mode_enable;
571+ bool percentage_ctrl_enable;
572+ bool bf_backoff_enable;
573+ u8 power_drop_level;
574+ };
575+ u8 band_idx;
576+ u8 rsv[1];
577+} __packed;
578+
579 enum {
580+ UNI_TXPOWER_SKU_POWER_LIMIT_CTRL = 0,
581+ UNI_TXPOWER_PERCENTAGE_CTRL = 1,
582+ UNI_TXPOWER_PERCENTAGE_DROP_CTRL = 2,
583+ UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
584 UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
585+ UNI_TXPOWER_ATE_MODE_CTRL = 6,
586 };
587
588 enum {
589diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developer1f55fcf2024-10-17 14:52:33 +0800590index 6c88942..5f91151 100644
developer66e89bc2024-04-23 14:50:01 +0800591--- a/mt7996/mt7996.h
592+++ b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +0800593@@ -32,6 +32,7 @@
developer66e89bc2024-04-23 14:50:01 +0800594 #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin"
595 #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin"
596 #define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
597+#define MT7996_FIRMWARE_WM_TM "mediatek/mt7996/mt7996_wm_tm.bin"
598 #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
599
developerd0c89452024-10-11 16:53:27 +0800600 #define MT7996_FIRMWARE_WA_233 "mediatek/mt7996/mt7996_wa_233.bin"
601@@ -42,16 +43,19 @@
developer66e89bc2024-04-23 14:50:01 +0800602 #define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin"
603 #define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin"
604 #define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin"
605+#define MT7992_FIRMWARE_WM_TM "mediatek/mt7996/mt7992_wm_tm.bin"
606 #define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin"
607
developer66e89bc2024-04-23 14:50:01 +0800608 #define MT7992_FIRMWARE_WA_23 "mediatek/mt7996/mt7992_wa_23.bin"
609 #define MT7992_FIRMWARE_WM_23 "mediatek/mt7996/mt7992_wm_23.bin"
610 #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin"
611+#define MT7992_FIRMWARE_WM_TM_23 "mediatek/mt7996/mt7992_wm_tm_23.bin"
612 #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin"
613
developerd0c89452024-10-11 16:53:27 +0800614 #define MT7992_FIRMWARE_WA_24 "mediatek/mt7996/mt7992_wa_24.bin"
615 #define MT7992_FIRMWARE_WM_24 "mediatek/mt7996/mt7992_wm_24.bin"
616 #define MT7992_FIRMWARE_DSP_24 "mediatek/mt7996/mt7992_dsp_24.bin"
617+#define MT7992_FIRMWARE_WM_TM_24 "mediatek/mt7996/mt7992_wm_tm_24.bin"
618 #define MT7992_ROM_PATCH_24 "mediatek/mt7996/mt7992_rom_patch_24.bin"
619
developer66e89bc2024-04-23 14:50:01 +0800620 #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
developerd0c89452024-10-11 16:53:27 +0800621@@ -119,6 +123,7 @@ struct mt7996_dfs_pattern;
developer66e89bc2024-04-23 14:50:01 +0800622
623 enum mt7996_ram_type {
624 MT7996_RAM_TYPE_WM,
625+ MT7996_RAM_TYPE_WM_TM = MT7996_RAM_TYPE_WM,
626 MT7996_RAM_TYPE_WA,
627 MT7996_RAM_TYPE_DSP,
628 __MT7996_RAM_TYPE_MAX,
developerd0c89452024-10-11 16:53:27 +0800629@@ -258,6 +263,8 @@ struct mt7996_phy {
630
631 struct ieee80211_sband_iftype_data iftype[NUM_NL80211_BANDS][NUM_NL80211_IFTYPES];
632
633+ struct ieee80211_vif *monitor_vif;
634+
635 struct thermal_cooling_device *cdev;
636 u8 cdev_state;
637 u8 throttle_state;
638@@ -285,6 +292,21 @@ struct mt7996_phy {
developer66e89bc2024-04-23 14:50:01 +0800639
640 u8 pp_mode;
641 u16 punct_bitmap;
642+
643+#ifdef CONFIG_NL80211_TESTMODE
644+ struct {
645+ u32 *reg_backup;
646+
647+ s32 last_freq_offset;
648+ u8 last_rcpi[4];
649+ s8 last_rssi[4];
650+ s8 last_ib_rssi[4];
651+ s8 last_wb_rssi[4];
652+ u8 last_snr;
653+
654+ u8 spe_idx;
655+ } test;
656+#endif
657 };
658
659 struct mt7996_dev {
developerd0c89452024-10-11 16:53:27 +0800660@@ -365,6 +387,8 @@ struct mt7996_dev {
developer66e89bc2024-04-23 14:50:01 +0800661 spinlock_t lock;
662 } wed_rro;
663
664+ bool testmode_enable;
665+
666 bool ibf;
667 u8 fw_debug_wm;
668 u8 fw_debug_wa;
developerd0c89452024-10-11 16:53:27 +0800669@@ -502,6 +526,7 @@ mt7996_has_background_radar(struct mt7996_dev *dev)
developer66e89bc2024-04-23 14:50:01 +0800670 extern const struct ieee80211_ops mt7996_ops;
671 extern struct pci_driver mt7996_pci_driver;
672 extern struct pci_driver mt7996_hif_driver;
673+extern const struct mt76_testmode_ops mt7996_testmode_ops;
674
675 struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
676 void __iomem *mem_base, u32 device_id);
developerd0c89452024-10-11 16:53:27 +0800677@@ -511,6 +536,7 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
developer66e89bc2024-04-23 14:50:01 +0800678 int mt7996_register_device(struct mt7996_dev *dev);
679 void mt7996_unregister_device(struct mt7996_dev *dev);
680 int mt7996_eeprom_init(struct mt7996_dev *dev);
681+int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev);
682 int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
683 int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
684 struct ieee80211_channel *chan);
developerd0c89452024-10-11 16:53:27 +0800685@@ -598,6 +624,7 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
developer66e89bc2024-04-23 14:50:01 +0800686 void mt7996_mcu_exit(struct mt7996_dev *dev);
687 int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
688 int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
689+int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
690
691 static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
692 {
693diff --git a/mt7996/testmode.c b/mt7996/testmode.c
694new file mode 100644
developer1f55fcf2024-10-17 14:52:33 +0800695index 0000000..58f0ad2
developer66e89bc2024-04-23 14:50:01 +0800696--- /dev/null
697+++ b/mt7996/testmode.c
698@@ -0,0 +1,740 @@
699+// SPDX-License-Identifier: ISC
700+/*
701+ * Copyright (C) 2022 MediaTek Inc.
702+ */
703+
704+#include "mt7996.h"
705+#include "mac.h"
706+#include "mcu.h"
707+#include "testmode.h"
708+
709+enum {
710+ TM_CHANGED_TXPOWER,
711+ TM_CHANGED_FREQ_OFFSET,
712+ TM_CHANGED_SKU_EN,
713+ TM_CHANGED_TX_LENGTH,
714+ TM_CHANGED_TX_TIME,
715+ TM_CHANGED_CFG,
716+
717+ /* must be last */
718+ NUM_TM_CHANGED
719+};
720+
721+static const u8 tm_change_map[] = {
722+ [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER,
723+ [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,
724+ [TM_CHANGED_SKU_EN] = MT76_TM_ATTR_SKU_EN,
725+ [TM_CHANGED_TX_LENGTH] = MT76_TM_ATTR_TX_LENGTH,
726+ [TM_CHANGED_TX_TIME] = MT76_TM_ATTR_TX_TIME,
727+ [TM_CHANGED_CFG] = MT76_TM_ATTR_CFG,
728+};
729+
730+static u8 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_method method)
731+{
732+ static const u8 width_to_bw[][NUM_BW_MAP] = {
733+ [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ},
734+ [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ},
735+ [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ},
736+ [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ},
737+ [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ},
738+ [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ},
739+ [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
740+ [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
741+ [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ},
742+ };
743+
744+ if (width >= ARRAY_SIZE(width_to_bw))
745+ return 0;
746+
747+ return width_to_bw[width][method];
748+}
749+
750+static u8 mt7996_tm_rate_to_phy(u8 tx_rate_mode)
751+{
752+ static const u8 rate_to_phy[] = {
753+ [MT76_TM_TX_MODE_CCK] = MT_PHY_TYPE_CCK,
754+ [MT76_TM_TX_MODE_OFDM] = MT_PHY_TYPE_OFDM,
755+ [MT76_TM_TX_MODE_HT] = MT_PHY_TYPE_HT,
756+ [MT76_TM_TX_MODE_VHT] = MT_PHY_TYPE_VHT,
757+ [MT76_TM_TX_MODE_HE_SU] = MT_PHY_TYPE_HE_SU,
758+ [MT76_TM_TX_MODE_HE_EXT_SU] = MT_PHY_TYPE_HE_EXT_SU,
759+ [MT76_TM_TX_MODE_HE_TB] = MT_PHY_TYPE_HE_TB,
760+ [MT76_TM_TX_MODE_HE_MU] = MT_PHY_TYPE_HE_MU,
761+ [MT76_TM_TX_MODE_EHT_SU] = MT_PHY_TYPE_EHT_SU,
762+ [MT76_TM_TX_MODE_EHT_TRIG] = MT_PHY_TYPE_EHT_TRIG,
763+ [MT76_TM_TX_MODE_EHT_MU] = MT_PHY_TYPE_EHT_MU,
764+ };
765+
766+ if (tx_rate_mode > MT76_TM_TX_MODE_MAX)
767+ return -EINVAL;
768+
769+ return rate_to_phy[tx_rate_mode];
770+}
771+
772+static int
773+mt7996_tm_check_antenna(struct mt7996_phy *phy)
774+{
775+ struct mt76_testmode_data *td = &phy->mt76->test;
776+ struct mt7996_dev *dev = phy->dev;
777+ u8 band_idx = phy->mt76->band_idx;
778+ u32 chainmask = phy->mt76->chainmask;
779+ u32 aux_rx_mask;
780+
781+ chainmask = chainmask >> dev->chainshift[band_idx];
782+ aux_rx_mask = BIT(fls(chainmask)) * phy->has_aux_rx;
783+ if (td->tx_antenna_mask & ~(chainmask | aux_rx_mask)) {
784+ dev_err(dev->mt76.dev,
785+ "tx antenna mask 0x%x exceeds hw limit (chainmask 0x%x, has aux rx: %s)\n",
786+ td->tx_antenna_mask, chainmask, phy->has_aux_rx ? "yes" : "no");
787+ return -EINVAL;
788+ }
789+
790+ return 0;
791+}
792+
793+static int
794+mt7996_tm_set(struct mt7996_dev *dev, u32 func_idx, u32 data)
795+{
796+ struct mt7996_tm_req req = {
797+ .rf_test = {
798+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
799+ .len = cpu_to_le16(sizeof(req.rf_test)),
800+ .action = RF_ACTION_SET,
801+ .op.rf.func_idx = func_idx,
802+ .op.rf.param.func_data = cpu_to_le32(data),
803+ },
804+ };
805+ bool wait = (data == RF_CMD(START_TX)) ? true : false;
806+
807+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_CTRL), &req,
808+ sizeof(req), wait);
809+}
810+
811+static int
812+mt7996_tm_get(struct mt7996_dev *dev, u32 func_idx, u32 data, u32 *result)
813+{
814+ struct mt7996_tm_req req = {
815+ .rf_test = {
816+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
817+ .len = cpu_to_le16(sizeof(req.rf_test)),
818+ .action = RF_ACTION_GET,
819+ .op.rf.func_idx = func_idx,
820+ .op.rf.param.func_data = cpu_to_le32(data),
821+ },
822+ };
823+ struct mt7996_tm_event *event;
824+ struct sk_buff *skb;
825+ int ret;
826+
827+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(TESTMODE_CTRL),
828+ &req, sizeof(req), true, &skb);
829+ if (ret)
830+ return ret;
831+
832+ event = (struct mt7996_tm_event *)skb->data;
833+ *result = event->result.payload_length;
834+
835+ dev_kfree_skb(skb);
836+
837+ return ret;
838+}
839+
840+static void
841+mt7996_tm_set_antenna(struct mt7996_phy *phy, u32 func_idx)
842+{
843+#define SPE_INDEX_MASK BIT(31)
844+#define TX_ANTENNA_MASK GENMASK(3, 0)
845+#define RX_ANTENNA_MASK GENMASK(20, 16) /* RX antenna mask at most 5 bit */
846+ struct mt7996_dev *dev = phy->dev;
847+ struct mt76_testmode_data *td = &phy->mt76->test;
848+ u32 antenna_mask;
849+
850+ if (!mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA))
851+ return;
852+
853+ if (func_idx == SET_ID(TX_PATH))
854+ antenna_mask = td->tx_spe_idx ? (SPE_INDEX_MASK | td->tx_spe_idx) :
855+ td->tx_antenna_mask & TX_ANTENNA_MASK;
856+ else if (func_idx == SET_ID(RX_PATH))
857+ antenna_mask = u32_encode_bits(td->tx_antenna_mask, RX_ANTENNA_MASK);
858+ else
859+ return;
860+
861+ mt7996_tm_set(dev, func_idx, antenna_mask);
862+}
863+
864+static void
865+mt7996_tm_set_mac_addr(struct mt7996_dev *dev, u8 *addr, u32 func_idx)
866+{
867+#define REMAIN_PART_TAG BIT(18)
868+ u32 own_mac_first = 0, own_mac_remain = 0;
869+ int len = sizeof(u32);
870+
871+ memcpy(&own_mac_first, addr, len);
872+ mt7996_tm_set(dev, func_idx, own_mac_first);
873+ /* Set the remain part of mac address */
874+ memcpy(&own_mac_remain, addr + len, ETH_ALEN - len);
875+ mt7996_tm_set(dev, func_idx | REMAIN_PART_TAG, own_mac_remain);
876+}
877+
878+static int
879+mt7996_tm_rf_switch_mode(struct mt7996_dev *dev, u32 op_mode)
880+{
881+ struct mt7996_tm_req req = {
882+ .rf_test = {
883+ .tag = cpu_to_le16(UNI_RF_TEST_CTRL),
884+ .len = cpu_to_le16(sizeof(req.rf_test)),
885+ .action = RF_ACTION_SWITCH_TO_RF_TEST,
886+ .op.op_mode = cpu_to_le32(op_mode),
887+ },
888+ };
889+
890+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_CTRL), &req,
891+ sizeof(req), false);
892+}
893+
894+static void
895+mt7996_tm_init(struct mt7996_phy *phy, bool en)
896+{
897+ struct mt7996_dev *dev = phy->dev;
898+ u8 rf_test_mode = en ? RF_OPER_RF_TEST : RF_OPER_NORMAL;
899+
900+ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
901+ return;
902+
903+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(ATE_MODE), en);
904+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(SKU_POWER_LIMIT), !en);
905+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(BACKOFF_POWER_LIMIT), !en);
906+
907+ mt7996_tm_rf_switch_mode(dev, rf_test_mode);
908+
909+ mt7996_mcu_add_bss_info(phy, phy->monitor_vif, en);
910+ mt7996_mcu_add_sta(dev, phy->monitor_vif, NULL, en, false);
911+
912+ mt7996_tm_set(dev, SET_ID(BAND_IDX), phy->mt76->band_idx);
913+
914+ /* use firmware counter for RX stats */
915+ phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
916+}
917+
918+static void
919+mt7996_tm_update_channel(struct mt7996_phy *phy)
920+{
921+#define CHAN_FREQ_BW_80P80_TAG (SET_ID(CHAN_FREQ) | BIT(16))
922+ struct mt7996_dev *dev = phy->dev;
923+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
924+ struct ieee80211_channel *chan = chandef->chan;
925+ u8 width = chandef->width;
926+ static const u8 ch_band[] = {
927+ [NL80211_BAND_2GHZ] = 0,
928+ [NL80211_BAND_5GHZ] = 1,
929+ [NL80211_BAND_6GHZ] = 2,
930+ };
931+
932+ if (!chan || !chandef) {
933+ dev_info(dev->mt76.dev, "chandef not found, channel update failed!\n");
934+ return;
935+ }
936+
937+ /* system bw */
938+ mt7996_tm_set(dev, SET_ID(CBW), mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
939+
940+ if (width == NL80211_CHAN_WIDTH_80P80) {
941+ width = NL80211_CHAN_WIDTH_160;
942+ mt7996_tm_set(dev, CHAN_FREQ_BW_80P80_TAG, chandef->center_freq2 * 1000);
943+ }
944+
945+ /* TODO: define per-packet bw */
946+ /* per-packet bw */
947+ mt7996_tm_set(dev, SET_ID(DBW), mt7996_tm_bw_mapping(width, BW_MAP_NL_TO_FW));
948+
949+ /* control channel selection index */
950+ mt7996_tm_set(dev, SET_ID(PRIMARY_CH), 0);
951+ mt7996_tm_set(dev, SET_ID(BAND), ch_band[chan->band]);
952+
953+ /* trigger switch channel calibration */
954+ mt7996_tm_set(dev, SET_ID(CHAN_FREQ), chandef->center_freq1 * 1000);
955+
956+ // TODO: update power limit table
957+}
958+
959+static void
960+mt7996_tm_tx_stop(struct mt76_phy *mphy)
961+{
962+ struct mt76_testmode_data *td = &mphy->test;
963+ struct mt7996_phy *phy = mphy->priv;
964+ struct mt7996_dev *dev = phy->dev;
965+
966+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
967+ td->tx_pending = 0;
968+}
969+
970+static void
971+mt7996_tm_set_tx_frames(struct mt7996_phy *phy, bool en)
972+{
973+#define FRAME_CONTROL 0x88
974+ struct mt76_testmode_data *td = &phy->mt76->test;
975+ struct mt7996_dev *dev = phy->dev;
976+
977+ //TODO: RU operation, replace mcs, nss, and ldpc
978+ if (en) {
979+ mt7996_tm_set(dev, SET_ID(MAC_HEADER), FRAME_CONTROL);
980+ mt7996_tm_set(dev, SET_ID(SEQ_CTRL), 0);
981+ mt7996_tm_set(dev, SET_ID(TX_COUNT), td->tx_count);
982+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
983+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
984+
985+ if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER))
986+ mt7996_tm_set(dev, SET_ID(POWER), td->tx_power[0]);
987+
988+ if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_TIME)) {
989+ mt7996_tm_set(dev, SET_ID(TX_LEN), 0);
990+ mt7996_tm_set(dev, SET_ID(TX_TIME), td->tx_time);
991+ } else {
992+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
993+ mt7996_tm_set(dev, SET_ID(TX_TIME), 0);
994+ }
995+
996+ mt7996_tm_set_antenna(phy, SET_ID(TX_PATH));
997+ mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
998+ mt7996_tm_set(dev, SET_ID(STBC), td->tx_rate_stbc);
999+ mt7996_tm_set(dev, SET_ID(ENCODE_MODE), td->tx_rate_ldpc);
1000+ mt7996_tm_set(dev, SET_ID(IBF_ENABLE), td->ibf);
1001+ mt7996_tm_set(dev, SET_ID(EBF_ENABLE), td->ebf);
1002+ mt7996_tm_set(dev, SET_ID(IPG), td->tx_ipg);
1003+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
1004+ mt7996_tm_set(dev, SET_ID(NSS), td->tx_rate_nss);
1005+ mt7996_tm_set(dev, SET_ID(AID_OFFSET), 0);
1006+ mt7996_tm_set(dev, SET_ID(PUNCTURE), td->tx_preamble_puncture);
1007+
1008+ mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
1009+ mt7996_tm_set(dev, SET_ID(HW_TX_MODE), 0);
1010+ mt7996_tm_update_channel(phy);
1011+
1012+ /* trigger firmware to start TX */
1013+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_TX));
1014+ } else {
1015+ mt7996_tm_tx_stop(phy->mt76);
1016+ }
1017+}
1018+
1019+static int
1020+mt7996_tm_rx_stats_user_ctrl(struct mt7996_phy *phy, u16 user_idx)
1021+{
1022+ struct mt7996_dev *dev = phy->dev;
1023+ struct mt7996_tm_rx_req req = {
1024+ .band = phy->mt76->band_idx,
1025+ .user_ctrl = {
1026+ .tag = cpu_to_le16(UNI_TM_RX_STAT_SET_USER_CTRL),
1027+ .len = cpu_to_le16(sizeof(req.user_ctrl)),
1028+ .band_idx = phy->mt76->band_idx,
1029+ .user_idx = cpu_to_le16(user_idx),
1030+ },
1031+ };
1032+
1033+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TESTMODE_RX_STAT), &req,
1034+ sizeof(req), false);
1035+}
1036+
1037+static void
1038+mt7996_tm_set_rx_frames(struct mt7996_phy *phy, bool en)
1039+{
1040+#define RX_MU_DISABLE 0xf800
1041+ struct mt76_testmode_data *td = &phy->mt76->test;
1042+ struct mt7996_dev *dev = phy->dev;
1043+ int ret;
1044+
1045+ if (en) {
1046+ ret = mt7996_tm_rx_stats_user_ctrl(phy, td->aid);
1047+ if (ret) {
1048+ dev_info(dev->mt76.dev, "Set RX stats user control failed!\n");
1049+ return;
1050+ }
1051+
1052+ mt7996_tm_update_channel(phy);
1053+
1054+ if (td->tx_rate_mode >= MT76_TM_TX_MODE_HE_MU) {
1055+ if (td->aid)
1056+ ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), td->aid);
1057+ else
1058+ ret = mt7996_tm_set(dev, SET_ID(RX_MU_AID), RX_MU_DISABLE);
1059+ }
1060+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1061+ mt7996_tm_set(dev, SET_ID(GI), td->tx_rate_sgi);
1062+ mt7996_tm_set_antenna(phy, SET_ID(RX_PATH));
1063+ mt7996_tm_set(dev, SET_ID(MAX_PE), 2);
1064+
1065+ mt7996_tm_set_mac_addr(dev, td->addr[1], SET_ID(SA));
1066+
1067+ /* trigger firmware to start RX */
1068+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(START_RX));
1069+ } else {
1070+ /* trigger firmware to stop RX */
1071+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
1072+ }
1073+}
1074+
1075+static void
1076+mt7996_tm_set_tx_cont(struct mt7996_phy *phy, bool en)
1077+{
1078+#define CONT_WAVE_MODE_OFDM 3
1079+ struct mt76_testmode_data *td = &phy->mt76->test;
1080+ struct mt7996_dev *dev = phy->dev;
1081+
1082+ if (en) {
1083+ mt7996_tm_update_channel(phy);
1084+ mt7996_tm_set(dev, SET_ID(TX_MODE), mt7996_tm_rate_to_phy(td->tx_rate_mode));
1085+ mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
1086+ /* fix payload is OFDM */
1087+ mt7996_tm_set(dev, SET_ID(CONT_WAVE_MODE), CONT_WAVE_MODE_OFDM);
1088+ mt7996_tm_set(dev, SET_ID(ANT_MASK), td->tx_antenna_mask);
1089+
1090+ /* trigger firmware to start CONT TX */
1091+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(CONT_WAVE));
1092+ } else {
1093+ /* trigger firmware to stop CONT TX */
1094+ mt7996_tm_set(dev, SET_ID(COMMAND), RF_CMD(STOP_TEST));
1095+ }
1096+}
1097+
1098+static void
1099+mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
1100+{
1101+ struct mt76_testmode_data *td = &phy->mt76->test;
1102+ struct mt7996_dev *dev = phy->dev;
1103+
1104+ if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) {
1105+ mt7996_tm_set(dev, SET_ID(FREQ_OFFSET), td->freq_offset);
1106+ mt7996_tm_set(dev, SET_ID(FREQ_OFFSET_C2), td->freq_offset);
1107+ }
1108+ if (changed & BIT(TM_CHANGED_TXPOWER))
1109+ mt7996_tm_set(dev, SET_ID(POWER), td->tx_power[0]);
1110+ if (changed & BIT(TM_CHANGED_SKU_EN)) {
1111+ mt7996_tm_update_channel(phy);
1112+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(SKU_POWER_LIMIT), td->sku_en);
1113+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(BACKOFF_POWER_LIMIT), td->sku_en);
1114+ mt7996_mcu_set_txpower_sku(phy);
1115+ }
1116+ if (changed & BIT(TM_CHANGED_TX_LENGTH)) {
1117+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
1118+ mt7996_tm_set(dev, SET_ID(TX_TIME), 0);
1119+ }
1120+ if (changed & BIT(TM_CHANGED_TX_TIME)) {
1121+ mt7996_tm_set(dev, SET_ID(TX_LEN), 0);
1122+ mt7996_tm_set(dev, SET_ID(TX_TIME), td->tx_time);
1123+ }
1124+ if (changed & BIT(TM_CHANGED_CFG)) {
1125+ u32 func_idx = td->cfg.enable ? SET_ID(CFG_ON) : SET_ID(CFG_OFF);
1126+
1127+ mt7996_tm_set(dev, func_idx, td->cfg.type);
1128+ }
1129+}
1130+
1131+static int
1132+mt7996_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state)
1133+{
1134+ struct mt76_testmode_data *td = &mphy->test;
1135+ struct mt7996_phy *phy = mphy->priv;
1136+ enum mt76_testmode_state prev_state = td->state;
1137+
1138+ mphy->test.state = state;
1139+
1140+ if (prev_state != MT76_TM_STATE_OFF)
1141+ mt7996_tm_set(phy->dev, SET_ID(BAND_IDX), mphy->band_idx);
1142+
1143+ if (prev_state == MT76_TM_STATE_TX_FRAMES ||
1144+ state == MT76_TM_STATE_TX_FRAMES)
1145+ mt7996_tm_set_tx_frames(phy, state == MT76_TM_STATE_TX_FRAMES);
1146+ else if (prev_state == MT76_TM_STATE_RX_FRAMES ||
1147+ state == MT76_TM_STATE_RX_FRAMES)
1148+ mt7996_tm_set_rx_frames(phy, state == MT76_TM_STATE_RX_FRAMES);
1149+ else if (prev_state == MT76_TM_STATE_TX_CONT ||
1150+ state == MT76_TM_STATE_TX_CONT)
1151+ mt7996_tm_set_tx_cont(phy, state == MT76_TM_STATE_TX_CONT);
1152+ else if (prev_state == MT76_TM_STATE_OFF ||
1153+ state == MT76_TM_STATE_OFF)
1154+ mt7996_tm_init(phy, !(state == MT76_TM_STATE_OFF));
1155+
1156+ if ((state == MT76_TM_STATE_IDLE &&
1157+ prev_state == MT76_TM_STATE_OFF) ||
1158+ (state == MT76_TM_STATE_OFF &&
1159+ prev_state == MT76_TM_STATE_IDLE)) {
1160+ u32 changed = 0;
1161+ int i, ret;
1162+
1163+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
1164+ u16 cur = tm_change_map[i];
1165+
1166+ if (mt76_testmode_param_present(td, cur))
1167+ changed |= BIT(i);
1168+ }
1169+
1170+ ret = mt7996_tm_check_antenna(phy);
1171+ if (ret)
1172+ return ret;
1173+
1174+ mt7996_tm_update_params(phy, changed);
1175+ }
1176+
1177+ return 0;
1178+}
1179+
1180+static int
1181+mt7996_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb,
1182+ enum mt76_testmode_state new_state)
1183+{
1184+ struct mt76_testmode_data *td = &mphy->test;
1185+ struct mt7996_phy *phy = mphy->priv;
1186+ struct mt7996_dev *dev = phy->dev;
1187+ u32 changed = 0;
1188+ int i, ret;
1189+
1190+ BUILD_BUG_ON(NUM_TM_CHANGED >= 32);
1191+
1192+ if (new_state == MT76_TM_STATE_OFF ||
1193+ td->state == MT76_TM_STATE_OFF)
1194+ return 0;
1195+
1196+ ret = mt7996_tm_check_antenna(phy);
1197+ if (ret)
1198+ return ret;
1199+
1200+ for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) {
1201+ if (tb[tm_change_map[i]])
1202+ changed |= BIT(i);
1203+ }
1204+
1205+ mt7996_tm_set(dev, SET_ID(BAND_IDX), mphy->band_idx);
1206+ mt7996_tm_update_params(phy, changed);
1207+
1208+ return 0;
1209+}
1210+
1211+static int
1212+mt7996_tm_get_rx_stats(struct mt7996_phy *phy)
1213+{
1214+ struct mt7996_dev *dev = phy->dev;
1215+ struct mt7996_tm_rx_req req = {
1216+ .band = phy->mt76->band_idx,
1217+ .rx_stat_all = {
1218+ .tag = cpu_to_le16(UNI_TM_RX_STAT_GET_ALL_V2),
1219+ .len = cpu_to_le16(sizeof(req.rx_stat_all)),
1220+ .band_idx = phy->mt76->band_idx,
1221+ },
1222+ };
1223+ struct mt76_testmode_data *td = &phy->mt76->test;
1224+ struct mt7996_tm_rx_event *rx_stats;
1225+ struct mt7996_tm_rx_event_stat_all *rx_stats_all;
1226+ struct sk_buff *skb;
1227+ enum mt76_rxq_id qid;
1228+ int i, ret = 0;
1229+ u32 mac_rx_mdrdy_cnt;
1230+ u16 mac_rx_len_mismatch, fcs_err_count;
1231+
1232+ if (td->state != MT76_TM_STATE_RX_FRAMES)
1233+ return 0;
1234+
1235+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD_QUERY(TESTMODE_RX_STAT),
1236+ &req, sizeof(req), true, &skb);
1237+
1238+ if (ret)
1239+ return ret;
1240+
1241+ rx_stats = (struct mt7996_tm_rx_event *)skb->data;
1242+ rx_stats_all = &rx_stats->rx_stat_all;
1243+
1244+ phy->test.last_freq_offset = le32_to_cpu(rx_stats_all->user_info[0].freq_offset);
1245+ phy->test.last_snr = le32_to_cpu(rx_stats_all->user_info[0].snr);
1246+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) {
1247+ phy->test.last_rcpi[i] = le16_to_cpu(rx_stats_all->rxv_info[i].rcpi);
1248+ phy->test.last_rssi[i] = le16_to_cpu(rx_stats_all->rxv_info[i].rssi);
1249+ phy->test.last_ib_rssi[i] = rx_stats_all->fagc[i].ib_rssi;
1250+ phy->test.last_wb_rssi[i] = rx_stats_all->fagc[i].wb_rssi;
1251+ }
1252+
1253+ if (phy->mt76->band_idx == 2)
1254+ qid = MT_RXQ_BAND2;
1255+ else if (phy->mt76->band_idx == 1)
1256+ qid = MT_RXQ_BAND1;
1257+ else
1258+ qid = MT_RXQ_MAIN;
1259+
1260+ fcs_err_count = le16_to_cpu(rx_stats_all->band_info.mac_rx_fcs_err_cnt);
1261+ mac_rx_len_mismatch = le16_to_cpu(rx_stats_all->band_info.mac_rx_len_mismatch);
1262+ mac_rx_mdrdy_cnt = le32_to_cpu(rx_stats_all->band_info.mac_rx_mdrdy_cnt);
1263+ td->rx_stats.packets[qid] += mac_rx_mdrdy_cnt;
1264+ td->rx_stats.packets[qid] += fcs_err_count;
1265+ td->rx_stats.fcs_error[qid] += fcs_err_count;
1266+ td->rx_stats.len_mismatch += mac_rx_len_mismatch;
1267+
1268+ dev_kfree_skb(skb);
1269+
1270+ return ret;
1271+}
1272+
1273+static void
1274+mt7996_tm_reset_trx_stats(struct mt76_phy *mphy)
1275+{
1276+ struct mt7996_phy *phy = mphy->priv;
1277+ struct mt7996_dev *dev = phy->dev;
1278+
1279+ memset(&mphy->test.rx_stats, 0, sizeof(mphy->test.rx_stats));
1280+ mt7996_tm_set(dev, SET_ID(TRX_COUNTER_RESET), 0);
1281+}
1282+
1283+static int
1284+mt7996_tm_get_tx_stats(struct mt7996_phy *phy)
1285+{
1286+ struct mt7996_dev *dev = phy->dev;
1287+ struct mt76_testmode_data *td = &phy->mt76->test;
1288+ int ret;
1289+
1290+ if (td->state != MT76_TM_STATE_TX_FRAMES)
1291+ return 0;
1292+
1293+ ret = mt7996_tm_get(dev, GET_ID(TXED_COUNT), 0, &td->tx_done);
1294+ if (ret)
1295+ return ret;
1296+
1297+ td->tx_pending = td->tx_count - td->tx_done;
1298+
1299+ return ret;
1300+}
1301+
1302+static int
1303+mt7996_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg)
1304+{
1305+ struct mt7996_phy *phy = mphy->priv;
1306+ void *rx, *rssi;
1307+ int i;
1308+
1309+ mt7996_tm_set(phy->dev, SET_ID(BAND_IDX), mphy->band_idx);
1310+ mt7996_tm_get_rx_stats(phy);
1311+ mt7996_tm_get_tx_stats(phy);
1312+
1313+ rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX);
1314+ if (!rx)
1315+ return -ENOMEM;
1316+
1317+ if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset))
1318+ return -ENOMEM;
1319+
1320+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI);
1321+ if (!rssi)
1322+ return -ENOMEM;
1323+
1324+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++)
1325+ if (nla_put_u8(msg, i, phy->test.last_rcpi[i]))
1326+ return -ENOMEM;
1327+
1328+ nla_nest_end(msg, rssi);
1329+
1330+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RSSI);
1331+ if (!rssi)
1332+ return -ENOMEM;
1333+
1334+ for (i = 0; i < ARRAY_SIZE(phy->test.last_rssi); i++)
1335+ if (nla_put_s8(msg, i, phy->test.last_rssi[i]))
1336+ return -ENOMEM;
1337+
1338+ nla_nest_end(msg, rssi);
1339+
1340+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI);
1341+ if (!rssi)
1342+ return -ENOMEM;
1343+
1344+ for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++)
1345+ if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i]))
1346+ return -ENOMEM;
1347+
1348+ nla_nest_end(msg, rssi);
1349+
1350+ rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI);
1351+ if (!rssi)
1352+ return -ENOMEM;
1353+
1354+ for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++)
1355+ if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i]))
1356+ return -ENOMEM;
1357+
1358+ nla_nest_end(msg, rssi);
1359+
1360+ if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, phy->test.last_snr))
1361+ return -ENOMEM;
1362+
1363+ nla_nest_end(msg, rx);
1364+
1365+ return 0;
1366+}
1367+
1368+static int
1369+mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
1370+{
1371+ struct mt7996_mcu_eeprom_info req = {
1372+ .tag = cpu_to_le16(UNI_EFUSE_ACCESS),
1373+ .len = cpu_to_le16(sizeof(req) - 4),
1374+ };
1375+ u8 read_buf[MT76_TM_EEPROM_BLOCK_SIZE], *eeprom = dev->mt76.eeprom.data;
1376+ int i, ret = -EINVAL;
1377+
1378+ /* prevent from damaging chip id in efuse */
1379+ if (mt76_chip(&dev->mt76) != get_unaligned_le16(eeprom))
1380+ goto out;
1381+
1382+ for (i = 0; i < MT7996_EEPROM_SIZE; i += MT76_TM_EEPROM_BLOCK_SIZE) {
1383+ req.addr = cpu_to_le32(i);
1384+ memcpy(req.data, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
1385+
developerd0c89452024-10-11 16:53:27 +08001386+ ret = mt7996_mcu_get_eeprom(dev, i, read_buf, sizeof(read_buf));
developer66e89bc2024-04-23 14:50:01 +08001387+ if (ret < 0)
1388+ return ret;
1389+
1390+ if (!memcmp(req.data, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
1391+ continue;
1392+
1393+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
1394+ &req, sizeof(req), true);
1395+ if (ret)
1396+ return ret;
1397+ }
1398+
1399+out:
1400+ return ret;
1401+}
1402+
1403+static int
1404+mt7996_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action)
1405+{
1406+ struct mt7996_phy *phy = mphy->priv;
1407+ struct mt7996_dev *dev = phy->dev;
1408+ u8 *eeprom = dev->mt76.eeprom.data;
1409+ int ret = 0;
1410+
1411+ if (offset >= MT7996_EEPROM_SIZE)
1412+ return -EINVAL;
1413+
1414+ switch (action) {
1415+ case MT76_TM_EEPROM_ACTION_UPDATE_DATA:
1416+ memcpy(eeprom + offset, val, MT76_TM_EEPROM_BLOCK_SIZE);
1417+ break;
1418+ case MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE:
1419+ ret = mt7996_mcu_set_eeprom(dev);
1420+ break;
1421+ case MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE:
1422+ ret = mt7996_tm_write_back_to_efuse(dev);
1423+ break;
1424+ default:
1425+ break;
1426+ }
1427+
1428+ return ret;
1429+}
1430+
1431+const struct mt76_testmode_ops mt7996_testmode_ops = {
1432+ .set_state = mt7996_tm_set_state,
1433+ .set_params = mt7996_tm_set_params,
1434+ .dump_stats = mt7996_tm_dump_stats,
1435+ .reset_rx_stats = mt7996_tm_reset_trx_stats,
1436+ .tx_stop = mt7996_tm_tx_stop,
1437+ .set_eeprom = mt7996_tm_set_eeprom,
1438+};
1439diff --git a/mt7996/testmode.h b/mt7996/testmode.h
1440new file mode 100644
developer1f55fcf2024-10-17 14:52:33 +08001441index 0000000..319ef25
developer66e89bc2024-04-23 14:50:01 +08001442--- /dev/null
1443+++ b/mt7996/testmode.h
1444@@ -0,0 +1,299 @@
1445+/* SPDX-License-Identifier: ISC */
1446+/* Copyright (C) 2020 MediaTek Inc. */
1447+
1448+#ifndef __MT7996_TESTMODE_H
1449+#define __MT7996_TESTMODE_H
1450+
1451+enum {
1452+ TM_CBW_20MHZ,
1453+ TM_CBW_40MHZ,
1454+ TM_CBW_80MHZ,
1455+ TM_CBW_10MHZ,
1456+ TM_CBW_5MHZ,
1457+ TM_CBW_160MHZ,
1458+ TM_CBW_8080MHZ,
1459+ TM_CBW_320MHZ = 12,
1460+};
1461+
1462+/* BW defined in FW hal_cal_flow_rom.h */
1463+enum {
1464+ FW_CDBW_20MHZ,
1465+ FW_CDBW_40MHZ,
1466+ FW_CDBW_80MHZ,
1467+ FW_CDBW_160MHZ,
1468+ FW_CDBW_320MHZ,
1469+ FW_CDBW_5MHZ,
1470+ FW_CDBW_10MHZ,
1471+ FW_CDBW_8080MHZ,
1472+};
1473+
1474+enum bw_mapping_method {
1475+ BW_MAP_NL_TO_FW,
1476+ BW_MAP_NL_TO_TM,
1477+
1478+ NUM_BW_MAP,
1479+};
1480+
1481+struct mt7996_tm_rf_test {
1482+ __le16 tag;
1483+ __le16 len;
1484+
1485+ u8 action;
1486+ u8 icap_len;
1487+ u8 _rsv[2];
1488+ union {
1489+ __le32 op_mode;
1490+ __le32 freq;
1491+
1492+ struct {
1493+ __le32 func_idx;
1494+ union {
1495+ __le32 func_data;
1496+ __le32 cal_dump;
1497+
1498+ u8 _pad[80];
1499+ } param;
1500+ } rf;
1501+ } op;
1502+} __packed;
1503+
1504+struct mt7996_tm_req {
1505+ u8 _rsv[4];
1506+
1507+ struct mt7996_tm_rf_test rf_test;
1508+} __packed;
1509+
1510+struct mt7996_tm_rf_test_result {
1511+ __le32 func_idx;
1512+ __le32 payload_length;
1513+ u8 event[0];
1514+};
1515+
1516+struct mt7996_tm_event {
1517+ u8 _rsv[4];
1518+
1519+ __le16 tag;
1520+ __le16 len;
1521+ struct mt7996_tm_rf_test_result result;
1522+} __packed;
1523+
1524+enum {
1525+ RF_ACTION_SWITCH_TO_RF_TEST,
1526+ RF_ACTION_IN_RF_TEST,
1527+ RF_ACTION_SET = 3,
1528+ RF_ACTION_GET,
1529+};
1530+
1531+enum {
1532+ RF_OPER_NORMAL,
1533+ RF_OPER_RF_TEST,
1534+ RF_OPER_ICAP,
1535+ RF_OPER_ICAP_OVERLAP,
1536+ RF_OPER_WIFI_SPECTRUM,
1537+};
1538+
1539+enum {
1540+ UNI_RF_TEST_CTRL,
1541+};
1542+
1543+#define RF_CMD(cmd) RF_TEST_CMD_##cmd
1544+
1545+enum {
1546+ RF_TEST_CMD_STOP_TEST = 0,
1547+ RF_TEST_CMD_START_TX = 1,
1548+ RF_TEST_CMD_START_RX = 2,
1549+ RF_TEST_CMD_CONT_WAVE = 10,
1550+ RF_TEST_CMD_TX_COMMIT = 18,
1551+ RF_TEST_CMD_RX_COMMIT = 19,
1552+};
1553+
1554+#define SET_ID(id) RF_TEST_ID_SET_##id
1555+#define GET_ID(id) RF_TEST_ID_GET_##id
1556+
1557+enum {
1558+ RF_TEST_ID_SET_COMMAND = 1,
1559+ RF_TEST_ID_SET_POWER = 2,
1560+ RF_TEST_ID_SET_TX_RATE = 3,
1561+ RF_TEST_ID_SET_TX_MODE = 4,
1562+ RF_TEST_ID_SET_TX_LEN = 6,
1563+ RF_TEST_ID_SET_TX_COUNT = 7,
1564+ RF_TEST_ID_SET_IPG = 8,
1565+ RF_TEST_ID_SET_GI = 16,
1566+ RF_TEST_ID_SET_STBC = 17,
1567+ RF_TEST_ID_SET_CHAN_FREQ = 18,
1568+ RF_TEST_ID_GET_TXED_COUNT = 32,
1569+ RF_TEST_ID_SET_CONT_WAVE_MODE = 65,
1570+ RF_TEST_ID_SET_DA = 68,
1571+ RF_TEST_ID_SET_SA = 69,
1572+ RF_TEST_ID_SET_CBW = 71,
1573+ RF_TEST_ID_SET_DBW = 72,
1574+ RF_TEST_ID_SET_PRIMARY_CH = 73,
1575+ RF_TEST_ID_SET_ENCODE_MODE = 74,
1576+ RF_TEST_ID_SET_BAND = 90,
1577+ RF_TEST_ID_SET_TRX_COUNTER_RESET = 91,
1578+ RF_TEST_ID_SET_MAC_HEADER = 101,
1579+ RF_TEST_ID_SET_SEQ_CTRL = 102,
1580+ RF_TEST_ID_SET_PAYLOAD = 103,
1581+ RF_TEST_ID_SET_BAND_IDX = 104,
1582+ RF_TEST_ID_SET_RX_PATH = 106,
1583+ RF_TEST_ID_SET_FREQ_OFFSET = 107,
1584+ RF_TEST_ID_GET_FREQ_OFFSET = 108,
1585+ RF_TEST_ID_SET_TX_PATH = 113,
1586+ RF_TEST_ID_SET_NSS = 114,
1587+ RF_TEST_ID_SET_ANT_MASK = 115,
1588+ RF_TEST_ID_SET_IBF_ENABLE = 126,
1589+ RF_TEST_ID_SET_EBF_ENABLE = 127,
1590+ RF_TEST_ID_GET_TX_POWER = 136,
1591+ RF_TEST_ID_SET_RX_MU_AID = 157,
1592+ RF_TEST_ID_SET_HW_TX_MODE = 167,
1593+ RF_TEST_ID_SET_PUNCTURE = 168,
1594+ RF_TEST_ID_SET_FREQ_OFFSET_C2 = 171,
1595+ RF_TEST_ID_GET_FREQ_OFFSET_C2 = 172,
1596+ RF_TEST_ID_SET_CFG_ON = 176,
1597+ RF_TEST_ID_SET_CFG_OFF = 177,
1598+ RF_TEST_ID_SET_BSSID = 189,
1599+ RF_TEST_ID_SET_TX_TIME = 190,
1600+ RF_TEST_ID_SET_MAX_PE = 191,
1601+ RF_TEST_ID_SET_AID_OFFSET = 204,
1602+};
1603+
1604+#define POWER_CTRL(type) UNI_TXPOWER_##type##_CTRL
1605+
1606+struct mt7996_tm_rx_stat_user_ctrl {
1607+ __le16 tag;
1608+ __le16 len;
1609+
1610+ u8 band_idx;
1611+ u8 rsv;
1612+ __le16 user_idx;
1613+} __packed;
1614+
1615+struct mt7996_tm_rx_stat_all {
1616+ __le16 tag;
1617+ __le16 len;
1618+
1619+ u8 band_idx;
1620+ u8 rsv[3];
1621+} __packed;
1622+
1623+struct mt7996_tm_rx_req {
1624+ u8 band;
1625+ u8 _rsv[3];
1626+
1627+ union {
1628+ struct mt7996_tm_rx_stat_user_ctrl user_ctrl;
1629+ struct mt7996_tm_rx_stat_all rx_stat_all;
1630+ };
1631+} __packed;
1632+
1633+enum {
1634+ UNI_TM_RX_STAT_SET_USER_CTRL = 7,
1635+ UNI_TM_RX_STAT_GET_ALL_V2 = 9,
1636+};
1637+
1638+struct rx_band_info {
1639+ /* mac part */
1640+ __le16 mac_rx_fcs_err_cnt;
1641+ __le16 mac_rx_len_mismatch;
1642+ __le16 mac_rx_fcs_ok_cnt;
1643+ u8 rsv1[2];
1644+ __le32 mac_rx_mdrdy_cnt;
1645+
1646+ /* phy part */
1647+ __le16 phy_rx_fcs_err_cnt_cck;
1648+ __le16 phy_rx_fcs_err_cnt_ofdm;
1649+ __le16 phy_rx_pd_cck;
1650+ __le16 phy_rx_pd_ofdm;
1651+ __le16 phy_rx_sig_err_cck;
1652+ __le16 phy_rx_sfd_err_cck;
1653+ __le16 phy_rx_sig_err_ofdm;
1654+ __le16 phy_rx_tag_err_ofdm;
1655+ __le16 phy_rx_mdrdy_cnt_cck;
1656+ __le16 phy_rx_mdrdy_cnt_ofdm;
1657+} __packed;
1658+
1659+struct rx_band_info_ext {
1660+ /* mac part */
1661+ __le32 mac_rx_mpdu_cnt;
1662+
1663+ /* phy part */
1664+ u8 rsv[4];
1665+} __packed;
1666+
1667+struct rx_common_info {
1668+ __le16 rx_fifo_full;
1669+ u8 rsv[2];
1670+ __le32 aci_hit_low;
1671+ __le32 aci_hit_high;
1672+} __packed;
1673+
1674+struct rx_common_info_ext {
1675+ __le32 driver_rx_count;
1676+ __le32 sinr;
1677+ __le32 mu_pkt_count;
1678+
1679+ /* mac part */
1680+ u8 _rsv[4];
1681+
1682+ /* phy part */
1683+ u8 sig_mcs;
1684+ u8 rsv[3];
1685+} __packed;
1686+
1687+struct rx_rxv_info {
1688+ __le16 rcpi;
1689+ s16 rssi;
1690+ s16 snr;
1691+ s16 adc_rssi;
1692+} __packed;
1693+
1694+struct rx_rssi_info {
1695+ s8 ib_rssi;
1696+ s8 wb_rssi;
1697+ u8 rsv[2];
1698+} __packed;
1699+
1700+struct rx_user_info {
1701+ s32 freq_offset;
1702+ s32 snr;
1703+ __le32 fcs_err_count;
1704+} __packed;
1705+
1706+struct rx_user_info_ext {
1707+ s8 ne_var_db_all_user;
1708+ u8 rsv[3];
1709+} __packed;
1710+
1711+#define MAX_ANTENNA_NUM 8
1712+#define MAX_USER_NUM 16
1713+
1714+struct mt7996_tm_rx_event_stat_all {
1715+ __le16 tag;
1716+ __le16 len;
1717+
1718+ struct rx_band_info band_info;
1719+ struct rx_band_info_ext band_info_ext;
1720+ struct rx_common_info common_info;
1721+ struct rx_common_info_ext common_info_ext;
1722+
1723+ /* RXV info */
1724+ struct rx_rxv_info rxv_info[MAX_ANTENNA_NUM];
1725+
1726+ /* RSSI info */
1727+ struct rx_rssi_info fagc[MAX_ANTENNA_NUM];
1728+ struct rx_rssi_info inst[MAX_ANTENNA_NUM];
1729+
1730+ /* User info */
1731+ struct rx_user_info user_info[MAX_USER_NUM];
1732+ struct rx_user_info_ext user_info_ext[MAX_USER_NUM];
1733+} __packed;
1734+
1735+struct mt7996_tm_rx_event {
1736+ u8 _rsv[4];
1737+
1738+ union {
1739+ struct mt7996_tm_rx_event_stat_all rx_stat_all;
1740+ };
1741+} __packed;
1742+
1743+#endif
1744diff --git a/testmode.c b/testmode.c
developer1f55fcf2024-10-17 14:52:33 +08001745index ca4fecc..44f3a5b 100644
developer66e89bc2024-04-23 14:50:01 +08001746--- a/testmode.c
1747+++ b/testmode.c
1748@@ -2,11 +2,13 @@
1749 /* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
1750
1751 #include <linux/random.h>
1752+#include "mt76_connac.h"
1753 #include "mt76.h"
1754
1755 const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
1756 [MT76_TM_ATTR_RESET] = { .type = NLA_FLAG },
1757 [MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
1758+ [MT76_TM_ATTR_SKU_EN] = { .type = NLA_U8 },
1759 [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
1760 [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
1761 [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
1762@@ -82,6 +84,11 @@ mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode)
1763 IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991)
1764 return IEEE80211_MAX_MPDU_LEN_VHT_7991;
1765 return IEEE80211_MAX_MPDU_LEN_VHT_11454;
1766+ case MT76_TM_TX_MODE_EHT_SU:
1767+ case MT76_TM_TX_MODE_EHT_TRIG:
1768+ case MT76_TM_TX_MODE_EHT_MU:
1769+ /* TODO: check the limit */
1770+ return UINT_MAX;
1771 case MT76_TM_TX_MODE_CCK:
1772 case MT76_TM_TX_MODE_OFDM:
1773 default:
1774@@ -183,6 +190,9 @@ mt76_testmode_tx_init(struct mt76_phy *phy)
1775 u8 max_nss = hweight8(phy->antenna_mask);
1776 int ret;
1777
1778+ if (is_mt7996(phy->dev))
1779+ return 0;
1780+
1781 ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len);
1782 if (ret)
1783 return ret;
1784@@ -275,7 +285,9 @@ mt76_testmode_tx_start(struct mt76_phy *phy)
1785 td->tx_queued = 0;
1786 td->tx_done = 0;
1787 td->tx_pending = td->tx_count;
1788- mt76_worker_schedule(&dev->tx_worker);
1789+
1790+ if (!is_mt7996(dev))
1791+ mt76_worker_schedule(&dev->tx_worker);
1792 }
1793
1794 static void
1795@@ -284,6 +296,11 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
1796 struct mt76_testmode_data *td = &phy->test;
1797 struct mt76_dev *dev = phy->dev;
1798
1799+ if (is_mt7996(dev) && dev->test_ops->tx_stop) {
1800+ dev->test_ops->tx_stop(phy);
1801+ return;
1802+ }
1803+
1804 mt76_worker_disable(&dev->tx_worker);
1805
1806 td->tx_pending = 0;
1807@@ -296,22 +313,11 @@ mt76_testmode_tx_stop(struct mt76_phy *phy)
1808 mt76_testmode_free_skb(phy);
1809 }
1810
1811-static inline void
1812-mt76_testmode_param_set(struct mt76_testmode_data *td, u16 idx)
1813-{
1814- td->param_set[idx / 32] |= BIT(idx % 32);
1815-}
1816-
1817-static inline bool
1818-mt76_testmode_param_present(struct mt76_testmode_data *td, u16 idx)
1819-{
1820- return td->param_set[idx / 32] & BIT(idx % 32);
1821-}
1822-
1823 static void
1824 mt76_testmode_init_defaults(struct mt76_phy *phy)
1825 {
1826 struct mt76_testmode_data *td = &phy->test;
1827+ u8 addr[ETH_ALEN] = {phy->band_idx, 0x11, 0x22, 0xaa, 0xbb, 0xcc};
1828
1829 if (td->tx_mpdu_len > 0)
1830 return;
1831@@ -319,11 +325,18 @@ mt76_testmode_init_defaults(struct mt76_phy *phy)
1832 td->tx_mpdu_len = 1024;
1833 td->tx_count = 1;
1834 td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;
1835+ td->tx_rate_idx = 7;
1836 td->tx_rate_nss = 1;
1837+ /* 0xffff for OFDMA no puncture */
1838+ td->tx_preamble_puncture = ~(td->tx_preamble_puncture & 0);
1839+ td->tx_ipg = 50;
1840
1841- memcpy(td->addr[0], phy->macaddr, ETH_ALEN);
1842- memcpy(td->addr[1], phy->macaddr, ETH_ALEN);
1843- memcpy(td->addr[2], phy->macaddr, ETH_ALEN);
1844+ /* rx stat user config */
1845+ td->aid = 1;
1846+
1847+ memcpy(td->addr[0], addr, ETH_ALEN);
1848+ memcpy(td->addr[1], addr, ETH_ALEN);
1849+ memcpy(td->addr[2], addr, ETH_ALEN);
1850 }
1851
1852 static int
1853@@ -353,7 +366,7 @@ __mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state)
1854 if (state == MT76_TM_STATE_TX_FRAMES)
1855 mt76_testmode_tx_start(phy);
1856 else if (state == MT76_TM_STATE_RX_FRAMES) {
1857- memset(&phy->test.rx_stats, 0, sizeof(phy->test.rx_stats));
1858+ dev->test_ops->reset_rx_stats(phy);
1859 }
1860
1861 phy->test.state = state;
1862@@ -404,6 +417,44 @@ mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max)
1863 return 0;
1864 }
1865
1866+static int
1867+mt76_testmode_set_eeprom(struct mt76_phy *phy, struct nlattr **tb)
1868+{
1869+ struct mt76_dev *dev = phy->dev;
1870+ u8 action, val[MT76_TM_EEPROM_BLOCK_SIZE];
1871+ u32 offset = 0;
1872+ int err = -EINVAL;
1873+
1874+ if (!dev->test_ops->set_eeprom)
1875+ return -EOPNOTSUPP;
1876+
1877+ if (mt76_tm_get_u8(tb[MT76_TM_ATTR_EEPROM_ACTION], &action,
1878+ 0, MT76_TM_EEPROM_ACTION_MAX))
1879+ goto out;
1880+
1881+ if (tb[MT76_TM_ATTR_EEPROM_OFFSET]) {
1882+ struct nlattr *cur;
1883+ int rem, idx = 0;
1884+
1885+ offset = nla_get_u32(tb[MT76_TM_ATTR_EEPROM_OFFSET]);
1886+ if (!!(offset % MT76_TM_EEPROM_BLOCK_SIZE) ||
1887+ !tb[MT76_TM_ATTR_EEPROM_VAL])
1888+ goto out;
1889+
1890+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_EEPROM_VAL], rem) {
1891+ if (nla_len(cur) != 1 || idx >= ARRAY_SIZE(val))
1892+ goto out;
1893+
1894+ val[idx++] = nla_get_u8(cur);
1895+ }
1896+ }
1897+
1898+ err = dev->test_ops->set_eeprom(phy, offset, val, action);
1899+
1900+out:
1901+ return err;
1902+}
1903+
1904 int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1905 void *data, int len)
1906 {
1907@@ -427,6 +478,11 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1908
1909 mutex_lock(&dev->mutex);
1910
1911+ if (tb[MT76_TM_ATTR_EEPROM_ACTION]) {
1912+ err = mt76_testmode_set_eeprom(phy, tb);
1913+ goto out;
1914+ }
1915+
1916 if (tb[MT76_TM_ATTR_RESET]) {
1917 mt76_testmode_set_state(phy, MT76_TM_STATE_OFF);
1918 memset(td, 0, sizeof(*td));
1919@@ -434,6 +490,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1920
1921 mt76_testmode_init_defaults(phy);
1922
1923+ if (tb[MT76_TM_ATTR_SKU_EN])
1924+ td->sku_en = nla_get_u8(tb[MT76_TM_ATTR_SKU_EN]);
1925+
1926 if (tb[MT76_TM_ATTR_TX_COUNT])
1927 td->tx_count = nla_get_u32(tb[MT76_TM_ATTR_TX_COUNT]);
1928
1929@@ -454,7 +513,8 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1930 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE],
1931 &td->tx_duty_cycle, 0, 99) ||
1932 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
1933- &td->tx_power_control, 0, 1))
1934+ &td->tx_power_control, 0, 1) ||
1935+ mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16))
1936 goto out;
1937
1938 if (tb[MT76_TM_ATTR_TX_LENGTH]) {
1939@@ -494,7 +554,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1940 idx >= ARRAY_SIZE(td->tx_power))
1941 goto out;
1942
1943- td->tx_power[idx++] = nla_get_u8(cur);
1944+ err = mt76_tm_get_u8(cur, &td->tx_power[idx++], 0, 63);
1945+ if (err)
1946+ return err;
1947 }
1948 }
1949
1950@@ -512,6 +574,22 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
1951 }
1952 }
1953
1954+ if (tb[MT76_TM_ATTR_CFG]) {
1955+ struct nlattr *cur;
1956+ int rem, idx = 0;
1957+
1958+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_CFG], rem) {
1959+ if (nla_len(cur) != 1 || idx >= 2)
1960+ goto out;
1961+
1962+ if (idx == 0)
1963+ td->cfg.type = nla_get_u8(cur);
1964+ else
1965+ td->cfg.enable = nla_get_u8(cur);
1966+ idx++;
1967+ }
1968+ }
1969+
1970 if (dev->test_ops->set_params) {
1971 err = dev->test_ops->set_params(phy, tb, state);
1972 if (err)
1973@@ -561,6 +639,9 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg)
1974 nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets,
1975 MT76_TM_STATS_ATTR_PAD) ||
1976 nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error,
1977+ MT76_TM_STATS_ATTR_PAD) ||
1978+ nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_LEN_MISMATCH,
1979+ td->rx_stats.len_mismatch,
1980 MT76_TM_STATS_ATTR_PAD))
1981 return -EMSGSIZE;
1982
1983@@ -613,7 +694,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
1984
1985 if (dev->test_mtd.name &&
1986 (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) ||
1987- nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset)))
1988+ nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset) ||
1989+ nla_put_u8(msg, MT76_TM_ATTR_BAND_IDX, phy->band_idx)))
1990 goto out;
1991
1992 if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
1993@@ -624,6 +706,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
1994 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
1995 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||
1996 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
1997+ nla_put_u8(msg, MT76_TM_ATTR_SKU_EN, td->sku_en) ||
1998+ nla_put_u8(msg, MT76_TM_ATTR_AID, td->aid) ||
1999 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
2000 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
2001 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
2002@@ -639,7 +723,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
2003 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&
2004 nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) ||
2005 (mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) &&
2006- nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset)))
2007+ nla_put_u32(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset)))
2008 goto out;
2009
2010 if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) {
2011diff --git a/testmode.h b/testmode.h
developer1f55fcf2024-10-17 14:52:33 +08002012index 1b0bcae..2873c90 100644
developer66e89bc2024-04-23 14:50:01 +08002013--- a/testmode.h
2014+++ b/testmode.h
2015@@ -5,7 +5,8 @@
2016 #ifndef __MT76_TESTMODE_H
2017 #define __MT76_TESTMODE_H
2018
2019-#define MT76_TM_TIMEOUT 10
2020+#define MT76_TM_TIMEOUT 10
2021+#define MT76_TM_EEPROM_BLOCK_SIZE 16
2022
2023 /**
2024 * enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA
2025@@ -17,7 +18,9 @@
2026 *
2027 * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string)
2028 * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
2029+ * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
2030 *
2031+ * @MT76_TM_ATTR_SKU_EN: config txpower sku is enabled or disabled in testmode (u8)
2032 * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
2033 * state to MT76_TM_STATE_TX_FRAMES (u32)
2034 * @MT76_TM_ATTR_TX_PENDING: pending frames during MT76_TM_STATE_TX_FRAMES (u32)
2035@@ -38,6 +41,11 @@
2036 *
2037 * @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr)
2038 *
2039+ * @MT76_TM_ATTR_PRECAL: Pre-cal data (u8)
2040+ * @MT76_TM_ATTR_PRECAL_INFO: group size, dpd size, dpd_info, transmit size,
2041+ * eeprom cal indicator (u32),
2042+ * dpd_info = [dpd_per_chan_size, chan_num_2g,
2043+ * chan_num_5g, chan_num_6g]
2044 * @MT76_TM_ATTR_TX_SPE_IDX: tx spatial extension index (u8)
2045 *
2046 * @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8)
2047@@ -47,6 +55,29 @@
2048 * @MT76_TM_ATTR_DRV_DATA: driver specific netlink attrs (nested)
2049 *
2050 * @MT76_TM_ATTR_MAC_ADDRS: array of nested MAC addresses (nested)
2051+ *
2052+ * @MT76_TM_ATTR_EEPROM_ACTION: eeprom setting actions
2053+ * (u8, see &enum mt76_testmode_eeprom_action)
2054+ * @MT76_TM_ATTR_EEPROM_OFFSET: offset of eeprom data block for writing (u32)
2055+ * @MT76_TM_ATTR_EEPROM_VAL: values for writing into a 16-byte data block
2056+ * (nested, u8 attrs)
2057+ *
2058+ * @MT76_TM_ATTR_CFG: config testmode rf feature (nested, see &mt76_testmode_cfg)
2059+ * @MT76_TM_ATTR_TXBF_ACT: txbf setting actions (u8)
2060+ * @MT76_TM_ATTR_TXBF_PARAM: txbf parameters (nested)
2061+ *
2062+ * @MT76_TM_ATTR_OFF_CH_SCAN_CH: config the channel of background chain (ZWDFS) (u8)
2063+ * @MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH: config the center channel of background chain (ZWDFS) (u8)
2064+ * @MT76_TM_ATTR_OFF_CH_SCAN_BW: config the bandwidth of background chain (ZWDFS) (u8)
2065+ * @MT76_TM_ATTR_OFF_CH_SCAN_PATH: config the tx path of background chain (ZWDFS) (u8)
2066+ *
2067+ * @MT76_TM_ATTR_IPI_THRESHOLD: config the IPI index you want to read (u8)
2068+ * @MT76_TM_ATTR_IPI_PERIOD: config the time period for reading
2069+ * the histogram of specific IPI index (u8)
2070+ * @MT76_TM_ATTR_IPI_ANTENNA_INDEX: config the antenna index for reading
2071+ * the histogram of specific IPI index (u8)
2072+ * @MT76_TM_ATTR_IPI_RESET: Reset the IPI counter
2073+ *
2074 */
2075 enum mt76_testmode_attr {
2076 MT76_TM_ATTR_UNSPEC,
2077@@ -56,7 +87,9 @@ enum mt76_testmode_attr {
2078
2079 MT76_TM_ATTR_MTD_PART,
2080 MT76_TM_ATTR_MTD_OFFSET,
2081+ MT76_TM_ATTR_BAND_IDX,
2082
2083+ MT76_TM_ATTR_SKU_EN,
2084 MT76_TM_ATTR_TX_COUNT,
2085 MT76_TM_ATTR_TX_LENGTH,
2086 MT76_TM_ATTR_TX_RATE_MODE,
2087@@ -74,6 +107,8 @@ enum mt76_testmode_attr {
2088 MT76_TM_ATTR_FREQ_OFFSET,
2089
2090 MT76_TM_ATTR_STATS,
2091+ MT76_TM_ATTR_PRECAL,
2092+ MT76_TM_ATTR_PRECAL_INFO,
2093
2094 MT76_TM_ATTR_TX_SPE_IDX,
2095
2096@@ -84,6 +119,27 @@ enum mt76_testmode_attr {
2097 MT76_TM_ATTR_DRV_DATA,
2098
2099 MT76_TM_ATTR_MAC_ADDRS,
2100+ MT76_TM_ATTR_AID,
2101+ MT76_TM_ATTR_RU_ALLOC,
2102+ MT76_TM_ATTR_RU_IDX,
2103+
2104+ MT76_TM_ATTR_EEPROM_ACTION,
2105+ MT76_TM_ATTR_EEPROM_OFFSET,
2106+ MT76_TM_ATTR_EEPROM_VAL,
2107+
2108+ MT76_TM_ATTR_CFG,
2109+ MT76_TM_ATTR_TXBF_ACT,
2110+ MT76_TM_ATTR_TXBF_PARAM,
2111+
2112+ MT76_TM_ATTR_OFF_CH_SCAN_CH,
2113+ MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
2114+ MT76_TM_ATTR_OFF_CH_SCAN_BW,
2115+ MT76_TM_ATTR_OFF_CH_SCAN_PATH,
2116+
2117+ MT76_TM_ATTR_IPI_THRESHOLD,
2118+ MT76_TM_ATTR_IPI_PERIOD,
2119+ MT76_TM_ATTR_IPI_ANTENNA_INDEX,
2120+ MT76_TM_ATTR_IPI_RESET,
2121
2122 /* keep last */
2123 NUM_MT76_TM_ATTRS,
2124@@ -101,6 +157,8 @@ enum mt76_testmode_attr {
2125 * @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64)
2126 * @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet
2127 * see &enum mt76_testmode_rx_attr
2128+ * @MT76_TM_STATS_ATTR_RX_LEN_MISMATCH: number of rx packets with length
2129+ * mismatch error (u64)
2130 */
2131 enum mt76_testmode_stats_attr {
2132 MT76_TM_STATS_ATTR_UNSPEC,
2133@@ -113,6 +171,7 @@ enum mt76_testmode_stats_attr {
2134 MT76_TM_STATS_ATTR_RX_PACKETS,
2135 MT76_TM_STATS_ATTR_RX_FCS_ERROR,
2136 MT76_TM_STATS_ATTR_LAST_RX,
2137+ MT76_TM_STATS_ATTR_RX_LEN_MISMATCH,
2138
2139 /* keep last */
2140 NUM_MT76_TM_STATS_ATTRS,
2141@@ -125,6 +184,7 @@ enum mt76_testmode_stats_attr {
2142 *
2143 * @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32)
2144 * @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8)
2145+ * @MT76_TM_RX_ATTR_RSSI: received signal strength indicator (array, s8)
2146 * @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (array, s8)
2147 * @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (array, s8)
2148 * @MT76_TM_RX_ATTR_SNR: signal-to-noise ratio (u8)
2149@@ -134,6 +194,7 @@ enum mt76_testmode_rx_attr {
2150
2151 MT76_TM_RX_ATTR_FREQ_OFFSET,
2152 MT76_TM_RX_ATTR_RCPI,
2153+ MT76_TM_RX_ATTR_RSSI,
2154 MT76_TM_RX_ATTR_IB_RSSI,
2155 MT76_TM_RX_ATTR_WB_RSSI,
2156 MT76_TM_RX_ATTR_SNR,
2157@@ -177,6 +238,9 @@ enum mt76_testmode_state {
2158 * @MT76_TM_TX_MODE_HE_EXT_SU: 802.11ax extended-range SU
2159 * @MT76_TM_TX_MODE_HE_TB: 802.11ax trigger-based
2160 * @MT76_TM_TX_MODE_HE_MU: 802.11ax multi-user MIMO
2161+ * @MT76_TM_TX_MODE_EHT_SU: 802.11be single-user MIMO
2162+ * @MT76_TM_TX_MODE_EHT_TRIG: 802.11be trigger-based
2163+ * @MT76_TM_TX_MODE_EHT_MU: 802.11be multi-user MIMO
2164 */
2165 enum mt76_testmode_tx_mode {
2166 MT76_TM_TX_MODE_CCK,
developerd0c89452024-10-11 16:53:27 +08002167@@ -187,10 +251,31 @@ enum mt76_testmode_tx_mode {
developer66e89bc2024-04-23 14:50:01 +08002168 MT76_TM_TX_MODE_HE_EXT_SU,
2169 MT76_TM_TX_MODE_HE_TB,
2170 MT76_TM_TX_MODE_HE_MU,
2171+ MT76_TM_TX_MODE_EHT_SU,
2172+ MT76_TM_TX_MODE_EHT_TRIG,
2173+ MT76_TM_TX_MODE_EHT_MU,
2174
2175 /* keep last */
2176 NUM_MT76_TM_TX_MODES,
2177 MT76_TM_TX_MODE_MAX = NUM_MT76_TM_TX_MODES - 1,
2178 };
2179
2180+/**
2181+ * enum mt76_testmode_eeprom_action - eeprom setting actions
2182+ *
2183+ * @MT76_TM_EEPROM_ACTION_UPDATE_DATA: update rf values to specific
2184+ * eeprom data block
2185+ * @MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE: send updated eeprom data to fw
2186+ * @MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE: write eeprom data back to efuse
2187+ */
2188+enum mt76_testmode_eeprom_action {
2189+ MT76_TM_EEPROM_ACTION_UPDATE_DATA,
2190+ MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE,
2191+ MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE,
2192+
2193+ /* keep last */
2194+ NUM_MT76_TM_EEPROM_ACTION,
2195+ MT76_TM_EEPROM_ACTION_MAX = NUM_MT76_TM_EEPROM_ACTION - 1,
2196+};
2197+
developer66e89bc2024-04-23 14:50:01 +08002198 #endif
2199diff --git a/tools/fields.c b/tools/fields.c
developer1f55fcf2024-10-17 14:52:33 +08002200index e3f6908..055f90f 100644
developer66e89bc2024-04-23 14:50:01 +08002201--- a/tools/fields.c
2202+++ b/tools/fields.c
2203@@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
2204 [MT76_TM_STATE_IDLE] = "idle",
2205 [MT76_TM_STATE_TX_FRAMES] = "tx_frames",
2206 [MT76_TM_STATE_RX_FRAMES] = "rx_frames",
2207+ [MT76_TM_STATE_TX_CONT] = "tx_cont",
2208 };
2209
2210 static const char * const testmode_tx_mode[] = {
2211@@ -21,6 +22,9 @@ static const char * const testmode_tx_mode[] = {
2212 [MT76_TM_TX_MODE_HE_EXT_SU] = "he_ext_su",
2213 [MT76_TM_TX_MODE_HE_TB] = "he_tb",
2214 [MT76_TM_TX_MODE_HE_MU] = "he_mu",
2215+ [MT76_TM_TX_MODE_EHT_SU] = "eht_su",
2216+ [MT76_TM_TX_MODE_EHT_TRIG] = "eht_tb",
2217+ [MT76_TM_TX_MODE_EHT_MU] = "eht_mu",
2218 };
2219
2220 static void print_enum(const struct tm_field *field, struct nlattr *attr)
2221@@ -65,7 +69,7 @@ static bool parse_u8(const struct tm_field *field, int idx,
2222
2223 static void print_u8(const struct tm_field *field, struct nlattr *attr)
2224 {
2225- printf("%d", nla_get_u8(attr));
2226+ printf("%u", nla_get_u8(attr));
2227 }
2228
2229 static void print_s8(const struct tm_field *field, struct nlattr *attr)
2230@@ -86,12 +90,12 @@ static void print_s32(const struct tm_field *field, struct nlattr *attr)
2231
2232 static void print_u32(const struct tm_field *field, struct nlattr *attr)
2233 {
2234- printf("%d", nla_get_u32(attr));
2235+ printf("%u", nla_get_u32(attr));
2236 }
2237
2238 static void print_u64(const struct tm_field *field, struct nlattr *attr)
2239 {
2240- printf("%lld", (unsigned long long)nla_get_u64(attr));
2241+ printf("%llu", (unsigned long long)nla_get_u64(attr));
2242 }
2243
2244 static bool parse_flag(const struct tm_field *field, int idx,
2245@@ -201,6 +205,62 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb)
2246 printf("%srx_per=%.02f%%\n", prefix, 100 * failed / total);
2247 }
2248
2249+static bool parse_mac(const struct tm_field *field, int idx,
2250+ struct nl_msg *msg, const char *val)
2251+{
2252+#define ETH_ALEN 6
2253+ bool ret = true;
2254+ char *str, *cur, *ap;
2255+ void *a;
2256+
2257+ str = strdup(val);
2258+ ap = str;
2259+
2260+ a = nla_nest_start(msg, idx);
2261+
2262+ idx = 0;
2263+ while ((cur = strsep(&ap, ",")) != NULL) {
2264+ unsigned char addr[ETH_ALEN];
2265+ char *val, *tmp = cur;
2266+ int i = 0;
2267+
2268+ while ((val = strsep(&tmp, ":")) != NULL) {
2269+ if (i >= ETH_ALEN)
2270+ break;
2271+
2272+ addr[i++] = strtoul(val, NULL, 16);
2273+ }
2274+
2275+ nla_put(msg, idx, ETH_ALEN, addr);
2276+
2277+ idx++;
2278+ }
2279+
2280+ nla_nest_end(msg, a);
2281+
2282+ free(str);
2283+
2284+ return ret;
2285+}
2286+
2287+static void print_mac(const struct tm_field *field, struct nlattr *attr)
2288+{
2289+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
2290+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
2291+ unsigned char addr[3][6];
2292+ struct nlattr *cur;
2293+ int idx = 0;
2294+ int rem;
2295+
2296+ nla_for_each_nested(cur, attr, rem) {
2297+ if (nla_len(cur) != 6)
2298+ continue;
2299+ memcpy(addr[idx++], nla_data(cur), 6);
2300+ }
2301+
2302+ printf("" MACSTR "," MACSTR "," MACSTR "",
2303+ MAC2STR(addr[0]), MAC2STR(addr[1]), MAC2STR(addr[2]));
2304+}
2305
2306 #define FIELD_GENERIC(_field, _name, ...) \
2307 [FIELD_NAME(_field)] = { \
2308@@ -250,10 +310,18 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb)
2309 ##__VA_ARGS__ \
2310 )
2311
2312+#define FIELD_MAC(_field, _name) \
2313+ [FIELD_NAME(_field)] = { \
2314+ .name = _name, \
2315+ .parse = parse_mac, \
2316+ .print = print_mac \
2317+ }
2318+
2319 #define FIELD_NAME(_field) MT76_TM_RX_ATTR_##_field
2320 static const struct tm_field rx_fields[NUM_MT76_TM_RX_ATTRS] = {
2321 FIELD_RO(s32, FREQ_OFFSET, "freq_offset"),
2322 FIELD_ARRAY_RO(u8, RCPI, "rcpi"),
2323+ FIELD_ARRAY_RO(s8, RSSI, "rssi"),
2324 FIELD_ARRAY_RO(s8, IB_RSSI, "ib_rssi"),
2325 FIELD_ARRAY_RO(s8, WB_RSSI, "wb_rssi"),
2326 FIELD_RO(s8, SNR, "snr"),
2327@@ -261,6 +329,7 @@ static const struct tm_field rx_fields[NUM_MT76_TM_RX_ATTRS] = {
2328 static struct nla_policy rx_policy[NUM_MT76_TM_RX_ATTRS] = {
2329 [MT76_TM_RX_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
2330 [MT76_TM_RX_ATTR_RCPI] = { .type = NLA_NESTED },
2331+ [MT76_TM_RX_ATTR_RSSI] = { .type = NLA_NESTED },
2332 [MT76_TM_RX_ATTR_IB_RSSI] = { .type = NLA_NESTED },
2333 [MT76_TM_RX_ATTR_WB_RSSI] = { .type = NLA_NESTED },
2334 [MT76_TM_RX_ATTR_SNR] = { .type = NLA_U8 },
2335@@ -274,6 +343,7 @@ static const struct tm_field stats_fields[NUM_MT76_TM_STATS_ATTRS] = {
2336 FIELD_RO(u32, TX_DONE, "tx_done"),
2337 FIELD_RO(u64, RX_PACKETS, "rx_packets"),
2338 FIELD_RO(u64, RX_FCS_ERROR, "rx_fcs_error"),
2339+ FIELD_RO(u64, RX_LEN_MISMATCH, "rx_len_mismatch"),
2340 FIELD_NESTED_RO(LAST_RX, rx, "last_"),
2341 };
2342 static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
2343@@ -282,6 +352,7 @@ static struct nla_policy stats_policy[NUM_MT76_TM_STATS_ATTRS] = {
2344 [MT76_TM_STATS_ATTR_TX_DONE] = { .type = NLA_U32 },
2345 [MT76_TM_STATS_ATTR_RX_PACKETS] = { .type = NLA_U64 },
2346 [MT76_TM_STATS_ATTR_RX_FCS_ERROR] = { .type = NLA_U64 },
2347+ [MT76_TM_STATS_ATTR_RX_LEN_MISMATCH] = { .type = NLA_U64 },
2348 };
2349 #undef FIELD_NAME
2350
2351@@ -291,6 +362,7 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
2352 FIELD_ENUM(STATE, "state", testmode_state),
2353 FIELD_RO(string, MTD_PART, "mtd_part"),
2354 FIELD_RO(u32, MTD_OFFSET, "mtd_offset"),
2355+ FIELD(u8, SKU_EN, "sku_en"),
2356 FIELD(u32, TX_COUNT, "tx_count"),
2357 FIELD(u32, TX_LENGTH, "tx_length"),
2358 FIELD_ENUM(TX_RATE_MODE, "tx_rate_mode", testmode_tx_mode),
2359@@ -300,12 +372,20 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
2360 FIELD(u8, TX_RATE_LDPC, "tx_rate_ldpc"),
2361 FIELD(u8, TX_RATE_STBC, "tx_rate_stbc"),
2362 FIELD(u8, TX_LTF, "tx_ltf"),
2363+ FIELD(u8, TX_DUTY_CYCLE, "tx_duty_cycle"),
2364+ FIELD(u32, TX_IPG, "tx_ipg"),
2365+ FIELD(u32, TX_TIME, "tx_time"),
2366 FIELD(u8, TX_POWER_CONTROL, "tx_power_control"),
2367 FIELD_ARRAY(u8, TX_POWER, "tx_power"),
2368 FIELD(u8, TX_ANTENNA, "tx_antenna"),
2369 FIELD(u32, FREQ_OFFSET, "freq_offset"),
2370+ FIELD(u8, AID, "aid"),
2371+ FIELD(u8, RU_ALLOC, "ru_alloc"),
2372+ FIELD(u8, RU_IDX, "ru_idx"),
2373+ FIELD_MAC(MAC_ADDRS, "mac_addrs"),
2374 FIELD_NESTED_RO(STATS, stats, "",
2375 .print_extra = print_extra_stats),
2376+
2377 };
2378 #undef FIELD_NAME
2379
2380@@ -313,6 +393,7 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
2381 [MT76_TM_ATTR_STATE] = { .type = NLA_U8 },
2382 [MT76_TM_ATTR_MTD_PART] = { .type = NLA_STRING },
2383 [MT76_TM_ATTR_MTD_OFFSET] = { .type = NLA_U32 },
2384+ [MT76_TM_ATTR_SKU_EN] = { .type = NLA_U8 },
2385 [MT76_TM_ATTR_TX_COUNT] = { .type = NLA_U32 },
2386 [MT76_TM_ATTR_TX_LENGTH] = { .type = NLA_U32 },
2387 [MT76_TM_ATTR_TX_RATE_MODE] = { .type = NLA_U8 },
2388@@ -322,10 +403,25 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
2389 [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 },
2390 [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 },
2391 [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 },
2392+ [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 },
2393+ [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 },
2394+ [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
2395 [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 },
2396 [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 },
2397+ [MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 },
2398 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
2399+ [MT76_TM_ATTR_AID] = { .type = NLA_U8 },
2400+ [MT76_TM_ATTR_RU_ALLOC] = { .type = NLA_U8 },
2401+ [MT76_TM_ATTR_RU_IDX] = { .type = NLA_U8 },
2402 [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED },
2403+ [MT76_TM_ATTR_TXBF_ACT] = { .type = NLA_U8 },
2404+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
2405+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
2406+ [MT76_TM_ATTR_OFF_CH_SCAN_BW] = { .type = NLA_U8 },
2407+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
2408+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
2409+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
2410+ [MT76_TM_ATTR_IPI_RESET] = { .type = NLA_U8 },
2411 };
2412
2413 const struct tm_field msg_field = {
2414--
developerd0c89452024-10-11 16:53:27 +080024152.45.2
developer66e89bc2024-04-23 14:50:01 +08002416