blob: 317894641c2e2fdc205653701412288356de185b [file] [log] [blame]
developerd0c89452024-10-11 16:53:27 +08001From 0ae2d7c2cf18d4ca07b05c7ea14fc0c2ea9e5ad7 Mon Sep 17 00:00:00 2001
developer66e89bc2024-04-23 14:50:01 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Wed, 22 Mar 2023 11:19:52 +0800
developerd0c89452024-10-11 16:53:27 +08004Subject: [PATCH 021/223] mtk: mt76: mt7996: add testmode ZWDFS verification
developer05f3b2b2024-08-19 19:17:34 +08005 support
developer66e89bc2024-04-23 14:50:01 +08006
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8---
9 mt76.h | 8 ++
10 mt7996/mt7996.h | 1 +
11 mt7996/testmode.c | 248 ++++++++++++++++++++++++++++++++++++++++++++--
12 mt7996/testmode.h | 44 ++++++++
13 testmode.c | 22 +++-
14 tools/fields.c | 15 +++
15 6 files changed, 326 insertions(+), 12 deletions(-)
16
17diff --git a/mt76.h b/mt76.h
developerd0c89452024-10-11 16:53:27 +080018index 924f273b..2805d758 100644
developer66e89bc2024-04-23 14:50:01 +080019--- a/mt76.h
20+++ b/mt76.h
developerd0c89452024-10-11 16:53:27 +080021@@ -801,6 +801,14 @@ struct mt76_testmode_data {
developer66e89bc2024-04-23 14:50:01 +080022 } cfg;
23
24 u8 aid;
25+
26+ u8 offchan_ch;
27+ u8 offchan_center_ch;
28+ u8 offchan_bw;
29+
30+ u8 ipi_threshold;
31+ u32 ipi_period;
32+ u8 ipi_reset;
33 };
34
35 struct mt76_vif {
36diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +080037index efb4e74c..1fe681cf 100644
developer66e89bc2024-04-23 14:50:01 +080038--- a/mt7996/mt7996.h
39+++ b/mt7996/mt7996.h
developerd0c89452024-10-11 16:53:27 +080040@@ -297,6 +297,7 @@ struct mt7996_phy {
developer66e89bc2024-04-23 14:50:01 +080041
42 struct mt76_mib_stats mib;
43 struct mt76_channel_state state_ts;
44+ struct delayed_work ipi_work;
45
46 bool has_aux_rx;
47
48diff --git a/mt7996/testmode.c b/mt7996/testmode.c
developerd0c89452024-10-11 16:53:27 +080049index 6969cba6..c4874eb3 100644
developer66e89bc2024-04-23 14:50:01 +080050--- a/mt7996/testmode.c
51+++ b/mt7996/testmode.c
52@@ -17,6 +17,12 @@ enum {
53 TM_CHANGED_TX_LENGTH,
54 TM_CHANGED_TX_TIME,
55 TM_CHANGED_CFG,
56+ TM_CHANGED_OFF_CHAN_CH,
57+ TM_CHANGED_OFF_CHAN_CENTER_CH,
58+ TM_CHANGED_OFF_CHAN_BW,
59+ TM_CHANGED_IPI_THRESHOLD,
60+ TM_CHANGED_IPI_PERIOD,
61+ TM_CHANGED_IPI_RESET,
62
63 /* must be last */
64 NUM_TM_CHANGED
65@@ -29,20 +35,31 @@ static const u8 tm_change_map[] = {
66 [TM_CHANGED_TX_LENGTH] = MT76_TM_ATTR_TX_LENGTH,
67 [TM_CHANGED_TX_TIME] = MT76_TM_ATTR_TX_TIME,
68 [TM_CHANGED_CFG] = MT76_TM_ATTR_CFG,
69+ [TM_CHANGED_OFF_CHAN_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CH,
70+ [TM_CHANGED_OFF_CHAN_CENTER_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
71+ [TM_CHANGED_OFF_CHAN_BW] = MT76_TM_ATTR_OFF_CH_SCAN_BW,
72+ [TM_CHANGED_IPI_THRESHOLD] = MT76_TM_ATTR_IPI_THRESHOLD,
73+ [TM_CHANGED_IPI_PERIOD] = MT76_TM_ATTR_IPI_PERIOD,
74+ [TM_CHANGED_IPI_RESET] = MT76_TM_ATTR_IPI_RESET,
75 };
76
77-static u8 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_method method)
78+static void mt7996_tm_ipi_work(struct work_struct *work);
79+
80+static u32 mt7996_tm_bw_mapping(enum nl80211_chan_width width, enum bw_mapping_method method)
81 {
82- static const u8 width_to_bw[][NUM_BW_MAP] = {
83- [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ},
84- [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ},
85- [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ},
86- [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ},
87- [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ},
88- [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ},
89- [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
90- [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ},
91- [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ},
92+ static const u32 width_to_bw[][NUM_BW_MAP] = {
93+ [NL80211_CHAN_WIDTH_40] = {FW_CDBW_40MHZ, TM_CBW_40MHZ, 40,
94+ FIRST_CONTROL_CHAN_BITMAP_BW40},
95+ [NL80211_CHAN_WIDTH_80] = {FW_CDBW_80MHZ, TM_CBW_80MHZ, 80,
96+ FIRST_CONTROL_CHAN_BITMAP_BW80},
97+ [NL80211_CHAN_WIDTH_80P80] = {FW_CDBW_8080MHZ, TM_CBW_8080MHZ, 80, 0x0},
98+ [NL80211_CHAN_WIDTH_160] = {FW_CDBW_160MHZ, TM_CBW_160MHZ, 160,
99+ FIRST_CONTROL_CHAN_BITMAP_BW160},
100+ [NL80211_CHAN_WIDTH_5] = {FW_CDBW_5MHZ, TM_CBW_5MHZ, 5, 0x0},
101+ [NL80211_CHAN_WIDTH_10] = {FW_CDBW_10MHZ, TM_CBW_10MHZ, 10, 0x0},
102+ [NL80211_CHAN_WIDTH_20] = {FW_CDBW_20MHZ, TM_CBW_20MHZ, 20, 0x0},
103+ [NL80211_CHAN_WIDTH_20_NOHT] = {FW_CDBW_20MHZ, TM_CBW_20MHZ, 20, 0x0},
104+ [NL80211_CHAN_WIDTH_320] = {FW_CDBW_320MHZ, TM_CBW_320MHZ, 320, 0x0},
105 };
106
107 if (width >= ARRAY_SIZE(width_to_bw))
108@@ -217,6 +234,9 @@ mt7996_tm_init(struct mt7996_phy *phy, bool en)
109
110 /* use firmware counter for RX stats */
111 phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
112+
113+ if (en)
114+ INIT_DELAYED_WORK(&phy->ipi_work, mt7996_tm_ipi_work);
115 }
116
117 static void
118@@ -829,6 +849,204 @@ void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb)
119 }
120 }
121
122+static u8
123+mt7996_tm_get_center_chan(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef)
124+{
125+ struct mt76_phy *mphy = phy->mt76;
126+ const struct ieee80211_channel *chan = mphy->sband_5g.sband.channels;
127+ u32 bitmap, i, offset, width_mhz, size = mphy->sband_5g.sband.n_channels;
128+ u16 first_control = 0, control_chan = chandef->chan->hw_value;
129+
130+ bitmap = mt7996_tm_bw_mapping(chandef->width, BW_MAP_NL_TO_CONTROL_BITMAP_5G);
131+ if (!bitmap)
132+ return control_chan;
133+
134+ width_mhz = mt7996_tm_bw_mapping(chandef->width, BW_MAP_NL_TO_MHZ);
135+ offset = width_mhz / 10 - 2;
136+
137+ for (i = 0; i < size; i++) {
138+ if (!((1 << i) & bitmap))
139+ continue;
140+
141+ if (control_chan >= chan[i].hw_value)
142+ first_control = chan[i].hw_value;
143+ else
144+ break;
145+ }
146+
147+ if (i == size || first_control == 0)
148+ return control_chan;
149+
150+ return first_control + offset;
151+}
152+
153+static int
154+mt7996_tm_set_offchan(struct mt7996_phy *phy, bool no_center)
155+{
156+ struct mt76_phy *mphy = phy->mt76;
157+ struct mt7996_dev *dev = phy->dev;
158+ struct ieee80211_hw *hw = mphy->hw;
159+ struct mt76_testmode_data *td = &phy->mt76->test;
160+ struct cfg80211_chan_def chandef = {};
161+ struct ieee80211_channel *chan;
162+ int ret, freq = ieee80211_channel_to_frequency(td->offchan_ch, NL80211_BAND_5GHZ);
163+
164+ if (!mphy->cap.has_5ghz || !freq) {
165+ ret = -EINVAL;
166+ dev_info(dev->mt76.dev, "Failed to set offchan (invalid band or channel)!\n");
167+ goto out;
168+ }
169+
170+ chandef.width = td->offchan_bw;
171+ chan = ieee80211_get_channel(hw->wiphy, freq);
172+ chandef.chan = chan;
173+ if (no_center)
174+ td->offchan_center_ch = mt7996_tm_get_center_chan(phy, &chandef);
175+ chandef.center_freq1 = ieee80211_channel_to_frequency(td->offchan_center_ch,
176+ NL80211_BAND_5GHZ);
177+ if (!cfg80211_chandef_valid(&chandef)) {
178+ ret = -EINVAL;
179+ dev_info(dev->mt76.dev, "Failed to set offchan, chandef is invalid!\n");
180+ goto out;
181+ }
182+
183+ memset(&dev->rdd2_chandef, 0, sizeof(struct cfg80211_chan_def));
184+
185+ ret = mt7996_mcu_rdd_background_enable(phy, &chandef);
186+
187+ if (ret)
188+ goto out;
189+
190+ dev->rdd2_phy = phy;
191+ dev->rdd2_chandef = chandef;
192+
193+ return 0;
194+
195+out:
196+ td->offchan_ch = 0;
197+ td->offchan_center_ch = 0;
198+ td->offchan_bw = 0;
199+
200+ return ret;
201+}
202+
203+static void
204+mt7996_tm_ipi_hist_ctrl(struct mt7996_phy *phy, struct mt7996_tm_rdd_ipi_ctrl *data, u8 cmd)
205+{
206+#define MT_IPI_RESET 0x830a5dfc
207+#define MT_IPI_RESET_MASK BIT(28)
208+#define MT_IPI_COUNTER_BASE 0x83041000
209+#define MT_IPI_COUNTER(idx) (MT_IPI_COUNTER_BASE + ((idx) * 4))
210+ struct mt7996_dev *dev = phy->dev;
211+ bool val;
212+ int i;
213+
214+ if (cmd == RDD_SET_IPI_HIST_RESET) {
215+ val = mt76_rr(dev, MT_IPI_RESET) & MT_IPI_RESET_MASK;
216+ mt76_rmw_field(dev, MT_IPI_RESET, MT_IPI_RESET_MASK, !val);
217+ return;
218+ }
219+
220+ for (i = 0; i < POWER_INDICATE_HIST_MAX; i++)
221+ data->ipi_hist_val[i] = mt76_rr(dev, MT_IPI_COUNTER(i));
222+}
223+
224+static void
225+mt7996_tm_ipi_work(struct work_struct *work)
226+{
227+#define PRECISION 100
228+ struct mt7996_phy *phy = container_of(work, struct mt7996_phy, ipi_work.work);
229+ struct mt7996_dev *dev = phy->dev;
230+ struct mt76_testmode_data *td = &phy->mt76->test;
231+ struct mt7996_tm_rdd_ipi_ctrl data;
232+ u32 ipi_idx, ipi_free_count, ipi_percentage;
233+ u32 ipi_hist_count_th = 0, ipi_hist_total_count = 0;
234+ u32 self_idle_ratio, ipi_idle_ratio, channel_load;
235+ u32 *ipi_hist_data;
236+ const char *power_lower_bound, *power_upper_bound;
237+ static const char * const ipi_idx_to_power_bound[] = {
238+ [RDD_IPI_HIST_0] = "-92",
239+ [RDD_IPI_HIST_1] = "-89",
240+ [RDD_IPI_HIST_2] = "-86",
241+ [RDD_IPI_HIST_3] = "-83",
242+ [RDD_IPI_HIST_4] = "-80",
243+ [RDD_IPI_HIST_5] = "-75",
244+ [RDD_IPI_HIST_6] = "-70",
245+ [RDD_IPI_HIST_7] = "-65",
246+ [RDD_IPI_HIST_8] = "-60",
247+ [RDD_IPI_HIST_9] = "-55",
248+ [RDD_IPI_HIST_10] = "inf",
249+ };
250+
251+ memset(&data, 0, sizeof(data));
252+ mt7996_tm_ipi_hist_ctrl(phy, &data, RDD_IPI_HIST_ALL_CNT);
253+
254+ ipi_hist_data = data.ipi_hist_val;
255+ for (ipi_idx = 0; ipi_idx < POWER_INDICATE_HIST_MAX; ipi_idx++) {
256+ power_lower_bound = ipi_idx ? ipi_idx_to_power_bound[ipi_idx - 1] : "-inf";
257+ power_upper_bound = ipi_idx_to_power_bound[ipi_idx];
258+
259+ dev_info(dev->mt76.dev, "IPI %d (power range: (%s, %s] dBm): ipi count = %d\n",
260+ ipi_idx, power_lower_bound, power_upper_bound, ipi_hist_data[ipi_idx]);
261+
262+ if (td->ipi_threshold <= ipi_idx && ipi_idx <= RDD_IPI_HIST_10)
263+ ipi_hist_count_th += ipi_hist_data[ipi_idx];
264+
265+ ipi_hist_total_count += ipi_hist_data[ipi_idx];
266+ }
267+
268+ ipi_free_count = ipi_hist_data[RDD_IPI_FREE_RUN_CNT];
269+
270+ dev_info(dev->mt76.dev, "IPI threshold %d: ipi_hist_count_th = %d, ipi_free_count = %d\n",
271+ td->ipi_threshold, ipi_hist_count_th, ipi_free_count);
272+ dev_info(dev->mt76.dev, "TX assert time = %d [ms]\n", data.tx_assert_time / 1000);
273+
274+ /* calculate channel load = (self idle ratio - idle ratio) / self idle ratio */
275+ if (ipi_hist_count_th >= UINT_MAX / (100 * PRECISION))
276+ ipi_percentage = 100 * PRECISION *
277+ (ipi_hist_count_th / (100 * PRECISION)) /
278+ (ipi_free_count / (100 * PRECISION));
279+ else
280+ ipi_percentage = PRECISION * 100 * ipi_hist_count_th / ipi_free_count;
281+
282+ ipi_idle_ratio = ((100 * PRECISION) - ipi_percentage) / PRECISION;
283+
284+ self_idle_ratio = PRECISION * 100 *
285+ (td->ipi_period - (data.tx_assert_time / 1000)) /
286+ td->ipi_period / PRECISION;
287+
288+ if (self_idle_ratio < ipi_idle_ratio)
289+ channel_load = 0;
290+ else
291+ channel_load = self_idle_ratio - ipi_idle_ratio;
292+
293+ if (self_idle_ratio <= td->ipi_threshold) {
294+ dev_info(dev->mt76.dev, "band[%d]: self idle ratio = %d%%, idle ratio = %d%%\n",
295+ phy->mt76->band_idx, self_idle_ratio, ipi_idle_ratio);
296+ return;
297+ }
298+
299+ channel_load = (100 * channel_load) / self_idle_ratio;
300+ dev_info(dev->mt76.dev,
301+ "band[%d]: chan load = %d%%, self idle ratio = %d%%, idle ratio = %d%%\n",
302+ phy->mt76->band_idx, channel_load, self_idle_ratio, ipi_idle_ratio);
303+}
304+
305+static int
306+mt7996_tm_set_ipi(struct mt7996_phy *phy)
307+{
308+ struct mt76_testmode_data *td = &phy->mt76->test;
309+
310+ /* reset IPI CR */
311+ mt7996_tm_ipi_hist_ctrl(phy, NULL, RDD_SET_IPI_HIST_RESET);
312+
313+ cancel_delayed_work(&phy->ipi_work);
314+ ieee80211_queue_delayed_work(phy->mt76->hw, &phy->ipi_work,
315+ msecs_to_jiffies(td->ipi_period));
316+
317+ return 0;
318+}
319+
320 static void
321 mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
322 {
323@@ -860,6 +1078,14 @@ mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
324
325 mt7996_tm_set(dev, func_idx, td->cfg.type);
326 }
327+ if ((changed & BIT(TM_CHANGED_OFF_CHAN_CH)) &&
328+ (changed & BIT(TM_CHANGED_OFF_CHAN_BW)))
329+ mt7996_tm_set_offchan(phy, !(changed & BIT(TM_CHANGED_OFF_CHAN_CENTER_CH)));
330+ if ((changed & BIT(TM_CHANGED_IPI_THRESHOLD)) &&
331+ (changed & BIT(TM_CHANGED_IPI_PERIOD)))
332+ mt7996_tm_set_ipi(phy);
333+ if (changed & BIT(TM_CHANGED_IPI_RESET))
334+ mt7996_tm_ipi_hist_ctrl(phy, NULL, RDD_SET_IPI_HIST_RESET);
335 }
336
337 static int
338diff --git a/mt7996/testmode.h b/mt7996/testmode.h
developer05f3b2b2024-08-19 19:17:34 +0800339index 9bfb86f2..78662b2e 100644
developer66e89bc2024-04-23 14:50:01 +0800340--- a/mt7996/testmode.h
341+++ b/mt7996/testmode.h
342@@ -27,9 +27,15 @@ enum {
343 FW_CDBW_8080MHZ,
344 };
345
346+#define FIRST_CONTROL_CHAN_BITMAP_BW40 0x5555555
347+#define FIRST_CONTROL_CHAN_BITMAP_BW80 0x111111
348+#define FIRST_CONTROL_CHAN_BITMAP_BW160 0x100101
349+
350 enum bw_mapping_method {
351 BW_MAP_NL_TO_FW,
352 BW_MAP_NL_TO_TM,
353+ BW_MAP_NL_TO_MHZ,
354+ BW_MAP_NL_TO_CONTROL_BITMAP_5G,
355
356 NUM_BW_MAP,
357 };
358@@ -312,4 +318,42 @@ struct mt7996_tm_rx_event {
359 };
360 } __packed;
361
362+enum {
363+ RDD_SET_IPI_CR_INIT, /* CR initialization */
364+ RDD_SET_IPI_HIST_RESET, /* Reset IPI histogram counter */
365+ RDD_SET_IDLE_POWER, /* Idle power info */
366+ RDD_SET_IPI_HIST_NUM
367+};
368+
369+enum {
370+ RDD_IPI_HIST_0, /* IPI count for power <= -92 (dBm) */
371+ RDD_IPI_HIST_1, /* IPI count for -92 < power <= -89 (dBm) */
372+ RDD_IPI_HIST_2, /* IPI count for -89 < power <= -86 (dBm) */
373+ RDD_IPI_HIST_3, /* IPI count for -86 < power <= -83 (dBm) */
374+ RDD_IPI_HIST_4, /* IPI count for -83 < power <= -80 (dBm) */
375+ RDD_IPI_HIST_5, /* IPI count for -80 < power <= -75 (dBm) */
376+ RDD_IPI_HIST_6, /* IPI count for -75 < power <= -70 (dBm) */
377+ RDD_IPI_HIST_7, /* IPI count for -70 < power <= -65 (dBm) */
378+ RDD_IPI_HIST_8, /* IPI count for -65 < power <= -60 (dBm) */
379+ RDD_IPI_HIST_9, /* IPI count for -60 < power <= -55 (dBm) */
380+ RDD_IPI_HIST_10, /* IPI count for -55 < power (dBm) */
381+ RDD_IPI_FREE_RUN_CNT, /* IPI count for counter++ per 8 us */
382+ RDD_IPI_HIST_ALL_CNT, /* Get all IPI */
383+ RDD_IPI_HIST_0_TO_10_CNT, /* Get IPI histogram 0 to 10 */
384+ RDD_IPI_HIST_2_TO_10_CNT, /* Get IPI histogram 2 to 10 */
385+ RDD_TX_ASSERT_TIME, /* Get band 1 TX assert time */
386+ RDD_IPI_HIST_NUM
387+};
388+
389+#define POWER_INDICATE_HIST_MAX RDD_IPI_FREE_RUN_CNT
390+#define IPI_HIST_TYPE_NUM (POWER_INDICATE_HIST_MAX + 1)
391+
392+struct mt7996_tm_rdd_ipi_ctrl {
393+ u8 ipi_hist_idx;
394+ u8 band_idx;
395+ u8 rsv[2];
396+ __le32 ipi_hist_val[IPI_HIST_TYPE_NUM];
397+ __le32 tx_assert_time; /* unit: us */
398+} __packed;
399+
400 #endif
401diff --git a/testmode.c b/testmode.c
developer05f3b2b2024-08-19 19:17:34 +0800402index cd8cb655..69147f86 100644
developer66e89bc2024-04-23 14:50:01 +0800403--- a/testmode.c
404+++ b/testmode.c
405@@ -27,6 +27,13 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
406 [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
407 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
408 [MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED },
409+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
410+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
411+ [MT76_TM_ATTR_OFF_CH_SCAN_BW] = { .type = NLA_U8 },
412+ [MT76_TM_ATTR_OFF_CH_SCAN_PATH] = { .type = NLA_U8 },
413+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
414+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
415+ [MT76_TM_ATTR_IPI_RESET] = { .type = NLA_U8 },
416 };
417 EXPORT_SYMBOL_GPL(mt76_tm_policy);
418
419@@ -499,6 +506,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
420 if (tb[MT76_TM_ATTR_TX_RATE_IDX])
421 td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]);
422
423+ if (tb[MT76_TM_ATTR_IPI_PERIOD])
424+ td->ipi_period = nla_get_u32(tb[MT76_TM_ATTR_IPI_PERIOD]);
425+
426 if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode,
427 0, MT76_TM_TX_MODE_MAX) ||
428 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss,
429@@ -514,7 +524,14 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
430 &td->tx_duty_cycle, 0, 99) ||
431 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL],
432 &td->tx_power_control, 0, 1) ||
433- mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16))
434+ mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16) ||
435+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CH], &td->offchan_ch, 36, 196) ||
436+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH], &td->offchan_center_ch,
437+ 36, 196) ||
438+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_BW],
439+ &td->offchan_bw, NL80211_CHAN_WIDTH_20_NOHT, NL80211_CHAN_WIDTH_160) ||
440+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_THRESHOLD], &td->ipi_threshold, 0, 10) ||
441+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_RESET], &td->ipi_reset, 0, 1))
442 goto out;
443
444 if (tb[MT76_TM_ATTR_TX_LENGTH]) {
445@@ -720,6 +737,9 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
446 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
447 nla_put_u8(msg, MT76_TM_ATTR_SKU_EN, td->sku_en) ||
448 nla_put_u8(msg, MT76_TM_ATTR_AID, td->aid) ||
449+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CH, td->offchan_ch) ||
450+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH, td->offchan_center_ch) ||
451+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_BW, td->offchan_bw) ||
452 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
453 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
454 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
455diff --git a/tools/fields.c b/tools/fields.c
developer05f3b2b2024-08-19 19:17:34 +0800456index b0122763..77696ce7 100644
developer66e89bc2024-04-23 14:50:01 +0800457--- a/tools/fields.c
458+++ b/tools/fields.c
459@@ -35,6 +35,15 @@ static const char * const testmode_tx_mode[] = {
460 [MT76_TM_TX_MODE_EHT_MU] = "eht_mu",
461 };
462
463+static const char * const testmode_offchan_bw[] = {
464+ [NL80211_CHAN_WIDTH_20_NOHT] = "NOHT",
465+ [NL80211_CHAN_WIDTH_20] = "20",
466+ [NL80211_CHAN_WIDTH_40] = "40",
467+ [NL80211_CHAN_WIDTH_80] = "80",
468+ [NL80211_CHAN_WIDTH_80P80] = "80p80",
469+ [NL80211_CHAN_WIDTH_160] = "160",
470+};
471+
472 static void print_enum(const struct tm_field *field, struct nlattr *attr)
473 {
474 unsigned int i = nla_get_u8(attr);
475@@ -390,6 +399,12 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
476 FIELD(u8, AID, "aid"),
477 FIELD(u8, RU_ALLOC, "ru_alloc"),
478 FIELD(u8, RU_IDX, "ru_idx"),
479+ FIELD(u8, OFF_CH_SCAN_CH, "offchan_ch"),
480+ FIELD(u8, OFF_CH_SCAN_CENTER_CH, "offchan_center_ch"),
481+ FIELD_ENUM(OFF_CH_SCAN_BW, "offchan_bw", testmode_offchan_bw),
482+ FIELD(u8, IPI_THRESHOLD, "ipi_threshold"),
483+ FIELD(u32, IPI_PERIOD, "ipi_period"),
484+ FIELD(u8, IPI_RESET, "ipi_reset"),
485 FIELD_MAC(MAC_ADDRS, "mac_addrs"),
486 FIELD_NESTED_RO(STATS, stats, "",
487 .print_extra = print_extra_stats),
488--
developerd0c89452024-10-11 16:53:27 +08004892.45.2
developer66e89bc2024-04-23 14:50:01 +0800490