blob: 08a404ec03c1699f2400548d61ddfdd8a65cc8e2 [file] [log] [blame]
developer3d5faf22022-11-29 18:07:22 +08001From f2a6f16bb0a584a0fb7e7dab8cb47e2870b040e9 Mon Sep 17 00:00:00 2001
developerb81e95d2022-11-08 10:16:29 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 27 Oct 2022 17:42:07 +0800
developer3d5faf22022-11-29 18:07:22 +08004Subject: [PATCH 1114/1127] mt76: testmode: add ZWDFS test mode support
developerb81e95d2022-11-08 10:16:29 +08005
6Change-Id: I14d104b7158a35acf6b0595357d07fb87f5a9d94
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8---
developer2cbf2fb2022-11-16 12:20:48 +08009 mt76.h | 9 ++
developerb81e95d2022-11-08 10:16:29 +080010 mt76_connac_mcu.h | 2 +
developer2cbf2fb2022-11-16 12:20:48 +080011 mt7915/mcu.c | 66 +++++++++++++
12 mt7915/mcu.h | 46 +++++++++
developerb81e95d2022-11-08 10:16:29 +080013 mt7915/mt7915.h | 4 +
developer2cbf2fb2022-11-16 12:20:48 +080014 mt7915/regs.h | 2 +
15 mt7915/testmode.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++
16 testmode.c | 25 ++++-
17 testmode.h | 45 +++++++++
18 tools/fields.c | 22 +++++
19 10 files changed, 452 insertions(+), 1 deletion(-)
developerb81e95d2022-11-08 10:16:29 +080020
21diff --git a/mt76.h b/mt76.h
developer3d5faf22022-11-29 18:07:22 +080022index 2beb1056..8139b4ad 100644
developerb81e95d2022-11-08 10:16:29 +080023--- a/mt76.h
24+++ b/mt76.h
developer3d5faf22022-11-29 18:07:22 +080025@@ -719,6 +719,15 @@ struct mt76_testmode_data {
developerb81e95d2022-11-08 10:16:29 +080026 u64 fcs_error[__MT_RXQ_MAX];
27 u64 len_mismatch;
28 } rx_stats;
29+
30+ u8 offchan_ch;
31+ u8 offchan_center_ch;
32+ u8 offchan_bw;
33+
34+ u8 ipi_threshold;
35+ u32 ipi_period;
36+ u8 ipi_antenna_idx;
developer2cbf2fb2022-11-16 12:20:48 +080037+ u8 ipi_reset;
developerb81e95d2022-11-08 10:16:29 +080038 };
39
40 struct mt76_vif {
41diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
developer3d5faf22022-11-29 18:07:22 +080042index 4e489244..c353341e 100644
developerb81e95d2022-11-08 10:16:29 +080043--- a/mt76_connac_mcu.h
44+++ b/mt76_connac_mcu.h
developer3d5faf22022-11-29 18:07:22 +080045@@ -1179,6 +1179,7 @@ enum {
developerb81e95d2022-11-08 10:16:29 +080046 MCU_EXT_CMD_OFFCH_SCAN_CTRL = 0x9a,
47 MCU_EXT_CMD_SET_RDD_TH = 0x9d,
48 MCU_EXT_CMD_MURU_CTRL = 0x9f,
49+ MCU_EXT_CMD_IPI_HIST_CTRL = 0xa3,
50 MCU_EXT_CMD_RX_STAT = 0xa4,
51 MCU_EXT_CMD_SET_SPR = 0xa8,
52 MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab,
developer3d5faf22022-11-29 18:07:22 +080053@@ -1189,6 +1190,7 @@ enum {
developerb81e95d2022-11-08 10:16:29 +080054 MCU_EXT_CMD_RX_STAT_USER_CTRL = 0xb3,
55 MCU_EXT_CMD_CERT_CFG = 0xb7,
56 MCU_EXT_CMD_CSI_CTRL = 0xc2,
57+ MCU_EXT_CMD_IPI_HIST_SCAN = 0xc5,
58 };
59
60 enum {
61diff --git a/mt7915/mcu.c b/mt7915/mcu.c
developer3d5faf22022-11-29 18:07:22 +080062index d1ff73a9..51ec151b 100644
developerb81e95d2022-11-08 10:16:29 +080063--- a/mt7915/mcu.c
64+++ b/mt7915/mcu.c
developer3d5faf22022-11-29 18:07:22 +080065@@ -2620,6 +2620,7 @@ mt7915_mcu_background_chain_ctrl(struct mt7915_phy *phy,
developerb81e95d2022-11-08 10:16:29 +080066 req.monitor_chan = chandef->chan->hw_value;
67 req.monitor_central_chan =
68 ieee80211_frequency_to_channel(chandef->center_freq1);
69+ req.monitor_bw = mt76_connac_chan_bw(chandef);
developer3d5faf22022-11-29 18:07:22 +080070 req.band_idx = phy->band_idx;
developerb81e95d2022-11-08 10:16:29 +080071 req.scan_mode = 2;
72 break;
developer3d5faf22022-11-29 18:07:22 +080073@@ -4450,3 +4451,68 @@ int mt7915_mcu_set_amsdu_algo(struct mt7915_dev *dev, u16 wcid, u8 enable)
developerb81e95d2022-11-08 10:16:29 +080074 return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(MEC_CTRL), &req, sizeof(req), true);
75 }
76 #endif
77+
78+int mt7915_mcu_ipi_hist_ctrl(struct mt7915_phy *phy, void *data, u8 cmd, bool wait_resp)
79+{
80+ struct mt7915_dev *dev = phy->dev;
81+ struct sk_buff *skb;
82+ int ret;
83+ struct {
84+ u8 ipi_hist_idx;
85+ u8 band_idx;
86+ u8 set_val;
87+ u8 rsv;
88+ int idle_power_th;
89+ u32 idle_power_max_cnt;
90+ u32 idle_power_duration;
91+ u32 idle_power_cmd_type;
92+ } __packed req = {
93+ .ipi_hist_idx = cmd,
94+ .band_idx = phy->band_idx,
95+ };
96+
developer2cbf2fb2022-11-16 12:20:48 +080097+ if (!wait_resp)
98+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(IPI_HIST_CTRL),
99+ &req, sizeof(req), true);
100+
101+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(IPI_HIST_CTRL),
developerb81e95d2022-11-08 10:16:29 +0800102+ &req, sizeof(req), wait_resp, &skb);
developer2cbf2fb2022-11-16 12:20:48 +0800103+
developerb81e95d2022-11-08 10:16:29 +0800104+ if (ret)
105+ return ret;
106+
developerb81e95d2022-11-08 10:16:29 +0800107+ memcpy(data, skb->data, sizeof(struct mt7915_mcu_rdd_ipi_ctrl));
108+ dev_kfree_skb(skb);
109+
110+ return 0;
111+}
112+
113+int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool wait_resp)
114+{
115+ struct mt7915_dev *dev = phy->dev;
116+ struct sk_buff *skb;
117+ int ret;
118+ struct rdd_ipi_hist_scan {
119+ u8 mode;
120+ u8 pd_setting;
121+ u8 band_idx;
122+ u8 rsv;
123+ } __packed req = {
124+ .mode = mode,
125+ .pd_setting = 1,
126+ .band_idx = phy->band_idx,
127+ };
128+
129+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(IPI_HIST_SCAN),
130+ &req, sizeof(req), wait_resp, &skb);
131+ if (ret)
132+ return ret;
133+
134+ if (!wait_resp)
135+ return 0;
136+
137+ memcpy(data, skb->data, sizeof(struct mt7915_mcu_rdd_ipi_scan));
138+ dev_kfree_skb(skb);
139+
140+ return 0;
141+}
142diff --git a/mt7915/mcu.h b/mt7915/mcu.h
developer3d5faf22022-11-29 18:07:22 +0800143index 4bc58c98..300b7834 100644
developerb81e95d2022-11-08 10:16:29 +0800144--- a/mt7915/mcu.h
145+++ b/mt7915/mcu.h
developer3d5faf22022-11-29 18:07:22 +0800146@@ -609,6 +609,52 @@ struct csi_data {
developerb81e95d2022-11-08 10:16:29 +0800147 };
148 #endif
149
150+enum {
151+ RDD_SET_IPI_CR_INIT, /* CR initialization */
152+ RDD_SET_IPI_HIST_RESET, /* Reset IPI histogram counter */
153+ RDD_SET_IDLE_POWER, /* Idle power info */
154+ RDD_SET_IPI_HIST_NUM
155+};
156+
157+enum {
158+ RDD_IPI_HIST_0, /* IPI count for power <= -92 (dBm) */
159+ RDD_IPI_HIST_1, /* IPI count for -92 < power <= -89 (dBm) */
160+ RDD_IPI_HIST_2, /* IPI count for -89 < power <= -86 (dBm) */
161+ RDD_IPI_HIST_3, /* IPI count for -86 < power <= -83 (dBm) */
162+ RDD_IPI_HIST_4, /* IPI count for -83 < power <= -80 (dBm) */
163+ RDD_IPI_HIST_5, /* IPI count for -80 < power <= -75 (dBm) */
164+ RDD_IPI_HIST_6, /* IPI count for -75 < power <= -70 (dBm) */
165+ RDD_IPI_HIST_7, /* IPI count for -70 < power <= -65 (dBm) */
166+ RDD_IPI_HIST_8, /* IPI count for -65 < power <= -60 (dBm) */
167+ RDD_IPI_HIST_9, /* IPI count for -60 < power <= -55 (dBm) */
168+ RDD_IPI_HIST_10, /* IPI count for -55 < power (dBm) */
169+ RDD_IPI_FREE_RUN_CNT, /* IPI count for counter++ per 8 us */
170+ RDD_IPI_HIST_ALL_CNT, /* Get all IPI */
171+ RDD_IPI_HIST_0_TO_10_CNT, /* Get IPI histogram 0 to 10 */
172+ RDD_IPI_HIST_2_TO_10_CNT, /* Get IPI histogram 2 to 10 */
173+ RDD_TX_ASSERT_TIME, /* Get band 1 TX assert time */
174+ RDD_IPI_HIST_NUM
175+};
176+
177+#define RDM_NF_MAX_WF_IDX 8
178+#define POWER_INDICATE_HIST_MAX RDD_IPI_FREE_RUN_CNT
179+#define IPI_HIST_TYPE_NUM (POWER_INDICATE_HIST_MAX + 1)
180+
181+struct mt7915_mcu_rdd_ipi_ctrl {
182+ u8 ipi_hist_idx;
183+ u8 band_idx;
184+ u8 rsv[2];
185+ u32 ipi_hist_val[IPI_HIST_TYPE_NUM];
186+ u32 tx_assert_time; /* unit: us */
187+} __packed;
188+
189+struct mt7915_mcu_rdd_ipi_scan {
190+ u32 ipi_hist_val[RDM_NF_MAX_WF_IDX][POWER_INDICATE_HIST_MAX];
191+ u8 band_idx;
192+ u8 rsv[2];
193+ u8 tx_assert_time; /* unit: us */
194+} __packed;
195+
196 /* MURU */
197 #define OFDMA_DL BIT(0)
198 #define OFDMA_UL BIT(1)
199diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
developer3d5faf22022-11-29 18:07:22 +0800200index cafd4389..0cbd02e2 100644
developerb81e95d2022-11-08 10:16:29 +0800201--- a/mt7915/mt7915.h
202+++ b/mt7915/mt7915.h
developer3d5faf22022-11-29 18:07:22 +0800203@@ -304,6 +304,7 @@ struct mt7915_phy {
developerb81e95d2022-11-08 10:16:29 +0800204
205 struct mib_stats mib;
206 struct mt76_channel_state state_ts;
207+ struct delayed_work ipi_work;
208
209 #ifdef CONFIG_NL80211_TESTMODE
210 struct {
developer3d5faf22022-11-29 18:07:22 +0800211@@ -753,6 +754,9 @@ int mt7915_vendor_amnt_sta_remove(struct mt7915_phy *phy,
developerb81e95d2022-11-08 10:16:29 +0800212 struct ieee80211_sta *sta);
213 #endif
214
215+int mt7915_mcu_ipi_hist_ctrl(struct mt7915_phy *phy, void *data, u8 cmd, bool wait_resp);
216+int mt7915_mcu_ipi_hist_scan(struct mt7915_phy *phy, void *data, u8 mode, bool wait_resp);
217+
218 #ifdef MTK_DEBUG
219 int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir);
220 int mt7915_dbg_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3, bool wait_resp);
developer2cbf2fb2022-11-16 12:20:48 +0800221diff --git a/mt7915/regs.h b/mt7915/regs.h
developer3d5faf22022-11-29 18:07:22 +0800222index ae4695ae..6aa98812 100644
developer2cbf2fb2022-11-16 12:20:48 +0800223--- a/mt7915/regs.h
224+++ b/mt7915/regs.h
developer3d5faf22022-11-29 18:07:22 +0800225@@ -1187,6 +1187,8 @@ enum offs_rev {
developer2cbf2fb2022-11-16 12:20:48 +0800226 #define MT_WF_IRPI_NSS(phy, nss) MT_WF_IRPI(0x6000 + ((phy) << 20) + ((nss) << 16))
227 #define MT_WF_IRPI_NSS_MT7916(phy, nss) MT_WF_IRPI(0x1000 + ((phy) << 20) + ((nss) << 16))
228
229+#define MT_WF_IPI_RESET 0x831a3008
230+
231 /* PHY */
232 #define MT_WF_PHY_BASE 0x83080000
233 #define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
developerb81e95d2022-11-08 10:16:29 +0800234diff --git a/mt7915/testmode.c b/mt7915/testmode.c
developer3d5faf22022-11-29 18:07:22 +0800235index 9de11e98..6ce2c0e6 100644
developerb81e95d2022-11-08 10:16:29 +0800236--- a/mt7915/testmode.c
237+++ b/mt7915/testmode.c
developer2cbf2fb2022-11-16 12:20:48 +0800238@@ -13,6 +13,12 @@ enum {
developerb81e95d2022-11-08 10:16:29 +0800239 TM_CHANGED_AID,
240 TM_CHANGED_CFG,
241 TM_CHANGED_TXBF_ACT,
242+ TM_CHANGED_OFF_CHAN_CH,
243+ TM_CHANGED_OFF_CHAN_CENTER_CH,
244+ TM_CHANGED_OFF_CHAN_BW,
245+ TM_CHANGED_IPI_THRESHOLD,
246+ TM_CHANGED_IPI_PERIOD,
developer2cbf2fb2022-11-16 12:20:48 +0800247+ TM_CHANGED_IPI_RESET,
developerb81e95d2022-11-08 10:16:29 +0800248
249 /* must be last */
250 NUM_TM_CHANGED
developer2cbf2fb2022-11-16 12:20:48 +0800251@@ -24,6 +30,12 @@ static const u8 tm_change_map[] = {
developerb81e95d2022-11-08 10:16:29 +0800252 [TM_CHANGED_AID] = MT76_TM_ATTR_AID,
253 [TM_CHANGED_CFG] = MT76_TM_ATTR_CFG,
254 [TM_CHANGED_TXBF_ACT] = MT76_TM_ATTR_TXBF_ACT,
255+ [TM_CHANGED_OFF_CHAN_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CH,
256+ [TM_CHANGED_OFF_CHAN_CENTER_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
257+ [TM_CHANGED_OFF_CHAN_BW] = MT76_TM_ATTR_OFF_CH_SCAN_BW,
258+ [TM_CHANGED_IPI_THRESHOLD] = MT76_TM_ATTR_IPI_THRESHOLD,
259+ [TM_CHANGED_IPI_PERIOD] = MT76_TM_ATTR_IPI_PERIOD,
developer2cbf2fb2022-11-16 12:20:48 +0800260+ [TM_CHANGED_IPI_RESET] = MT76_TM_ATTR_IPI_RESET,
developerb81e95d2022-11-08 10:16:29 +0800261 };
262
263 struct reg_band {
developer2cbf2fb2022-11-16 12:20:48 +0800264@@ -962,6 +974,216 @@ mt7915_tm_set_txbf(struct mt7915_phy *phy)
developerb81e95d2022-11-08 10:16:29 +0800265 return 0;
266 }
267
268+static int
269+mt7915_tm_set_offchan(struct mt7915_phy *phy)
270+{
271+ struct mt76_phy *mphy = phy->mt76;
272+ struct mt7915_dev *dev = phy->dev;
273+ struct ieee80211_hw *hw = mphy->hw;
274+ struct mt76_testmode_data *td = &phy->mt76->test;
275+ struct cfg80211_chan_def chandef = {};
276+ struct ieee80211_channel *chan;
277+ int ret, freq = ieee80211_channel_to_frequency(td->offchan_ch, NL80211_BAND_5GHZ);
278+ int width_mhz;
279+ const int bw_to_mhz[] = {
280+ [NL80211_CHAN_WIDTH_20_NOHT] = 20,
281+ [NL80211_CHAN_WIDTH_20] = 20,
282+ [NL80211_CHAN_WIDTH_40] = 40,
283+ [NL80211_CHAN_WIDTH_80] = 80,
284+ [NL80211_CHAN_WIDTH_80P80] = 80,
285+ [NL80211_CHAN_WIDTH_160] = 160,
286+ };
287+
developer2cbf2fb2022-11-16 12:20:48 +0800288+ if (!mphy->cap.has_5ghz || !freq) {
developerb81e95d2022-11-08 10:16:29 +0800289+ ret = -EINVAL;
290+ dev_info(dev->mt76.dev, "Failed to set offchan (invalid band or channel)!\n");
291+ goto out;
292+ }
293+
294+ chandef.width = td->offchan_bw;
295+ width_mhz = bw_to_mhz[chandef.width];
296+ chandef.center_freq1 = freq;
297+ chan = ieee80211_get_channel(hw->wiphy, freq);
298+ chandef.chan = chan;
299+
300+ memset(&dev->rdd2_chandef, 0, sizeof(struct cfg80211_chan_def));
301+
302+ ret = mt7915_mcu_rdd_background_enable(phy, &chandef);
303+
304+ if (ret)
305+ goto out;
306+
307+ dev->rdd2_phy = phy;
308+ dev->rdd2_chandef = chandef;
309+
310+ return ret;
311+
312+out:
313+ td->offchan_ch = 0;
314+ td->offchan_bw = 0;
315+
316+ return ret;
317+}
318+
319+static void
320+mt7915_tm_dump_ipi(struct mt7915_phy *phy, void *data, u8 antenna_num,
321+ u8 start_antenna_idx, bool is_scan)
322+{
323+#define PRECISION 100
324+ struct mt7915_dev *dev = phy->dev;
325+ struct mt76_testmode_data *td = &phy->mt76->test;
326+ struct mt7915_mcu_rdd_ipi_scan *scan_data;
327+ struct mt7915_mcu_rdd_ipi_ctrl *ctrl_data;
328+ u32 ipi_idx, ipi_free_count, ipi_percentage, ipi_hist_count_th, ipi_hist_total_count;
329+ u32 self_idle_ratio, ipi_idle_ratio, channel_load, tx_assert_time;
330+ u8 i, antenna_idx = start_antenna_idx;
331+ u32 *ipi_hist_data;
332+ const char *power_lower_bound, *power_upper_bound;
333+ static const char * const ipi_idx_to_power_bound[] = {
334+ [RDD_IPI_HIST_0] = "-92",
335+ [RDD_IPI_HIST_1] = "-89",
336+ [RDD_IPI_HIST_2] = "-86",
337+ [RDD_IPI_HIST_3] = "-83",
338+ [RDD_IPI_HIST_4] = "-80",
339+ [RDD_IPI_HIST_5] = "-75",
340+ [RDD_IPI_HIST_6] = "-70",
341+ [RDD_IPI_HIST_7] = "-65",
342+ [RDD_IPI_HIST_8] = "-60",
343+ [RDD_IPI_HIST_9] = "-55",
344+ [RDD_IPI_HIST_10] = "inf",
345+ };
346+
347+ if (is_scan) {
348+ scan_data = (struct mt7915_mcu_rdd_ipi_scan *)data;
349+ tx_assert_time = scan_data->tx_assert_time;
350+ } else {
351+ ctrl_data = (struct mt7915_mcu_rdd_ipi_ctrl *)data;
352+ tx_assert_time = ctrl_data->tx_assert_time;
353+ }
354+
355+ for (i = 0; i < antenna_num; i++) {
356+ ipi_free_count = 0;
357+ ipi_hist_count_th = 0;
358+ ipi_hist_total_count = 0;
359+ ipi_hist_data = is_scan ? scan_data->ipi_hist_val[antenna_idx] :
360+ ctrl_data->ipi_hist_val;
361+
362+ dev_info(dev->mt76.dev, "Antenna index: %d\n", antenna_idx);
363+ for (ipi_idx = 0; ipi_idx < POWER_INDICATE_HIST_MAX; ipi_idx++) {
364+ power_lower_bound = ipi_idx ? ipi_idx_to_power_bound[ipi_idx - 1] :
365+ "-inf";
366+ power_upper_bound = ipi_idx_to_power_bound[ipi_idx];
367+
368+ dev_info(dev->mt76.dev,
369+ "IPI %d (power range: (%s, %s] dBm): ipi count = %d\n",
370+ ipi_idx, power_lower_bound,
371+ power_upper_bound, ipi_hist_data[ipi_idx]);
372+
373+ if (td->ipi_threshold <= ipi_idx && ipi_idx <= RDD_IPI_HIST_10)
374+ ipi_hist_count_th += ipi_hist_data[ipi_idx];
375+
376+ ipi_hist_total_count += ipi_hist_data[ipi_idx];
377+ }
378+ ipi_free_count = is_scan ? ipi_hist_total_count :
379+ ipi_hist_data[RDD_IPI_FREE_RUN_CNT];
380+
381+ dev_info(dev->mt76.dev,
382+ "IPI threshold %d: ipi_hist_count_th = %d, ipi_free_count = %d\n",
383+ td->ipi_threshold, ipi_hist_count_th, ipi_free_count);
384+ dev_info(dev->mt76.dev, "TX assert time = %d [ms]\n",
385+ tx_assert_time / 1000);
386+
387+ // Calculate channel load = (self idle ratio - idle ratio) / self idle ratio
388+ if (ipi_hist_count_th >= UINT_MAX / (100 * PRECISION))
389+ ipi_percentage = 100 * PRECISION *
390+ (ipi_hist_count_th / (100 * PRECISION)) /
391+ (ipi_free_count / (100 * PRECISION));
392+ else
393+ ipi_percentage = PRECISION * 100 * ipi_hist_count_th / ipi_free_count;
394+
395+ ipi_idle_ratio = ((100 * PRECISION) - ipi_percentage) / PRECISION;
396+
397+ self_idle_ratio = PRECISION * 100 *
398+ (td->ipi_period - (tx_assert_time / 1000)) /
399+ td->ipi_period / PRECISION;
400+
401+ if (self_idle_ratio < ipi_idle_ratio)
402+ channel_load = 0;
403+ else
404+ channel_load = self_idle_ratio - ipi_idle_ratio;
405+
406+ if (self_idle_ratio <= td->ipi_threshold) {
407+ dev_info(dev->mt76.dev,
408+ "band[%d]: self idle ratio = %d%%, idle ratio = %d%%\n",
409+ phy->band_idx, self_idle_ratio, ipi_idle_ratio);
410+ return;
411+ }
412+
413+ channel_load = (100 * channel_load) / self_idle_ratio;
414+ dev_info(dev->mt76.dev,
415+ "band[%d]: chan load = %d%%, self idle ratio = %d%%, idle ratio = %d%%\n",
416+ phy->band_idx, channel_load, self_idle_ratio, ipi_idle_ratio);
417+ antenna_idx++;
418+ }
419+}
420+
421+static void
422+mt7915_tm_ipi_work(struct work_struct *work)
423+{
424+ struct mt7915_phy *phy = container_of(work, struct mt7915_phy, ipi_work.work);
425+ struct mt7915_dev *dev = phy->dev;
426+ struct mt76_testmode_data *td = &phy->mt76->test;
427+ u8 start_antenna_idx = 0, antenna_num = 1;
428+
429+ if (!is_mt7915(&dev->mt76)) {
430+ struct mt7915_mcu_rdd_ipi_scan data;
431+
432+ if (phy->band_idx)
433+ start_antenna_idx = 4;
434+
435+ /* Use all antenna */
436+ if (td->ipi_antenna_idx == MT76_TM_IPI_ANTENNA_ALL)
437+ antenna_num = 4;
438+ else
439+ start_antenna_idx += td->ipi_antenna_idx;
440+
441+ mt7915_mcu_ipi_hist_scan(phy, &data, 0, true);
442+ mt7915_tm_dump_ipi(phy, &data, antenna_num, start_antenna_idx, true);
443+ } else {
444+ struct mt7915_mcu_rdd_ipi_ctrl data;
445+
developer2cbf2fb2022-11-16 12:20:48 +0800446+ start_antenna_idx = 4;
developerb81e95d2022-11-08 10:16:29 +0800447+ mt7915_mcu_ipi_hist_ctrl(phy, &data, RDD_IPI_HIST_ALL_CNT, true);
448+ mt7915_tm_dump_ipi(phy, &data, antenna_num, start_antenna_idx, false);
449+ }
450+}
451+
developer2cbf2fb2022-11-16 12:20:48 +0800452+static inline void
453+mt7915_tm_reset_ipi(struct mt7915_phy *phy)
454+{
455+#define IPI_RESET_BIT BIT(2)
456+ struct mt7915_dev *dev = phy->dev;
457+
458+ if (is_mt7915(&dev->mt76))
459+ mt7915_mcu_ipi_hist_ctrl(phy, NULL, RDD_SET_IPI_HIST_RESET, false);
460+ else
461+ mt76_set(dev, MT_WF_IPI_RESET, IPI_RESET_BIT);
462+}
463+
developerb81e95d2022-11-08 10:16:29 +0800464+static int
465+mt7915_tm_set_ipi(struct mt7915_phy *phy)
466+{
467+ struct mt76_testmode_data *td = &phy->mt76->test;
468+
developer2cbf2fb2022-11-16 12:20:48 +0800469+ mt7915_tm_reset_ipi(phy);
470+
developerb81e95d2022-11-08 10:16:29 +0800471+ cancel_delayed_work(&phy->ipi_work);
472+ ieee80211_queue_delayed_work(phy->mt76->hw, &phy->ipi_work,
473+ msecs_to_jiffies(td->ipi_period));
474+
475+ return 0;
476+}
477+
478 static int
479 mt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min,
480 u16 cw_max, u16 txop, u8 tx_cmd)
developer2cbf2fb2022-11-16 12:20:48 +0800481@@ -1247,6 +1469,8 @@ mt7915_tm_init(struct mt7915_phy *phy, bool en)
developerb81e95d2022-11-08 10:16:29 +0800482 phy->mt76->test.tx_mpdu_len = 0;
483 phy->test.bf_en = 0;
484 mt7915_tm_set_entry(phy);
485+ } else {
486+ INIT_DELAYED_WORK(&phy->ipi_work, mt7915_tm_ipi_work);
487 }
488 }
489
developer3d5faf22022-11-29 18:07:22 +0800490@@ -2005,6 +2229,14 @@ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
developerb81e95d2022-11-08 10:16:29 +0800491 mt7915_tm_set_cfg(phy);
492 if (changed & BIT(TM_CHANGED_TXBF_ACT))
493 mt7915_tm_set_txbf(phy);
494+ if ((changed & BIT(TM_CHANGED_OFF_CHAN_CH)) &&
495+ (changed & BIT(TM_CHANGED_OFF_CHAN_BW)))
496+ mt7915_tm_set_offchan(phy);
497+ if ((changed & BIT(TM_CHANGED_IPI_THRESHOLD)) &&
498+ (changed & BIT(TM_CHANGED_IPI_PERIOD)))
499+ mt7915_tm_set_ipi(phy);
developer2cbf2fb2022-11-16 12:20:48 +0800500+ if (changed & BIT(TM_CHANGED_IPI_RESET))
501+ mt7915_tm_reset_ipi(phy);
developerb81e95d2022-11-08 10:16:29 +0800502 }
503
504 static int
505diff --git a/testmode.c b/testmode.c
developer2cbf2fb2022-11-16 12:20:48 +0800506index aa874a83..b19b872a 100644
developerb81e95d2022-11-08 10:16:29 +0800507--- a/testmode.c
508+++ b/testmode.c
developer2cbf2fb2022-11-16 12:20:48 +0800509@@ -24,6 +24,13 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
developerb81e95d2022-11-08 10:16:29 +0800510 [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 },
511 [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 },
512 [MT76_TM_ATTR_DRV_DATA] = { .type = NLA_NESTED },
513+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
514+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
515+ [MT76_TM_ATTR_OFF_CH_SCAN_PATH] = { .type = NLA_U8 },
516+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
517+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
518+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
developer2cbf2fb2022-11-16 12:20:48 +0800519+ [MT76_TM_ATTR_IPI_RESET] = { .type = NLA_U8 },
developerb81e95d2022-11-08 10:16:29 +0800520 };
521 EXPORT_SYMBOL_GPL(mt76_tm_policy);
522
developer2cbf2fb2022-11-16 12:20:48 +0800523@@ -402,6 +409,7 @@ mt76_testmode_init_defaults(struct mt76_phy *phy)
developerb81e95d2022-11-08 10:16:29 +0800524 td->tx_count = 1;
525 td->tx_rate_mode = MT76_TM_TX_MODE_OFDM;
526 td->tx_rate_nss = 1;
527+ td->ipi_antenna_idx = MT76_TM_IPI_ANTENNA_ALL;
528
529 memcpy(td->addr[0], phy->macaddr, ETH_ALEN);
530 memcpy(td->addr[1], phy->macaddr, ETH_ALEN);
developer2cbf2fb2022-11-16 12:20:48 +0800531@@ -607,6 +615,9 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developerb81e95d2022-11-08 10:16:29 +0800532 if (tb[MT76_TM_ATTR_TX_RATE_IDX])
533 td->tx_rate_idx = nla_get_u8(tb[MT76_TM_ATTR_TX_RATE_IDX]);
534
535+ if (tb[MT76_TM_ATTR_IPI_PERIOD])
536+ td->ipi_period = nla_get_u32(tb[MT76_TM_ATTR_IPI_PERIOD]);
537+
538 if (mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_MODE], &td->tx_rate_mode,
539 0, MT76_TM_TX_MODE_MAX) ||
540 mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_NSS], &td->tx_rate_nss,
developer2cbf2fb2022-11-16 12:20:48 +0800541@@ -623,7 +634,16 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
developerb81e95d2022-11-08 10:16:29 +0800542 &td->tx_power_control, 0, 1) ||
543 mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16) ||
544 mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_ALLOC], &td->ru_alloc, 0, 0xff) ||
545- mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_IDX], &td->ru_idx, 0, 68))
546+ mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_IDX], &td->ru_idx, 0, 68) ||
547+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CH], &td->offchan_ch, 36, 196) ||
548+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH], &td->offchan_center_ch,
549+ 36, 196) ||
550+ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_BW],
551+ &td->offchan_bw, NL80211_CHAN_WIDTH_20_NOHT, NL80211_CHAN_WIDTH_160) ||
552+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_THRESHOLD], &td->ipi_threshold, 0, 10) ||
553+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_ANTENNA_INDEX], &td->ipi_antenna_idx,
developer2cbf2fb2022-11-16 12:20:48 +0800554+ MT76_TM_IPI_ANTENNA_0, MT76_TM_IPI_ANTENNA_ALL) ||
555+ mt76_tm_get_u8(tb[MT76_TM_ATTR_IPI_RESET], &td->ipi_reset, 0, 1))
developerb81e95d2022-11-08 10:16:29 +0800556 goto out;
557
558 if (tb[MT76_TM_ATTR_TX_LENGTH]) {
developer2cbf2fb2022-11-16 12:20:48 +0800559@@ -857,6 +877,9 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
developerb81e95d2022-11-08 10:16:29 +0800560 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) ||
561 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
562 nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
563+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CH, td->offchan_ch) ||
564+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH, td->offchan_center_ch) ||
565+ nla_put_u8(msg, MT76_TM_ATTR_OFF_CH_SCAN_BW, td->offchan_bw) ||
566 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
567 nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
568 (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
569diff --git a/testmode.h b/testmode.h
developer2cbf2fb2022-11-16 12:20:48 +0800570index 5d1fe793..27a00953 100644
developerb81e95d2022-11-08 10:16:29 +0800571--- a/testmode.h
572+++ b/testmode.h
developer2cbf2fb2022-11-16 12:20:48 +0800573@@ -63,6 +63,20 @@
developerb81e95d2022-11-08 10:16:29 +0800574 * (nested, u8 attrs)
575 *
576 * @MT76_TM_ATTR_CFG: config testmode rf feature (nested, see &mt76_testmode_cfg)
577+ * @MT76_TM_ATTR_TXBF_ACT: txbf setting actions (u8)
578+ * @MT76_TM_ATTR_TXBF_PARAM: txbf parameters (nested)
579+ *
580+ * @MT76_TM_ATTR_OFF_CH_SCAN_CH: config the channel of background chain (ZWDFS) (u8)
581+ * @MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH: config the center channel of background chain (ZWDFS) (u8)
582+ * @MT76_TM_ATTR_OFF_CH_SCAN_BW: config the bandwidth of background chain (ZWDFS) (u8)
583+ * @MT76_TM_ATTR_OFF_CH_SCAN_PATH: config the tx path of background chain (ZWDFS) (u8)
584+ *
585+ * @MT76_TM_ATTR_IPI_THRESHOLD: config the IPI index you want to read (u8)
586+ * @MT76_TM_ATTR_IPI_PERIOD: config the time period for reading
587+ * the histogram of specific IPI index (u8)
588+ * @MT76_TM_ATTR_IPI_ANTENNA_INDEX: config the antenna index for reading
589+ * the histogram of specific IPI index (u8)
developer2cbf2fb2022-11-16 12:20:48 +0800590+ * @MT76_TM_ATTR_IPI_RESET: Reset the IPI counter
developerb81e95d2022-11-08 10:16:29 +0800591 *
592 */
593 enum mt76_testmode_attr {
developer2cbf2fb2022-11-16 12:20:48 +0800594@@ -116,6 +130,16 @@ enum mt76_testmode_attr {
developerb81e95d2022-11-08 10:16:29 +0800595 MT76_TM_ATTR_TXBF_ACT,
596 MT76_TM_ATTR_TXBF_PARAM,
597
598+ MT76_TM_ATTR_OFF_CH_SCAN_CH,
599+ MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH,
600+ MT76_TM_ATTR_OFF_CH_SCAN_BW,
601+ MT76_TM_ATTR_OFF_CH_SCAN_PATH,
602+
603+ MT76_TM_ATTR_IPI_THRESHOLD,
604+ MT76_TM_ATTR_IPI_PERIOD,
605+ MT76_TM_ATTR_IPI_ANTENNA_INDEX,
developer2cbf2fb2022-11-16 12:20:48 +0800606+ MT76_TM_ATTR_IPI_RESET,
developerb81e95d2022-11-08 10:16:29 +0800607+
608 /* keep last */
609 NUM_MT76_TM_ATTRS,
610 MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1,
developer2cbf2fb2022-11-16 12:20:48 +0800611@@ -292,4 +316,25 @@ enum mt76_testmode_txbf_act {
developerb81e95d2022-11-08 10:16:29 +0800612 MT76_TM_TXBF_ACT_MAX = NUM_MT76_TM_TXBF_ACT - 1,
613 };
614
615+/**
616+ * enum mt76_testmode_ipi_antenna - specify antenna index for ipi count
617+ *
618+ * @MT76_TM_IPI_ANTENNA_0: use antenna 0
619+ * @MT76_TM_IPI_ANTENNA_1: use antenna 1
620+ * @MT76_TM_IPI_ANTENNA_2: use antenna 2
621+ * @MT76_TM_IPI_ANTENNA_3: use antenna 3
622+ * @MT76_TM_IPI_ANTENNA_ALL: use all antenna
623+ */
624+enum mt76_testmode_ipi_antenna {
625+ MT76_TM_IPI_ANTENNA_0,
626+ MT76_TM_IPI_ANTENNA_1,
627+ MT76_TM_IPI_ANTENNA_2,
628+ MT76_TM_IPI_ANTENNA_3,
629+ MT76_TM_IPI_ANTENNA_ALL,
630+
631+ /* keep last */
632+ NUM_MT76_TM_IPI_ANTENNA,
633+ MT76_TM_IPI_ANTENNA_MAX = NUM_MT76_TM_IPI_ANTENNA - 1,
634+};
635+
636 #endif
637diff --git a/tools/fields.c b/tools/fields.c
developer2cbf2fb2022-11-16 12:20:48 +0800638index 47fc69f9..6f07eed0 100644
developerb81e95d2022-11-08 10:16:29 +0800639--- a/tools/fields.c
640+++ b/tools/fields.c
641@@ -46,6 +46,14 @@ static const char * const testmode_txbf_act[] = {
642 [MT76_TM_TXBF_ACT_E2P_UPDATE] = "e2p_update",
643 };
644
645+static const char * const testmode_offchan_bw[] = {
646+ [NL80211_CHAN_WIDTH_20_NOHT] = "NOHT",
647+ [NL80211_CHAN_WIDTH_20] = "20",
648+ [NL80211_CHAN_WIDTH_40] = "40",
649+ [NL80211_CHAN_WIDTH_80] = "80",
650+ [NL80211_CHAN_WIDTH_160] = "160",
651+};
652+
653 static void print_enum(const struct tm_field *field, struct nlattr *attr)
654 {
655 unsigned int i = nla_get_u8(attr);
developer2cbf2fb2022-11-16 12:20:48 +0800656@@ -411,6 +419,13 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = {
developerb81e95d2022-11-08 10:16:29 +0800657 FIELD(u8, RU_IDX, "ru_idx"),
658 FIELD_ENUM(TXBF_ACT, "txbf_act", testmode_txbf_act),
659 FIELD_ARRAY(u16_hex, TXBF_PARAM, "txbf_param"),
660+ FIELD(u8, OFF_CH_SCAN_CH, "offchan_ch"),
661+ FIELD(u8, OFF_CH_SCAN_CENTER_CH, "offchan_center_ch"),
662+ FIELD_ENUM(OFF_CH_SCAN_BW, "offchan_bw", testmode_offchan_bw),
663+ FIELD(u8, IPI_THRESHOLD, "ipi_threshold"),
664+ FIELD(u32, IPI_PERIOD, "ipi_period"),
665+ FIELD(u8, IPI_ANTENNA_INDEX, "ipi_antenna_idx"),
developer2cbf2fb2022-11-16 12:20:48 +0800666+ FIELD(u8, IPI_RESET, "ipi_reset"),
developerb81e95d2022-11-08 10:16:29 +0800667 FIELD_MAC(MAC_ADDRS, "mac_addrs"),
668 FIELD_NESTED_RO(STATS, stats, "",
669 .print_extra = print_extra_stats),
developer2cbf2fb2022-11-16 12:20:48 +0800670@@ -442,6 +457,13 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = {
developerb81e95d2022-11-08 10:16:29 +0800671 [MT76_TM_ATTR_RU_IDX] = { .type = NLA_U8 },
672 [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED },
673 [MT76_TM_ATTR_TXBF_ACT] = { .type = NLA_U8 },
674+ [MT76_TM_ATTR_OFF_CH_SCAN_CH] = { .type = NLA_U8 },
675+ [MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH] = { .type = NLA_U8 },
676+ [MT76_TM_ATTR_OFF_CH_SCAN_BW] = { .type = NLA_U8 },
677+ [MT76_TM_ATTR_IPI_THRESHOLD] = { .type = NLA_U8 },
678+ [MT76_TM_ATTR_IPI_PERIOD] = { .type = NLA_U32 },
679+ [MT76_TM_ATTR_IPI_ANTENNA_INDEX] = { .type = NLA_U8 },
developer2cbf2fb2022-11-16 12:20:48 +0800680+ [MT76_TM_ATTR_IPI_RESET] = { .type = NLA_U8 },
developerb81e95d2022-11-08 10:16:29 +0800681 };
682
683 const struct tm_field msg_field = {
684--
6852.18.0
686