blob: 1deda117e7e111d764660be37103afa9a3334ccb [file] [log] [blame]
developer887da632022-10-28 09:35:38 +08001From 8f5eeab00cf1eeb394132306db23fb1cd2ef5afa Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 27 Oct 2022 17:42:07 +0800
4Subject: [PATCH] mt76: testmode: add ZWDFS test mode support
5
6Change-Id: I14d104b7158a35acf6b0595357d07fb87f5a9d94
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8---
9 mt76.h | 8 ++
10 mt76_connac_mcu.h | 2 +
11 mt7915/mcu.c | 64 ++++++++++++++
12 mt7915/mcu.h | 46 ++++++++++
13 mt7915/mt7915.h | 4 +
14 mt7915/testmode.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++
15 testmode.c | 23 ++++-
16 testmode.h | 43 ++++++++++
17 tools/fields.c | 20 +++++
18 9 files changed, 422 insertions(+), 1 deletion(-)
19
20diff --git a/mt76.h b/mt76.h
21index 3ca449f..adeba98 100644
22--- a/mt76.h
23+++ b/mt76.h
24@@ -708,6 +708,14 @@ struct mt76_testmode_data {
25 u64 fcs_error[__MT_RXQ_MAX];
26 u64 len_mismatch;
27 } rx_stats;
28+
29+ u8 offchan_ch;
30+ u8 offchan_center_ch;
31+ u8 offchan_bw;
32+
33+ u8 ipi_threshold;
34+ u32 ipi_period;
35+ u8 ipi_antenna_idx;
36 };
37
38 struct mt76_vif {
39diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
40index b14f931..d7ea781 100644
41--- a/mt76_connac_mcu.h
42+++ b/mt76_connac_mcu.h
43@@ -1148,6 +1148,7 @@ enum {
44 MCU_EXT_CMD_OFFCH_SCAN_CTRL = 0x9a,
45 MCU_EXT_CMD_SET_RDD_TH = 0x9d,
46 MCU_EXT_CMD_MURU_CTRL = 0x9f,
47+ MCU_EXT_CMD_IPI_HIST_CTRL = 0xa3,
48 MCU_EXT_CMD_RX_STAT = 0xa4,
49 MCU_EXT_CMD_SET_SPR = 0xa8,
50 MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
51@@ -1158,6 +1159,7 @@ enum {
52 MCU_EXT_CMD_RX_STAT_USER_CTRL = 0xb3,
53 MCU_EXT_CMD_CERT_CFG = 0xb7,
54 MCU_EXT_CMD_CSI_CTRL = 0xc2,
55+ MCU_EXT_CMD_IPI_HIST_SCAN = 0xc5,
56 };
57
58 enum {
59diff --git a/mt7915/mcu.c b/mt7915/mcu.c
60index 34ce7d6..87578d7 100644
61--- a/mt7915/mcu.c
62+++ b/mt7915/mcu.c
63@@ -2665,6 +2665,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
64 req.monitor_chan = chandef->chan->hw_value;
65 req.monitor_central_chan =
66 ieee80211_frequency_to_channel(chandef->center_freq1);
67+ req.monitor_bw = mt76_connac_chan_bw(chandef);
68 req.band_idx = phy != &dev->phy;
69 req.scan_mode = 2;
70 break;
71@@ -4236,3 +4237,66 @@ int mt7915_mcu_set_amsdu_algo(struct mt7915_dev *dev, u16 wcid, u8 enable)
72 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MEC_CTRL), &req, sizeof(req), true);
73 }
74 #endif
75+
76+int mt7915_mcu_ipi_hist_ctrl(struct mt7915_phy *phy, void *data, u8 cmd, bool wait_resp)
77+{
78+ struct mt7915_dev *dev = phy->dev;
79+ struct sk_buff *skb;
80+ int ret;
81+ struct {
82+ u8 ipi_hist_idx;
83+ u8 band_idx;
84+ u8 set_val;
85+ u8 rsv;
86+ int idle_power_th;
87+ u32 idle_power_max_cnt;
88+ u32 idle_power_duration;
89+ u32 idle_power_cmd_type;
90+ } __packed req = {
91+ .ipi_hist_idx = cmd,
92+ .band_idx = phy->band_idx,
93+ };
94+
95+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(IPI_HIST_CTRL),
96+ &req, sizeof(req), wait_resp, &skb);
97+ if (ret)
98+ return ret;
99+
100+ if (!wait_resp)
101+ return 0;
102+
103+ memcpy(data, skb->data, sizeof(struct mt7915_mcu_rdd_ipi_ctrl));
104+ dev_kfree_skb(skb);
105+
106+ return 0;
107+}
108+
109+int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool wait_resp)
110+{
111+ struct mt7915_dev *dev = phy->dev;
112+ struct sk_buff *skb;
113+ int ret;
114+ struct rdd_ipi_hist_scan {
115+ u8 mode;
116+ u8 pd_setting;
117+ u8 band_idx;
118+ u8 rsv;
119+ } __packed req = {
120+ .mode = mode,
121+ .pd_setting = 1,
122+ .band_idx = phy->band_idx,
123+ };
124+
125+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(IPI_HIST_SCAN),
126+ &req, sizeof(req), wait_resp, &skb);
127+ if (ret)
128+ return ret;
129+
130+ if (!wait_resp)
131+ return 0;
132+
133+ memcpy(data, skb->data, sizeof(struct mt7915_mcu_rdd_ipi_scan));
134+ dev_kfree_skb(skb);
135+
136+ return 0;
137+}
138diff --git a/mt7915/mcu.h b/mt7915/mcu.h
139index ad85e56..e0fb5a1 100644
140--- a/mt7915/mcu.h
141+++ b/mt7915/mcu.h
142@@ -576,6 +576,52 @@ struct csi_data {
143 };
144 #endif
145
146+enum {
147+ RDD_SET_IPI_CR_INIT, /* CR initialization */
148+ RDD_SET_IPI_HIST_RESET, /* Reset IPI histogram counter */
149+ RDD_SET_IDLE_POWER, /* Idle power info */
150+ RDD_SET_IPI_HIST_NUM
151+};
152+
153+enum {
154+ RDD_IPI_HIST_0, /* IPI count for power <= -92 (dBm) */
155+ RDD_IPI_HIST_1, /* IPI count for -92 < power <= -89 (dBm) */
156+ RDD_IPI_HIST_2, /* IPI count for -89 < power <= -86 (dBm) */
157+ RDD_IPI_HIST_3, /* IPI count for -86 < power <= -83 (dBm) */
158+ RDD_IPI_HIST_4, /* IPI count for -83 < power <= -80 (dBm) */
159+ RDD_IPI_HIST_5, /* IPI count for -80 < power <= -75 (dBm) */
160+ RDD_IPI_HIST_6, /* IPI count for -75 < power <= -70 (dBm) */
161+ RDD_IPI_HIST_7, /* IPI count for -70 < power <= -65 (dBm) */
162+ RDD_IPI_HIST_8, /* IPI count for -65 < power <= -60 (dBm) */
163+ RDD_IPI_HIST_9, /* IPI count for -60 < power <= -55 (dBm) */
164+ RDD_IPI_HIST_10, /* IPI count for -55 < power (dBm) */
165+ RDD_IPI_FREE_RUN_CNT, /* IPI count for counter++ per 8 us */
166+ RDD_IPI_HIST_ALL_CNT, /* Get all IPI */
167+ RDD_IPI_HIST_0_TO_10_CNT, /* Get IPI histogram 0 to 10 */
168+ RDD_IPI_HIST_2_TO_10_CNT, /* Get IPI histogram 2 to 10 */
169+ RDD_TX_ASSERT_TIME, /* Get band 1 TX assert time */
170+ RDD_IPI_HIST_NUM
171+};
172+
173+#define RDM_NF_MAX_WF_IDX 8
174+#define POWER_INDICATE_HIST_MAX RDD_IPI_FREE_RUN_CNT
175+#define IPI_HIST_TYPE_NUM (POWER_INDICATE_HIST_MAX + 1)
176+
177+struct mt7915_mcu_rdd_ipi_ctrl {
178+ u8 ipi_hist_idx;
179+ u8 band_idx;
180+ u8 rsv[2];
181+ u32 ipi_hist_val[IPI_HIST_TYPE_NUM];
182+ u32 tx_assert_time; /* unit: us */
183+} __packed;
184+
185+struct mt7915_mcu_rdd_ipi_scan {
186+ u32 ipi_hist_val[RDM_NF_MAX_WF_IDX][POWER_INDICATE_HIST_MAX];
187+ u8 band_idx;
188+ u8 rsv[2];
189+ u8 tx_assert_time; /* unit: us */
190+} __packed;
191+
192 /* MURU */
193 #define OFDMA_DL BIT(0)
194 #define OFDMA_UL BIT(1)
195diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
196index f3bbdba..d29c8ef 100644
197--- a/mt7915/mt7915.h
198+++ b/mt7915/mt7915.h
199@@ -289,6 +289,7 @@ struct mt7915_phy {
200
201 struct mib_stats mib;
202 struct mt76_channel_state state_ts;
203+ struct delayed_work ipi_work;
204
205 #ifdef CONFIG_NL80211_TESTMODE
206 struct {
207@@ -725,6 +726,9 @@ int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
208 struct ieee80211_sta *sta);
209 #endif
210
211+int mt7915_mcu_ipi_hist_ctrl(struct mt7915_phy *phy, void *data, u8 cmd, bool wait_resp);
212+int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool wait_resp);
213+
214 #ifdef MTK_DEBUG
215 int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir);
216 int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3, bool wait_resp);
217diff --git a/mt7915/testmode.c b/mt7915/testmode.c
218index f735ed6..8c48d2d 100644
219--- a/mt7915/testmode.c
220+++ b/mt7915/testmode.c
221@@ -13,6 +13,11 @@ enum {
222 TM_CHANGED_AID,
223 TM_CHANGED_CFG,
224 TM_CHANGED_TXBF_ACT,
225+ TM_CHANGED_OFF_CHAN_CH,
226+ TM_CHANGED_OFF_CHAN_CENTER_CH,
227+ TM_CHANGED_OFF_CHAN_BW,
228+ TM_CHANGED_IPI_THRESHOLD,
229+ TM_CHANGED_IPI_PERIOD,
230
231 /* must be last */
232 NUM_TM_CHANGED
233@@ -24,6 +29,11 @@ static const u8 tm_change_map[] = {
234 [TM_CHANGED_AID] = MT76_TM_ATTR_AID,
235 [TM_CHANGED_CFG] = MT76_TM_ATTR_CFG,
236 [TM_CHANGED_TXBF_ACT] = MT76_TM_ATTR_TXBF_ACT,
237+ [TM_CHANGED_OFF_CHAN_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CH,
238+ [TM_CHANGED_OFF_CHAN_CENTER_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
239+ [TM_CHANGED_OFF_CHAN_BW] = MT76_TM_ATTR_OFF_CH_SCAN_BW,
240+ [TM_CHANGED_IPI_THRESHOLD] = MT76_TM_ATTR_IPI_THRESHOLD,
241+ [TM_CHANGED_IPI_PERIOD] = MT76_TM_ATTR_IPI_PERIOD,
242 };
243
244 struct reg_band {
245@@ -962,6 +972,201 @@ mt7915_tm_set_txbf(struct mt7915_phy *phy)
246 return 0;
247 }
248
249+static int
250+mt7915_tm_set_offchan(struct mt7915_phy *phy)
251+{
252+ struct mt76_phy *mphy = phy->mt76;
253+ struct mt7915_dev *dev = phy->dev;
254+ struct ieee80211_hw *hw = mphy->hw;
255+ struct mt76_testmode_data *td = &phy->mt76->test;
256+ struct cfg80211_chan_def chandef = {};
257+ struct ieee80211_channel *chan;
258+ int ret, freq = ieee80211_channel_to_frequency(td->offchan_ch, NL80211_BAND_5GHZ);
259+ int width_mhz;
260+ const int bw_to_mhz[] = {
261+ [NL80211_CHAN_WIDTH_20_NOHT] = 20,
262+ [NL80211_CHAN_WIDTH_20] = 20,
263+ [NL80211_CHAN_WIDTH_40] = 40,
264+ [NL80211_CHAN_WIDTH_80] = 80,
265+ [NL80211_CHAN_WIDTH_80P80] = 80,
266+ [NL80211_CHAN_WIDTH_160] = 160,
267+ };
268+
269+ if (phy->band_idx != NL80211_BAND_5GHZ && !freq) {
270+ ret = -EINVAL;
271+ dev_info(dev->mt76.dev, "Failed to set offchan (invalid band or channel)!\n");
272+ goto out;
273+ }
274+
275+ chandef.width = td->offchan_bw;
276+ width_mhz = bw_to_mhz[chandef.width];
277+ chandef.center_freq1 = freq;
278+ chan = ieee80211_get_channel(hw->wiphy, freq);
279+ chandef.chan = chan;
280+
281+ memset(&dev->rdd2_chandef, 0, sizeof(struct cfg80211_chan_def));
282+
283+ ret = mt7915_mcu_rdd_background_enable(phy, &chandef);
284+
285+ if (ret)
286+ goto out;
287+
288+ dev->rdd2_phy = phy;
289+ dev->rdd2_chandef = chandef;
290+
291+ return ret;
292+
293+out:
294+ td->offchan_ch = 0;
295+ td->offchan_bw = 0;
296+
297+ return ret;
298+}
299+
300+static void
301+mt7915_tm_dump_ipi(struct mt7915_phy *phy, void *data, u8 antenna_num,
302+ u8 start_antenna_idx, bool is_scan)
303+{
304+#define PRECISION 100
305+ struct mt7915_dev *dev = phy->dev;
306+ struct mt76_testmode_data *td = &phy->mt76->test;
307+ struct mt7915_mcu_rdd_ipi_scan *scan_data;
308+ struct mt7915_mcu_rdd_ipi_ctrl *ctrl_data;
309+ u32 ipi_idx, ipi_free_count, ipi_percentage, ipi_hist_count_th, ipi_hist_total_count;
310+ u32 self_idle_ratio, ipi_idle_ratio, channel_load, tx_assert_time;
311+ u8 i, antenna_idx = start_antenna_idx;
312+ u32 *ipi_hist_data;
313+ const char *power_lower_bound, *power_upper_bound;
314+ static const char * const ipi_idx_to_power_bound[] = {
315+ [RDD_IPI_HIST_0] = "-92",
316+ [RDD_IPI_HIST_1] = "-89",
317+ [RDD_IPI_HIST_2] = "-86",
318+ [RDD_IPI_HIST_3] = "-83",
319+ [RDD_IPI_HIST_4] = "-80",
320+ [RDD_IPI_HIST_5] = "-75",
321+ [RDD_IPI_HIST_6] = "-70",
322+ [RDD_IPI_HIST_7] = "-65",
323+ [RDD_IPI_HIST_8] = "-60",
324+ [RDD_IPI_HIST_9] = "-55",
325+ [RDD_IPI_HIST_10] = "inf",
326+ };
327+
328+ if (is_scan) {
329+ scan_data = (struct mt7915_mcu_rdd_ipi_scan *)data;
330+ tx_assert_time = scan_data->tx_assert_time;
331+ } else {
332+ ctrl_data = (struct mt7915_mcu_rdd_ipi_ctrl *)data;
333+ tx_assert_time = ctrl_data->tx_assert_time;
334+ }
335+
336+ for (i = 0; i < antenna_num; i++) {
337+ ipi_free_count = 0;
338+ ipi_hist_count_th = 0;
339+ ipi_hist_total_count = 0;
340+ ipi_hist_data = is_scan ? scan_data->ipi_hist_val[antenna_idx] :
341+ ctrl_data->ipi_hist_val;
342+
343+ dev_info(dev->mt76.dev, "Antenna index: %d\n", antenna_idx);
344+ for (ipi_idx = 0; ipi_idx < POWER_INDICATE_HIST_MAX; ipi_idx++) {
345+ power_lower_bound = ipi_idx ? ipi_idx_to_power_bound[ipi_idx - 1] :
346+ "-inf";
347+ power_upper_bound = ipi_idx_to_power_bound[ipi_idx];
348+
349+ dev_info(dev->mt76.dev,
350+ "IPI %d (power range: (%s, %s] dBm): ipi count = %d\n",
351+ ipi_idx, power_lower_bound,
352+ power_upper_bound, ipi_hist_data[ipi_idx]);
353+
354+ if (td->ipi_threshold <= ipi_idx && ipi_idx <= RDD_IPI_HIST_10)
355+ ipi_hist_count_th += ipi_hist_data[ipi_idx];
356+
357+ ipi_hist_total_count += ipi_hist_data[ipi_idx];
358+ }
359+ ipi_free_count = is_scan ? ipi_hist_total_count :
360+ ipi_hist_data[RDD_IPI_FREE_RUN_CNT];
361+
362+ dev_info(dev->mt76.dev,
363+ "IPI threshold %d: ipi_hist_count_th = %d, ipi_free_count = %d\n",
364+ td->ipi_threshold, ipi_hist_count_th, ipi_free_count);
365+ dev_info(dev->mt76.dev, "TX assert time = %d [ms]\n",
366+ tx_assert_time / 1000);
367+
368+ // Calculate channel load = (self idle ratio - idle ratio) / self idle ratio
369+ if (ipi_hist_count_th >= UINT_MAX / (100 * PRECISION))
370+ ipi_percentage = 100 * PRECISION *
371+ (ipi_hist_count_th / (100 * PRECISION)) /
372+ (ipi_free_count / (100 * PRECISION));
373+ else
374+ ipi_percentage = PRECISION * 100 * ipi_hist_count_th / ipi_free_count;
375+
376+ ipi_idle_ratio = ((100 * PRECISION) - ipi_percentage) / PRECISION;
377+
378+ self_idle_ratio = PRECISION * 100 *
379+ (td->ipi_period - (tx_assert_time / 1000)) /
380+ td->ipi_period / PRECISION;
381+
382+ if (self_idle_ratio < ipi_idle_ratio)
383+ channel_load = 0;
384+ else
385+ channel_load = self_idle_ratio - ipi_idle_ratio;
386+
387+ if (self_idle_ratio <= td->ipi_threshold) {
388+ dev_info(dev->mt76.dev,
389+ "band[%d]: self idle ratio = %d%%, idle ratio = %d%%\n",
390+ phy->band_idx, self_idle_ratio, ipi_idle_ratio);
391+ return;
392+ }
393+
394+ channel_load = (100 * channel_load) / self_idle_ratio;
395+ dev_info(dev->mt76.dev,
396+ "band[%d]: chan load = %d%%, self idle ratio = %d%%, idle ratio = %d%%\n",
397+ phy->band_idx, channel_load, self_idle_ratio, ipi_idle_ratio);
398+ antenna_idx++;
399+ }
400+}
401+
402+static void
403+mt7915_tm_ipi_work(struct work_struct *work)
404+{
405+ struct mt7915_phy *phy = container_of(work, struct mt7915_phy, ipi_work.work);
406+ struct mt7915_dev *dev = phy->dev;
407+ struct mt76_testmode_data *td = &phy->mt76->test;
408+ u8 start_antenna_idx = 0, antenna_num = 1;
409+
410+ if (!is_mt7915(&dev->mt76)) {
411+ struct mt7915_mcu_rdd_ipi_scan data;
412+
413+ if (phy->band_idx)
414+ start_antenna_idx = 4;
415+
416+ /* Use all antenna */
417+ if (td->ipi_antenna_idx == MT76_TM_IPI_ANTENNA_ALL)
418+ antenna_num = 4;
419+ else
420+ start_antenna_idx += td->ipi_antenna_idx;
421+
422+ mt7915_mcu_ipi_hist_scan(phy, &data, 0, true);
423+ mt7915_tm_dump_ipi(phy, &data, antenna_num, start_antenna_idx, true);
424+ } else {
425+ struct mt7915_mcu_rdd_ipi_ctrl data;
426+
427+ mt7915_mcu_ipi_hist_ctrl(phy, &data, RDD_IPI_HIST_ALL_CNT, true);
428+ mt7915_tm_dump_ipi(phy, &data, antenna_num, start_antenna_idx, false);
429+ }
430+}
431+
432+static int
433+mt7915_tm_set_ipi(struct mt7915_phy *phy)
434+{
435+ struct mt76_testmode_data *td = &phy->mt76->test;
436+
437+ cancel_delayed_work(&phy->ipi_work);
438+ ieee80211_queue_delayed_work(phy->mt76->hw, &phy->ipi_work,
439+ msecs_to_jiffies(td->ipi_period));
440+
441+ return 0;
442+}
443+
444 static int
445 mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
446 u16 cw_max, u16 txop, u8 tx_cmd)
447@@ -1247,6 +1452,8 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
448 phy->mt76->test.tx_mpdu_len = 0;
449 phy->test.bf_en = 0;
450 mt7915_tm_set_entry(phy);
451+ } else {
452+ INIT_DELAYED_WORK(&phy->ipi_work, mt7915_tm_ipi_work);
453 }
454 }
455
456@@ -2004,6 +2211,12 @@ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
457 mt7915_tm_set_cfg(phy);
458 if (changed & BIT(TM_CHANGED_TXBF_ACT))
459 mt7915_tm_set_txbf(phy);
460+ if ((changed & BIT(TM_CHANGED_OFF_CHAN_CH)) &&
461+ (changed & BIT(TM_CHANGED_OFF_CHAN_BW)))
462+ mt7915_tm_set_offchan(phy);
463+ if ((changed & BIT(TM_CHANGED_IPI_THRESHOLD)) &&
464+ (changed & BIT(TM_CHANGED_IPI_PERIOD)))
465+ mt7915_tm_set_ipi(phy);
466 }
467
468 static int
469diff --git a/testmode.c b/testmode.c
470index aa874a8..de2892b 100644
471--- a/testmode.c
472+++ b/testmode.c
473@@ -24,6 +24,12 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
474 [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
475 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
476 [MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED },
477+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
478+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
479+ [MT76_TM_ATTR_OFF_CH_SCAN_PATH] = { .type = NLA_U8 },
480+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
481+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
482+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
483 };
484 EXPORT_SYMBOL_GPL(mt76_tm_policy);
485
486@@ -402,6 +408,7 @@ mt76_testmode_init_defaults(struct mt76_phy *phy)
487 td->tx_count = 1;
488 td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;
489 td->tx_rate_nss = 1;
490+ td->ipi_antenna_idx = MT76_TM_IPI_ANTENNA_ALL;
491
492 memcpy(td->addr[0], phy->macaddr, ETH_ALEN);
493 memcpy(td->addr[1], phy->macaddr, ETH_ALEN);
494@@ -607,6 +614,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
495 if (tb[MT76_TM_ATTR_TX_RATE_IDX])
496 td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]);
497
498+ if (tb[MT76_TM_ATTR_IPI_PERIOD])
499+ td->ipi_period = nla_get_u32(tb[MT76_TM_ATTR_IPI_PERIOD]);
500+
501 if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode,
502 0, MT76_TM_TX_MODE_MAX) ||
503 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss,
504@@ -623,7 +633,15 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
505 &td->tx_power_control, 0, 1) ||
506 mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16) ||
507 mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_ALLOC], &td->ru_alloc, 0, 0xff) ||
508- mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_IDX], &td->ru_idx, 0, 68))
509+ mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_IDX], &td->ru_idx, 0, 68) ||
510+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CH], &td->offchan_ch, 36, 196) ||
511+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH], &td->offchan_center_ch,
512+ 36, 196) ||
513+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_BW],
514+ &td->offchan_bw, NL80211_CHAN_WIDTH_20_NOHT, NL80211_CHAN_WIDTH_160) ||
515+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_THRESHOLD], &td->ipi_threshold, 0, 10) ||
516+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_ANTENNA_INDEX], &td->ipi_antenna_idx,
517+ MT76_TM_IPI_ANTENNA_0, MT76_TM_IPI_ANTENNA_ALL))
518 goto out;
519
520 if (tb[MT76_TM_ATTR_TX_LENGTH]) {
521@@ -857,6 +875,9 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
522 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) ||
523 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
524 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
525+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CH, td->offchan_ch) ||
526+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH, td->offchan_center_ch) ||
527+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_BW, td->offchan_bw) ||
528 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
529 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
530 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
531diff --git a/testmode.h b/testmode.h
532index 5d1fe79..9f61847 100644
533--- a/testmode.h
534+++ b/testmode.h
535@@ -63,6 +63,19 @@
536 * (nested, u8 attrs)
537 *
538 * @MT76_TM_ATTR_CFG: config testmode rf feature (nested, see &mt76_testmode_cfg)
539+ * @MT76_TM_ATTR_TXBF_ACT: txbf setting actions (u8)
540+ * @MT76_TM_ATTR_TXBF_PARAM: txbf parameters (nested)
541+ *
542+ * @MT76_TM_ATTR_OFF_CH_SCAN_CH: config the channel of background chain (ZWDFS) (u8)
543+ * @MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH: config the center channel of background chain (ZWDFS) (u8)
544+ * @MT76_TM_ATTR_OFF_CH_SCAN_BW: config the bandwidth of background chain (ZWDFS) (u8)
545+ * @MT76_TM_ATTR_OFF_CH_SCAN_PATH: config the tx path of background chain (ZWDFS) (u8)
546+ *
547+ * @MT76_TM_ATTR_IPI_THRESHOLD: config the IPI index you want to read (u8)
548+ * @MT76_TM_ATTR_IPI_PERIOD: config the time period for reading
549+ * the histogram of specific IPI index (u8)
550+ * @MT76_TM_ATTR_IPI_ANTENNA_INDEX: config the antenna index for reading
551+ * the histogram of specific IPI index (u8)
552 *
553 */
554 enum mt76_testmode_attr {
555@@ -116,6 +129,15 @@ enum mt76_testmode_attr {
556 MT76_TM_ATTR_TXBF_ACT,
557 MT76_TM_ATTR_TXBF_PARAM,
558
559+ MT76_TM_ATTR_OFF_CH_SCAN_CH,
560+ MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
561+ MT76_TM_ATTR_OFF_CH_SCAN_BW,
562+ MT76_TM_ATTR_OFF_CH_SCAN_PATH,
563+
564+ MT76_TM_ATTR_IPI_THRESHOLD,
565+ MT76_TM_ATTR_IPI_PERIOD,
566+ MT76_TM_ATTR_IPI_ANTENNA_INDEX,
567+
568 /* keep last */
569 NUM_MT76_TM_ATTRS,
570 MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1,
571@@ -292,4 +314,25 @@ enum mt76_testmode_txbf_act {
572 MT76_TM_TXBF_ACT_MAX = NUM_MT76_TM_TXBF_ACT - 1,
573 };
574
575+/**
576+ * enum mt76_testmode_ipi_antenna - specify antenna index for ipi count
577+ *
578+ * @MT76_TM_IPI_ANTENNA_0: use antenna 0
579+ * @MT76_TM_IPI_ANTENNA_1: use antenna 1
580+ * @MT76_TM_IPI_ANTENNA_2: use antenna 2
581+ * @MT76_TM_IPI_ANTENNA_3: use antenna 3
582+ * @MT76_TM_IPI_ANTENNA_ALL: use all antenna
583+ */
584+enum mt76_testmode_ipi_antenna {
585+ MT76_TM_IPI_ANTENNA_0,
586+ MT76_TM_IPI_ANTENNA_1,
587+ MT76_TM_IPI_ANTENNA_2,
588+ MT76_TM_IPI_ANTENNA_3,
589+ MT76_TM_IPI_ANTENNA_ALL,
590+
591+ /* keep last */
592+ NUM_MT76_TM_IPI_ANTENNA,
593+ MT76_TM_IPI_ANTENNA_MAX = NUM_MT76_TM_IPI_ANTENNA - 1,
594+};
595+
596 #endif
597diff --git a/tools/fields.c b/tools/fields.c
598index 47fc69f..21f6b19 100644
599--- a/tools/fields.c
600+++ b/tools/fields.c
601@@ -46,6 +46,14 @@ static const char * const testmode_txbf_act[] = {
602 [MT76_TM_TXBF_ACT_E2P_UPDATE] = "e2p_update",
603 };
604
605+static const char * const testmode_offchan_bw[] = {
606+ [NL80211_CHAN_WIDTH_20_NOHT] = "NOHT",
607+ [NL80211_CHAN_WIDTH_20] = "20",
608+ [NL80211_CHAN_WIDTH_40] = "40",
609+ [NL80211_CHAN_WIDTH_80] = "80",
610+ [NL80211_CHAN_WIDTH_160] = "160",
611+};
612+
613 static void print_enum(const struct tm_field *field, struct nlattr *attr)
614 {
615 unsigned int i = nla_get_u8(attr);
616@@ -411,6 +419,12 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
617 FIELD(u8, RU_IDX, "ru_idx"),
618 FIELD_ENUM(TXBF_ACT, "txbf_act", testmode_txbf_act),
619 FIELD_ARRAY(u16_hex, TXBF_PARAM, "txbf_param"),
620+ FIELD(u8, OFF_CH_SCAN_CH, "offchan_ch"),
621+ FIELD(u8, OFF_CH_SCAN_CENTER_CH, "offchan_center_ch"),
622+ FIELD_ENUM(OFF_CH_SCAN_BW, "offchan_bw", testmode_offchan_bw),
623+ FIELD(u8, IPI_THRESHOLD, "ipi_threshold"),
624+ FIELD(u32, IPI_PERIOD, "ipi_period"),
625+ FIELD(u8, IPI_ANTENNA_INDEX, "ipi_antenna_idx"),
626 FIELD_MAC(MAC_ADDRS, "mac_addrs"),
627 FIELD_NESTED_RO(STATS, stats, "",
628 .print_extra = print_extra_stats),
629@@ -442,6 +456,12 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
630 [MT76_TM_ATTR_RU_IDX] = { .type = NLA_U8 },
631 [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED },
632 [MT76_TM_ATTR_TXBF_ACT] = { .type = NLA_U8 },
633+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
634+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
635+ [MT76_TM_ATTR_OFF_CH_SCAN_BW] = { .type = NLA_U8 },
636+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
637+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
638+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
639 };
640
641 const struct tm_field msg_field = {
642--
6432.18.0
644