developer | 064da3c | 2023-06-13 15:57:26 +0800 | [diff] [blame] | 1 | From 639385416a573ae5ce631a0323c5541dea3e406c Mon Sep 17 00:00:00 2001 |
| 2 | From: StanleyYP Wang <StanleyYP.Wang@mediatek.com> |
| 3 | Date: Wed, 22 Mar 2023 11:19:52 +0800 |
| 4 | Subject: [PATCH 1010/1015] wifi: mt76: testmode: add testmode ZWDFS |
| 5 | verification support |
| 6 | |
| 7 | Signed-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 | |
| 17 | diff --git a/mt76.h b/mt76.h |
| 18 | index 7d6e3241..5b442691 100644 |
| 19 | --- a/mt76.h |
| 20 | +++ b/mt76.h |
| 21 | @@ -732,6 +732,14 @@ struct mt76_testmode_data { |
| 22 | } 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 { |
| 36 | diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| 37 | index 94b62211..abdbb1ef 100644 |
| 38 | --- a/mt7996/mt7996.h |
| 39 | +++ b/mt7996/mt7996.h |
| 40 | @@ -295,6 +295,7 @@ struct mt7996_phy { |
| 41 | |
| 42 | struct mib_stats mib; |
| 43 | struct mt76_channel_state state_ts; |
| 44 | + struct delayed_work ipi_work; |
| 45 | |
| 46 | bool has_aux_rx; |
| 47 | |
| 48 | diff --git a/mt7996/testmode.c b/mt7996/testmode.c |
| 49 | index 7d36902e..ba3cd802 100644 |
| 50 | --- a/mt7996/testmode.c |
| 51 | +++ b/mt7996/testmode.c |
| 52 | @@ -16,6 +16,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 | @@ -27,20 +33,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 | @@ -853,6 +1071,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 |
| 338 | diff --git a/mt7996/testmode.h b/mt7996/testmode.h |
| 339 | index 778c9bc6..09f81d39 100644 |
| 340 | --- 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 | @@ -308,4 +314,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 |
| 401 | diff --git a/testmode.c b/testmode.c |
| 402 | index 74bb26fa..22d6afd4 100644 |
| 403 | --- a/testmode.c |
| 404 | +++ b/testmode.c |
| 405 | @@ -25,6 +25,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 | @@ -451,6 +458,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 | @@ -466,7 +476,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 | @@ -671,6 +688,9 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, |
| 446 | nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) || |
| 447 | nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) || |
| 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) && |
| 455 | diff --git a/tools/fields.c b/tools/fields.c |
| 456 | index b22b3fc8..55854a6f 100644 |
| 457 | --- 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 | @@ -387,6 +396,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 | -- |
| 489 | 2.39.2 |
| 490 | |