developer | 5f11e9e | 2022-03-10 15:03:47 +0800 | [diff] [blame] | 1 | diff --git a/package/kernel/mt76/patches/1006-mt76-mt7915-testmode-patches.patch b/package/kernel/mt76/patches/1006-mt76-mt7915-testmode-patches.patch |
| 2 | new file mode 100644 |
| 3 | index 00000000..002d1fcb |
| 4 | --- /dev/null |
| 5 | +++ b/package/kernel/mt76/patches/1006-mt76-mt7915-testmode-patches.patch |
| 6 | @@ -0,0 +1,2014 @@ |
| 7 | +From cdb7bc7976835e2b96ae5f19392a793d1895fd4f Mon Sep 17 00:00:00 2001 |
| 8 | +From: Shayne Chen <shayne.chen@mediatek.com> |
| 9 | +Date: Wed, 19 Jan 2022 15:46:06 +0800 |
| 10 | +Subject: [PATCH 1006/1006] mt76: mt7915: testmode patches |
| 11 | + |
| 12 | +--- |
| 13 | + drivers/net/wireless/mediatek/mt76/mac80211.c | 18 +- |
| 14 | + drivers/net/wireless/mediatek/mt76/mt76.h | 123 ++++- |
| 15 | + .../wireless/mediatek/mt76/mt76_connac_mcu.c | 5 + |
| 16 | + .../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 + |
| 17 | + .../net/wireless/mediatek/mt76/mt7915/init.c | 2 +- |
| 18 | + .../net/wireless/mediatek/mt76/mt7915/mac.c | 26 +- |
| 19 | + .../net/wireless/mediatek/mt76/mt7915/mcu.c | 13 +- |
| 20 | + .../net/wireless/mediatek/mt76/mt7915/mcu.h | 5 + |
| 21 | + .../net/wireless/mediatek/mt76/mt7915/mmio.c | 2 + |
| 22 | + .../wireless/mediatek/mt76/mt7915/mt7915.h | 2 +- |
| 23 | + .../net/wireless/mediatek/mt76/mt7915/regs.h | 16 +- |
| 24 | + .../wireless/mediatek/mt76/mt7915/testmode.c | 513 +++++++++++++++--- |
| 25 | + .../wireless/mediatek/mt76/mt7915/testmode.h | 38 ++ |
| 26 | + drivers/net/wireless/mediatek/mt76/testmode.c | 276 ++++++++-- |
| 27 | + drivers/net/wireless/mediatek/mt76/testmode.h | 71 +++ |
| 28 | + .../net/wireless/mediatek/mt76/tools/fields.c | 76 +++ |
| 29 | + drivers/net/wireless/mediatek/mt76/tx.c | 3 +- |
| 30 | + 17 files changed, 1048 insertions(+), 142 deletions(-) |
| 31 | + |
| 32 | +diff --git a/mac80211.c b/mac80211.c |
| 33 | +index 9796419..e473227 100644 |
| 34 | +--- a/mac80211.c |
| 35 | ++++ b/mac80211.c |
| 36 | +@@ -45,6 +45,9 @@ static const struct ieee80211_channel mt76_channels_2ghz[] = { |
| 37 | + }; |
| 38 | + |
| 39 | + static const struct ieee80211_channel mt76_channels_5ghz[] = { |
| 40 | ++ CHAN5G(12, 5060), |
| 41 | ++ CHAN5G(16, 5080), |
| 42 | ++ |
| 43 | + CHAN5G(36, 5180), |
| 44 | + CHAN5G(40, 5200), |
| 45 | + CHAN5G(44, 5220), |
| 46 | +@@ -55,6 +58,13 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { |
| 47 | + CHAN5G(60, 5300), |
| 48 | + CHAN5G(64, 5320), |
| 49 | + |
| 50 | ++ CHAN5G(68, 5340), |
| 51 | ++ CHAN5G(80, 5400), |
| 52 | ++ CHAN5G(84, 5420), |
| 53 | ++ CHAN5G(88, 5440), |
| 54 | ++ CHAN5G(92, 5460), |
| 55 | ++ CHAN5G(96, 5480), |
| 56 | ++ |
| 57 | + CHAN5G(100, 5500), |
| 58 | + CHAN5G(104, 5520), |
| 59 | + CHAN5G(108, 5540), |
| 60 | +@@ -75,6 +85,11 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = { |
| 61 | + CHAN5G(165, 5825), |
| 62 | + CHAN5G(169, 5845), |
| 63 | + CHAN5G(173, 5865), |
| 64 | ++ |
| 65 | ++ CHAN5G(184, 4920), |
| 66 | ++ CHAN5G(188, 4940), |
| 67 | ++ CHAN5G(192, 4960), |
| 68 | ++ CHAN5G(196, 4980), |
| 69 | + }; |
| 70 | + |
| 71 | + static const struct ieee80211_channel mt76_channels_6ghz[] = { |
| 72 | +@@ -737,7 +752,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb) |
| 73 | + } |
| 74 | + |
| 75 | + #ifdef CONFIG_NL80211_TESTMODE |
| 76 | +- if (phy->test.state == MT76_TM_STATE_RX_FRAMES) { |
| 77 | ++ if (!(phy->test.flag & MT_TM_FW_RX_COUNT) && |
| 78 | ++ phy->test.state == MT76_TM_STATE_RX_FRAMES) { |
| 79 | + phy->test.rx_stats.packets[q]++; |
| 80 | + if (status->flag & RX_FLAG_FAILED_FCS_CRC) |
| 81 | + phy->test.rx_stats.fcs_error[q]++; |
| 82 | +diff --git a/mt76.h b/mt76.h |
| 83 | +index 5e10fe1..4b502c6 100644 |
| 84 | +--- a/mt76.h |
| 85 | ++++ b/mt76.h |
| 86 | +@@ -581,6 +581,25 @@ struct mt76_testmode_ops { |
| 87 | + int (*set_params)(struct mt76_phy *phy, struct nlattr **tb, |
| 88 | + enum mt76_testmode_state new_state); |
| 89 | + int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg); |
| 90 | ++ int (*set_eeprom)(struct mt76_phy *phy, u32 offset, u8 *val, u8 action); |
| 91 | ++}; |
| 92 | ++ |
| 93 | ++#define MT_TM_FW_RX_COUNT BIT(0) |
| 94 | ++ |
| 95 | ++struct mt76_testmode_sta_data { |
| 96 | ++ u16 tx_mpdu_len; |
| 97 | ++ u8 tx_rate_idx; |
| 98 | ++ u8 tx_rate_nss; |
| 99 | ++ u8 tx_rate_ldpc; |
| 100 | ++ |
| 101 | ++ u8 aid; |
| 102 | ++ u8 ru_alloc; |
| 103 | ++ u8 ru_idx; |
| 104 | ++}; |
| 105 | ++ |
| 106 | ++struct mt76_testmode_sta { |
| 107 | ++ struct sk_buff *tx_skb; |
| 108 | ++ struct mt76_testmode_sta_data sd; |
| 109 | + }; |
| 110 | + |
| 111 | + struct mt76_testmode_data { |
| 112 | +@@ -590,13 +609,9 @@ struct mt76_testmode_data { |
| 113 | + struct sk_buff *tx_skb; |
| 114 | + |
| 115 | + u32 tx_count; |
| 116 | +- u16 tx_mpdu_len; |
| 117 | + |
| 118 | + u8 tx_rate_mode; |
| 119 | +- u8 tx_rate_idx; |
| 120 | +- u8 tx_rate_nss; |
| 121 | + u8 tx_rate_sgi; |
| 122 | +- u8 tx_rate_ldpc; |
| 123 | + u8 tx_rate_stbc; |
| 124 | + u8 tx_ltf; |
| 125 | + |
| 126 | +@@ -614,6 +629,35 @@ struct mt76_testmode_data { |
| 127 | + |
| 128 | + u8 addr[3][ETH_ALEN]; |
| 129 | + |
| 130 | ++ u8 flag; |
| 131 | ++ |
| 132 | ++ struct { |
| 133 | ++ u8 type; |
| 134 | ++ u8 enable; |
| 135 | ++ } cfg; |
| 136 | ++ |
| 137 | ++ u8 off_ch_scan_ch; |
| 138 | ++ u8 off_ch_scan_center_ch; |
| 139 | ++ u8 off_ch_scan_bw; |
| 140 | ++ u8 off_ch_scan_path; |
| 141 | ++ |
| 142 | ++ struct mt76_wcid *tm_wcid[MT76_TM_MAX_STA_NUM + 1]; |
| 143 | ++ u8 cur_aid; |
| 144 | ++ u16 tm_sta_mask; |
| 145 | ++ union { |
| 146 | ++ struct mt76_testmode_sta_data sd; |
| 147 | ++ struct { |
| 148 | ++ u16 tx_mpdu_len; |
| 149 | ++ u8 tx_rate_idx; |
| 150 | ++ u8 tx_rate_nss; |
| 151 | ++ u8 tx_rate_ldpc; |
| 152 | ++ |
| 153 | ++ u8 aid; |
| 154 | ++ u8 ru_alloc; |
| 155 | ++ u8 ru_idx; |
| 156 | ++ }; |
| 157 | ++ }; |
| 158 | ++ |
| 159 | + u32 tx_pending; |
| 160 | + u32 tx_queued; |
| 161 | + u16 tx_queued_limit; |
| 162 | +@@ -621,6 +665,7 @@ struct mt76_testmode_data { |
| 163 | + struct { |
| 164 | + u64 packets[__MT_RXQ_MAX]; |
| 165 | + u64 fcs_error[__MT_RXQ_MAX]; |
| 166 | ++ u64 len_mismatch; |
| 167 | + } rx_stats; |
| 168 | + }; |
| 169 | + |
| 170 | +@@ -1091,22 +1136,69 @@ static inline bool mt76_testmode_enabled(struct mt76_phy *phy) |
| 171 | + #endif |
| 172 | + } |
| 173 | + |
| 174 | ++#ifdef CONFIG_NL80211_TESTMODE |
| 175 | ++static inline bool |
| 176 | ++mt76_testmode_has_sta(struct mt76_phy *phy) |
| 177 | ++{ |
| 178 | ++ return phy->test.tm_sta_mask != 0; |
| 179 | ++} |
| 180 | ++ |
| 181 | ++static inline struct mt76_testmode_sta * |
| 182 | ++mt76_testmode_aid_get_sta(struct mt76_phy *phy, u8 aid) |
| 183 | ++{ |
| 184 | ++ struct mt76_wcid *wcid = phy->test.tm_wcid[aid]; |
| 185 | ++ |
| 186 | ++ if (!wcid || !aid) |
| 187 | ++ return NULL; |
| 188 | ++ |
| 189 | ++ return (struct mt76_testmode_sta *)((u8 *)wcid + phy->hw->sta_data_size); |
| 190 | ++} |
| 191 | ++ |
| 192 | ++#define mt76_testmode_for_each_sta(phy, aid, tm_sta) \ |
| 193 | ++ for (aid = 1, tm_sta = mt76_testmode_aid_get_sta(phy, 1); \ |
| 194 | ++ aid <= hweight16(phy->test.tm_sta_mask); \ |
| 195 | ++ aid = phy->test.tm_sta_mask >> aid ? \ |
| 196 | ++ ffs(phy->test.tm_sta_mask >> aid) + aid : \ |
| 197 | ++ aid + 1, \ |
| 198 | ++ tm_sta = mt76_testmode_aid_get_sta(phy, aid)) |
| 199 | ++ |
| 200 | ++static inline bool |
| 201 | ++__mt76_testmode_check_skb(struct mt76_phy *phy, struct sk_buff *skb) |
| 202 | ++{ |
| 203 | ++ struct mt76_testmode_sta *tm_sta; |
| 204 | ++ int i; |
| 205 | ++ |
| 206 | ++ if (!mt76_testmode_has_sta(phy)) |
| 207 | ++ return false; |
| 208 | ++ |
| 209 | ++ mt76_testmode_for_each_sta(phy, i, tm_sta) { |
| 210 | ++ if (tm_sta->tx_skb == skb) |
| 211 | ++ return true; |
| 212 | ++ } |
| 213 | ++ |
| 214 | ++ return false; |
| 215 | ++} |
| 216 | ++ |
| 217 | + static inline bool mt76_is_testmode_skb(struct mt76_dev *dev, |
| 218 | + struct sk_buff *skb, |
| 219 | + struct ieee80211_hw **hw) |
| 220 | + { |
| 221 | +-#ifdef CONFIG_NL80211_TESTMODE |
| 222 | +- if (skb == dev->phy.test.tx_skb) |
| 223 | +- *hw = dev->phy.hw; |
| 224 | +- else if (dev->phy2 && skb == dev->phy2->test.tx_skb) |
| 225 | +- *hw = dev->phy2->hw; |
| 226 | +- else |
| 227 | +- return false; |
| 228 | +- return true; |
| 229 | +-#else |
| 230 | ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
| 231 | ++ struct mt76_phy *phy = &dev->phy; |
| 232 | ++ |
| 233 | ++ if ((info->hw_queue & MT_TX_HW_QUEUE_EXT_PHY) && dev->phy2) |
| 234 | ++ phy = dev->phy2; |
| 235 | ++ |
| 236 | ++ if (mt76_testmode_enabled(phy) && |
| 237 | ++ (skb == phy->test.tx_skb || |
| 238 | ++ __mt76_testmode_check_skb(phy, skb))) { |
| 239 | ++ *hw = phy->hw; |
| 240 | ++ return true; |
| 241 | ++ } |
| 242 | ++ |
| 243 | + return false; |
| 244 | +-#endif |
| 245 | + } |
| 246 | ++#endif |
| 247 | + |
| 248 | + void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb); |
| 249 | + void mt76_tx(struct mt76_phy *dev, struct ieee80211_sta *sta, |
| 250 | +@@ -1198,7 +1290,7 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 251 | + int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb, |
| 252 | + struct netlink_callback *cb, void *data, int len); |
| 253 | + int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state); |
| 254 | +-int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len); |
| 255 | ++int mt76_testmode_init_skb(struct mt76_phy *phy, u32 len, u8 aid, struct sk_buff **skb); |
| 256 | + |
| 257 | + static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable) |
| 258 | + { |
| 259 | +@@ -1212,7 +1304,6 @@ static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable) |
| 260 | + #endif |
| 261 | + } |
| 262 | + |
| 263 | +- |
| 264 | + /* internal */ |
| 265 | + static inline struct ieee80211_hw * |
| 266 | + mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb) |
| 267 | +diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c |
| 268 | +index 0a646ae..9158329 100644 |
| 269 | +--- a/mt76_connac_mcu.c |
| 270 | ++++ b/mt76_connac_mcu.c |
| 271 | +@@ -389,6 +389,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb, |
| 272 | + switch (vif->type) { |
| 273 | + case NL80211_IFTYPE_MESH_POINT: |
| 274 | + case NL80211_IFTYPE_AP: |
| 275 | ++ case NL80211_IFTYPE_MONITOR: |
| 276 | + if (vif->p2p) |
| 277 | + conn_type = CONNECTION_P2P_GC; |
| 278 | + else |
| 279 | +@@ -577,6 +578,10 @@ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, |
| 280 | + wtbl_tlv, sta_wtbl); |
| 281 | + spe = (struct wtbl_spe *)tlv; |
| 282 | + spe->spe_idx = 24; |
| 283 | ++ |
| 284 | ++ /* check */ |
| 285 | ++ if (vif->type == NL80211_IFTYPE_MONITOR) |
| 286 | ++ rx->rca1 = 0; |
| 287 | + } |
| 288 | + EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_generic_tlv); |
| 289 | + |
| 290 | +diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h |
| 291 | +index 8903e08..cb7d096 100644 |
| 292 | +--- a/mt76_connac_mcu.h |
| 293 | ++++ b/mt76_connac_mcu.h |
| 294 | +@@ -987,6 +987,7 @@ enum { |
| 295 | + MCU_EXT_CMD_OFFCH_SCAN_CTRL = 0x9a, |
| 296 | + MCU_EXT_CMD_SET_RDD_TH = 0x9d, |
| 297 | + MCU_EXT_CMD_MURU_CTRL = 0x9f, |
| 298 | ++ MCU_EXT_CMD_RX_STAT = 0xa4, |
| 299 | + MCU_EXT_CMD_SET_SPR = 0xa8, |
| 300 | + MCU_EXT_CMD_GROUP_PRE_CAL_INFO = 0xab, |
| 301 | + MCU_EXT_CMD_DPD_PRE_CAL_INFO = 0xac, |
| 302 | +diff --git a/mt7915/init.c b/mt7915/init.c |
| 303 | +index aed4731..7ec48e0 100644 |
| 304 | +--- a/mt7915/init.c |
| 305 | ++++ b/mt7915/init.c |
| 306 | +@@ -568,7 +568,7 @@ static void mt7915_init_work(struct work_struct *work) |
| 307 | + struct mt7915_dev *dev = container_of(work, struct mt7915_dev, |
| 308 | + init_work); |
| 309 | + |
| 310 | +- mt7915_mcu_set_eeprom(dev); |
| 311 | ++ mt7915_mcu_set_eeprom(dev, dev->flash_mode); |
| 312 | + mt7915_mac_init(dev); |
| 313 | + mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband); |
| 314 | + mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband); |
| 315 | +diff --git a/mt7915/mac.c b/mt7915/mac.c |
| 316 | +index efdc1b1..9a5bb20 100644 |
| 317 | +--- a/mt7915/mac.c |
| 318 | ++++ b/mt7915/mac.c |
| 319 | +@@ -904,16 +904,28 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, |
| 320 | + { |
| 321 | + #ifdef CONFIG_NL80211_TESTMODE |
| 322 | + struct mt76_testmode_data *td = &phy->mt76->test; |
| 323 | ++ struct mt76_testmode_sta_data *sd = &td->sd; |
| 324 | + const struct ieee80211_rate *r; |
| 325 | +- u8 bw, mode, nss = td->tx_rate_nss; |
| 326 | +- u8 rate_idx = td->tx_rate_idx; |
| 327 | ++ u8 bw, mode, nss, rate_idx; |
| 328 | + u16 rateval = 0; |
| 329 | + u32 val; |
| 330 | + bool cck = false; |
| 331 | + int band; |
| 332 | + |
| 333 | +- if (skb != phy->mt76->test.tx_skb) |
| 334 | +- return; |
| 335 | ++ if (mt76_testmode_has_sta(phy->mt76)) { |
| 336 | ++ struct mt76_testmode_sta *tm_sta; |
| 337 | ++ int i; |
| 338 | ++ |
| 339 | ++ mt76_testmode_for_each_sta(phy->mt76, i, tm_sta) { |
| 340 | ++ if (tm_sta->tx_skb == skb) { |
| 341 | ++ sd = &tm_sta->sd; |
| 342 | ++ break; |
| 343 | ++ } |
| 344 | ++ } |
| 345 | ++ } |
| 346 | ++ |
| 347 | ++ nss = sd->tx_rate_nss; |
| 348 | ++ rate_idx = sd->tx_rate_idx; |
| 349 | + |
| 350 | + switch (td->tx_rate_mode) { |
| 351 | + case MT76_TM_TX_MODE_HT: |
| 352 | +@@ -1003,9 +1015,10 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi, |
| 353 | + if (mode >= MT_PHY_TYPE_HE_SU) |
| 354 | + val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf); |
| 355 | + |
| 356 | +- if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU)) |
| 357 | ++ if (sd->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU)) |
| 358 | + val |= MT_TXD6_LDPC; |
| 359 | + |
| 360 | ++ txwi[1] &= ~cpu_to_le32(MT_TXD1_VTA); |
| 361 | + txwi[3] &= ~cpu_to_le32(MT_TXD3_SN_VALID); |
| 362 | + txwi[6] |= cpu_to_le32(val); |
| 363 | + txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, |
| 364 | +@@ -1472,6 +1485,9 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len) |
| 365 | + continue; |
| 366 | + |
| 367 | + msta = container_of(wcid, struct mt7915_sta, wcid); |
| 368 | ++ if (mt76_testmode_enabled(msta->vif->phy->mt76)) |
| 369 | ++ continue; |
| 370 | ++ |
| 371 | + spin_lock_bh(&dev->sta_poll_lock); |
| 372 | + if (list_empty(&msta->poll_list)) |
| 373 | + list_add_tail(&msta->poll_list, &dev->sta_poll_list); |
| 374 | +diff --git a/mt7915/mcu.c b/mt7915/mcu.c |
| 375 | +index bb77edc..29ba3ed 100644 |
| 376 | +--- a/mt7915/mcu.c |
| 377 | ++++ b/mt7915/mcu.c |
| 378 | +@@ -289,7 +289,6 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, |
| 379 | + if (mcu_txd->ext_cid) { |
| 380 | + mcu_txd->ext_cid_ack = 1; |
| 381 | + |
| 382 | +- /* do not use Q_SET for efuse */ |
| 383 | + if (cmd & __MCU_CMD_FIELD_QUERY) |
| 384 | + mcu_txd->set_query = MCU_Q_QUERY; |
| 385 | + else |
| 386 | +@@ -2784,7 +2783,6 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) |
| 387 | + struct mt7915_dev *dev = phy->dev; |
| 388 | + struct cfg80211_chan_def *chandef = &phy->mt76->chandef; |
| 389 | + int freq1 = chandef->center_freq1; |
| 390 | +- bool ext_phy = phy != &dev->phy; |
| 391 | + struct { |
| 392 | + u8 control_ch; |
| 393 | + u8 center_ch; |
| 394 | +@@ -2814,14 +2812,9 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) |
| 395 | + |
| 396 | + #ifdef CONFIG_NL80211_TESTMODE |
| 397 | + if (phy->mt76->test.tx_antenna_mask && |
| 398 | +- (phy->mt76->test.state == MT76_TM_STATE_TX_FRAMES || |
| 399 | +- phy->mt76->test.state == MT76_TM_STATE_RX_FRAMES || |
| 400 | +- phy->mt76->test.state == MT76_TM_STATE_TX_CONT)) { |
| 401 | ++ mt76_testmode_enabled(phy->mt76)) { |
| 402 | + req.tx_streams_num = fls(phy->mt76->test.tx_antenna_mask); |
| 403 | + req.rx_streams = phy->mt76->test.tx_antenna_mask; |
| 404 | +- |
| 405 | +- if (ext_phy) |
| 406 | +- req.rx_streams >>= dev->chainshift; |
| 407 | + } |
| 408 | + #endif |
| 409 | + |
| 410 | +@@ -2887,14 +2880,14 @@ static int mt7915_mcu_set_eeprom_flash(struct mt7915_dev *dev) |
| 411 | + return 0; |
| 412 | + } |
| 413 | + |
| 414 | +-int mt7915_mcu_set_eeprom(struct mt7915_dev *dev) |
| 415 | ++int mt7915_mcu_set_eeprom(struct mt7915_dev *dev, bool flash_mode) |
| 416 | + { |
| 417 | + struct mt7915_mcu_eeprom req = { |
| 418 | + .buffer_mode = EE_MODE_EFUSE, |
| 419 | + .format = EE_FORMAT_WHOLE, |
| 420 | + }; |
| 421 | + |
| 422 | +- if (dev->flash_mode) |
| 423 | ++ if (flash_mode) |
| 424 | + return mt7915_mcu_set_eeprom_flash(dev); |
| 425 | + |
| 426 | + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_BUFFER_MODE), |
| 427 | +diff --git a/mt7915/mcu.h b/mt7915/mcu.h |
| 428 | +index 30211cb..4b78468 100644 |
| 429 | +--- a/mt7915/mcu.h |
| 430 | ++++ b/mt7915/mcu.h |
| 431 | +@@ -27,7 +27,12 @@ struct mt7915_mcu_txd { |
| 432 | + |
| 433 | + enum { |
| 434 | + MCU_ATE_SET_TRX = 0x1, |
| 435 | ++ MCU_ATE_SET_TSSI = 0x5, |
| 436 | ++ MCU_ATE_SET_DPD = 0x6, |
| 437 | ++ MCU_ATE_SET_RATE_POWER_OFFSET = 0x7, |
| 438 | ++ MCU_ATE_SET_THERMAL_COMP = 0x8, |
| 439 | + MCU_ATE_SET_FREQ_OFFSET = 0xa, |
| 440 | ++ MCU_ATE_SET_PHY_COUNT = 0x11, |
| 441 | + MCU_ATE_SET_SLOT_TIME = 0x13, |
| 442 | + MCU_ATE_CLEAN_TXQUEUE = 0x1c, |
| 443 | + }; |
| 444 | +diff --git a/mt7915/mmio.c b/mt7915/mmio.c |
| 445 | +index 1b14bba..207941d 100644 |
| 446 | +--- a/mt7915/mmio.c |
| 447 | ++++ b/mt7915/mmio.c |
| 448 | +@@ -53,6 +53,7 @@ static const u32 mt7986_reg[] = { |
| 449 | + }; |
| 450 | + |
| 451 | + static const u32 mt7915_offs[] = { |
| 452 | ++ [TMAC_TCR2] = 0x05c, |
| 453 | + [TMAC_CDTR] = 0x090, |
| 454 | + [TMAC_ODTR] = 0x094, |
| 455 | + [TMAC_ATCR] = 0x098, |
| 456 | +@@ -125,6 +126,7 @@ static const u32 mt7915_offs[] = { |
| 457 | + }; |
| 458 | + |
| 459 | + static const u32 mt7916_offs[] = { |
| 460 | ++ [TMAC_TCR2] = 0x004, |
| 461 | + [TMAC_CDTR] = 0x0c8, |
| 462 | + [TMAC_ODTR] = 0x0cc, |
| 463 | + [TMAC_ATCR] = 0x00c, |
| 464 | +diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h |
| 465 | +index b3abe77..db4c6bc 100644 |
| 466 | +--- a/mt7915/mt7915.h |
| 467 | ++++ b/mt7915/mt7915.h |
| 468 | +@@ -539,7 +539,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev, |
| 469 | + struct ieee80211_vif *vif, |
| 470 | + struct ieee80211_sta *sta, |
| 471 | + void *data, u32 field); |
| 472 | +-int mt7915_mcu_set_eeprom(struct mt7915_dev *dev); |
| 473 | ++int mt7915_mcu_set_eeprom(struct mt7915_dev *dev, bool flash_mode); |
| 474 | + int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset); |
| 475 | + int mt7915_mcu_get_eeprom_free_block(struct mt7915_dev *dev, u8 *block_num); |
| 476 | + int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable, |
| 477 | +diff --git a/mt7915/regs.h b/mt7915/regs.h |
| 478 | +index 71f325a..dcfb3f8 100644 |
| 479 | +--- a/mt7915/regs.h |
| 480 | ++++ b/mt7915/regs.h |
| 481 | +@@ -34,6 +34,7 @@ enum reg_rev { |
| 482 | + }; |
| 483 | + |
| 484 | + enum offs_rev { |
| 485 | ++ TMAC_TCR2, |
| 486 | + TMAC_CDTR, |
| 487 | + TMAC_ODTR, |
| 488 | + TMAC_ATCR, |
| 489 | +@@ -171,6 +172,12 @@ enum offs_rev { |
| 490 | + #define MT_MDP_TO_HIF 0 |
| 491 | + #define MT_MDP_TO_WM 1 |
| 492 | + |
| 493 | ++#define MT_MDP_TOP_DBG_WDT_CTRL MT_MDP(0x0d0) |
| 494 | ++#define MT_MDP_TOP_DBG_WDT_CTRL_TDP_DIS_BLK BIT(7) |
| 495 | ++ |
| 496 | ++#define MT_MDP_TOP_DBG_CTRL MT_MDP(0x0dc) |
| 497 | ++#define MT_MDP_TOP_DBG_CTRL_ENQ_MODE BIT(30) |
| 498 | ++ |
| 499 | + /* TMAC: band 0(0x820e4000), band 1(0x820f4000) */ |
| 500 | + #define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000) |
| 501 | + #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) |
| 502 | +@@ -179,6 +186,9 @@ enum offs_rev { |
| 503 | + #define MT_TMAC_TCR0_TX_BLINK GENMASK(7, 6) |
| 504 | + #define MT_TMAC_TCR0_TBTT_STOP_CTRL BIT(25) |
| 505 | + |
| 506 | ++#define MT_TMAC_TCR2(_band) MT_WF_TMAC(_band, __OFFS(TMAC_TCR2)) |
| 507 | ++#define MT_TMAC_TCR2_SCH_DET_DIS BIT(19) |
| 508 | ++ |
| 509 | + #define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, __OFFS(TMAC_CDTR)) |
| 510 | + #define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, __OFFS(TMAC_ODTR)) |
| 511 | + #define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0) |
| 512 | +@@ -437,8 +447,10 @@ enum offs_rev { |
| 513 | + #define MT_AGG_PCR0_VHT_PROT BIT(13) |
| 514 | + #define MT_AGG_PCR0_PTA_WIN_DIS BIT(15) |
| 515 | + |
| 516 | +-#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23) |
| 517 | +-#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0) |
| 518 | ++#define MT_AGG_PCR1_RTS0_NUM_THRES GENMASK(31, 23) |
| 519 | ++#define MT_AGG_PCR1_RTS0_LEN_THRES GENMASK(19, 0) |
| 520 | ++#define MT_AGG_PCR1_RTS0_NUM_THRES_MT7916 GENMASK(29, 24) |
| 521 | ++#define MT_AGG_PCR1_RTS0_LEN_THRES_MT7916 GENMASK(22, 0) |
| 522 | + |
| 523 | + #define MT_AGG_ACR0(_band) MT_WF_AGG(_band, __OFFS(AGG_ACR0)) |
| 524 | + #define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0) |
| 525 | +diff --git a/mt7915/testmode.c b/mt7915/testmode.c |
| 526 | +index 6605e24..9f13919 100644 |
| 527 | +--- a/mt7915/testmode.c |
| 528 | ++++ b/mt7915/testmode.c |
| 529 | +@@ -9,6 +9,9 @@ |
| 530 | + enum { |
| 531 | + TM_CHANGED_TXPOWER, |
| 532 | + TM_CHANGED_FREQ_OFFSET, |
| 533 | ++ TM_CHANGED_CFG, |
| 534 | ++ TM_CHANGED_OFF_CH_SCAN_CH, |
| 535 | ++ TM_CHANGED_AID, |
| 536 | + |
| 537 | + /* must be last */ |
| 538 | + NUM_TM_CHANGED |
| 539 | +@@ -17,6 +20,9 @@ enum { |
| 540 | + static const u8 tm_change_map[] = { |
| 541 | + [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER, |
| 542 | + [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET, |
| 543 | ++ [TM_CHANGED_CFG] = MT76_TM_ATTR_CFG, |
| 544 | ++ [TM_CHANGED_OFF_CH_SCAN_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CH, |
| 545 | ++ [TM_CHANGED_AID] = MT76_TM_ATTR_AID, |
| 546 | + }; |
| 547 | + |
| 548 | + struct reg_band { |
| 549 | +@@ -30,10 +36,29 @@ struct reg_band { |
| 550 | + { _list.band[0] = MT_##_reg(0, _idx); \ |
| 551 | + _list.band[1] = MT_##_reg(1, _idx); } |
| 552 | + |
| 553 | +-#define TM_REG_MAX_ID 17 |
| 554 | ++#define TM_REG_MAX_ID 20 |
| 555 | + static struct reg_band reg_backup_list[TM_REG_MAX_ID]; |
| 556 | + |
| 557 | + |
| 558 | ++static u8 mt7915_tm_chan_bw(enum nl80211_chan_width width) |
| 559 | ++{ |
| 560 | ++ static const u8 width_to_bw[] = { |
| 561 | ++ [NL80211_CHAN_WIDTH_40] = TM_CBW_40MHZ, |
| 562 | ++ [NL80211_CHAN_WIDTH_80] = TM_CBW_80MHZ, |
| 563 | ++ [NL80211_CHAN_WIDTH_80P80] = TM_CBW_8080MHZ, |
| 564 | ++ [NL80211_CHAN_WIDTH_160] = TM_CBW_160MHZ, |
| 565 | ++ [NL80211_CHAN_WIDTH_5] = TM_CBW_5MHZ, |
| 566 | ++ [NL80211_CHAN_WIDTH_10] = TM_CBW_10MHZ, |
| 567 | ++ [NL80211_CHAN_WIDTH_20] = TM_CBW_20MHZ, |
| 568 | ++ [NL80211_CHAN_WIDTH_20_NOHT] = TM_CBW_20MHZ, |
| 569 | ++ }; |
| 570 | ++ |
| 571 | ++ if (width >= ARRAY_SIZE(width_to_bw)) |
| 572 | ++ return 0; |
| 573 | ++ |
| 574 | ++ return width_to_bw[width]; |
| 575 | ++} |
| 576 | ++ |
| 577 | + static int |
| 578 | + mt7915_tm_set_tx_power(struct mt7915_phy *phy) |
| 579 | + { |
| 580 | +@@ -119,15 +144,45 @@ mt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en) |
| 581 | + } |
| 582 | + |
| 583 | + static int |
| 584 | +-mt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid) |
| 585 | ++mt7915_tm_clean_hwq(struct mt7915_phy *phy) |
| 586 | + { |
| 587 | + struct mt7915_dev *dev = phy->dev; |
| 588 | + struct mt7915_tm_cmd req = { |
| 589 | + .testmode_en = 1, |
| 590 | + .param_idx = MCU_ATE_CLEAN_TXQUEUE, |
| 591 | +- .param.clean.wcid = wcid, |
| 592 | + .param.clean.band = phy != &dev->phy, |
| 593 | + }; |
| 594 | ++ struct mt76_testmode_sta *tm_sta; |
| 595 | ++ int ret, i; |
| 596 | ++ |
| 597 | ++ if (!mt76_testmode_has_sta(phy->mt76)) { |
| 598 | ++ req.param.clean.wcid = dev->mt76.global_wcid.idx; |
| 599 | ++ |
| 600 | ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), |
| 601 | ++ &req, sizeof(req), false); |
| 602 | ++ } |
| 603 | ++ |
| 604 | ++ mt76_testmode_for_each_sta(phy->mt76, i, tm_sta) { |
| 605 | ++ req.param.clean.wcid = phy->mt76->test.tm_wcid[i]->idx; |
| 606 | ++ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), |
| 607 | ++ &req, sizeof(req), false); |
| 608 | ++ if (ret) |
| 609 | ++ return ret; |
| 610 | ++ } |
| 611 | ++ |
| 612 | ++ return 0; |
| 613 | ++} |
| 614 | ++ |
| 615 | ++static int |
| 616 | ++mt7915_tm_set_phy_count(struct mt7915_phy *phy, u8 control) |
| 617 | ++{ |
| 618 | ++ struct mt7915_dev *dev = phy->dev; |
| 619 | ++ struct mt7915_tm_cmd req = { |
| 620 | ++ .testmode_en = 1, |
| 621 | ++ .param_idx = MCU_ATE_SET_PHY_COUNT, |
| 622 | ++ .param.cfg.enable = control, |
| 623 | ++ .param.cfg.band = phy != &dev->phy, |
| 624 | ++ }; |
| 625 | + |
| 626 | + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, |
| 627 | + sizeof(req), false); |
| 628 | +@@ -167,6 +222,77 @@ mt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu) |
| 629 | + return mt7915_mcu_set_muru_ctrl(dev, MURU_SET_ARB_OP_MODE, op_mode); |
| 630 | + } |
| 631 | + |
| 632 | ++static int |
| 633 | ++mt7915_tm_set_cfg(struct mt7915_phy *phy) |
| 634 | ++{ |
| 635 | ++ static const u8 cfg_cmd[] = { |
| 636 | ++ [MT76_TM_CFG_TSSI] = MCU_ATE_SET_TSSI, |
| 637 | ++ [MT76_TM_CFG_DPD] = MCU_ATE_SET_DPD, |
| 638 | ++ [MT76_TM_CFG_RATE_POWER_OFFSET] = MCU_ATE_SET_RATE_POWER_OFFSET, |
| 639 | ++ [MT76_TM_CFG_THERMAL_COMP] = MCU_ATE_SET_THERMAL_COMP, |
| 640 | ++ }; |
| 641 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 642 | ++ struct mt7915_dev *dev = phy->dev; |
| 643 | ++ struct mt7915_tm_cmd req = { |
| 644 | ++ .testmode_en = !(phy->mt76->test.state == MT76_TM_STATE_OFF), |
| 645 | ++ .param_idx = cfg_cmd[td->cfg.type], |
| 646 | ++ .param.cfg.enable = td->cfg.enable, |
| 647 | ++ .param.cfg.band = phy != &dev->phy, |
| 648 | ++ }; |
| 649 | ++ |
| 650 | ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, |
| 651 | ++ sizeof(req), false); |
| 652 | ++} |
| 653 | ++ |
| 654 | ++static int |
| 655 | ++mt7915_tm_set_off_channel_scan(struct mt7915_phy *phy) |
| 656 | ++{ |
| 657 | ++#define OFF_CH_SCAN_SIMPLE_RX 2 |
| 658 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 659 | ++ struct mt7915_dev *dev = phy->dev; |
| 660 | ++ struct cfg80211_chan_def *chandef = &phy->mt76->chandef; |
| 661 | ++ int freq1 = chandef->center_freq1; |
| 662 | ++ struct { |
| 663 | ++ u8 cur_pri_ch; |
| 664 | ++ u8 cur_center_ch; |
| 665 | ++ u8 cur_bw; |
| 666 | ++ u8 cur_tx_path; |
| 667 | ++ u8 cur_rx_path; |
| 668 | ++ |
| 669 | ++ u8 scan_pri_ch; |
| 670 | ++ u8 scan_center_ch; |
| 671 | ++ u8 scan_bw; |
| 672 | ++ u8 scan_tx_path; |
| 673 | ++ u8 scan_rx_path; |
| 674 | ++ |
| 675 | ++ u8 enable; |
| 676 | ++ u8 band_idx; |
| 677 | ++ u8 type; |
| 678 | ++ u8 is_5g; |
| 679 | ++ u8 _rsv[2]; |
| 680 | ++ } __packed req = { |
| 681 | ++ .cur_pri_ch = chandef->chan->hw_value, |
| 682 | ++ .cur_center_ch = ieee80211_frequency_to_channel(freq1), |
| 683 | ++ .cur_bw = mt7915_tm_chan_bw(chandef->width), |
| 684 | ++ .cur_tx_path = td->tx_antenna_mask, |
| 685 | ++ .cur_rx_path = td->tx_antenna_mask, |
| 686 | ++ |
| 687 | ++ .scan_pri_ch = td->off_ch_scan_ch, |
| 688 | ++ .scan_center_ch = td->off_ch_scan_center_ch, |
| 689 | ++ .scan_bw = td->off_ch_scan_bw, |
| 690 | ++ .scan_tx_path = td->off_ch_scan_path, |
| 691 | ++ .scan_rx_path = td->off_ch_scan_path, |
| 692 | ++ |
| 693 | ++ .enable = !!td->off_ch_scan_ch, |
| 694 | ++ .band_idx = phy != &dev->phy, |
| 695 | ++ .type = OFF_CH_SCAN_SIMPLE_RX, |
| 696 | ++ .is_5g = td->off_ch_scan_ch > 14 ? 1 : 0, |
| 697 | ++ }; |
| 698 | ++ |
| 699 | ++ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(OFFCH_SCAN_CTRL), &req, |
| 700 | ++ sizeof(req), false); |
| 701 | ++} |
| 702 | ++ |
| 703 | + static int |
| 704 | + mt7915_tm_set_wmm_qid(struct mt7915_dev *dev, u8 qid, u8 aifs, u8 cw_min, |
| 705 | + u16 cw_max, u16 txop) |
| 706 | +@@ -320,7 +446,7 @@ mt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time) |
| 707 | + bitrate = cfg80211_calculate_bitrate(&rate); |
| 708 | + tx_len = bitrate * tx_time / 10 / 8; |
| 709 | + |
| 710 | +- ret = mt76_testmode_alloc_skb(phy->mt76, tx_len); |
| 711 | ++ ret = mt76_testmode_init_skb(phy->mt76, tx_len, 0, &td->tx_skb); |
| 712 | + if (ret) |
| 713 | + return ret; |
| 714 | + |
| 715 | +@@ -332,7 +458,7 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) |
| 716 | + { |
| 717 | + int n_regs = ARRAY_SIZE(reg_backup_list); |
| 718 | + struct mt7915_dev *dev = phy->dev; |
| 719 | +- u32 *b = phy->test.reg_backup; |
| 720 | ++ u32 *b = phy->test.reg_backup, val; |
| 721 | + int i; |
| 722 | + |
| 723 | + REG_BAND_IDX(reg_backup_list[0], AGG_PCR0, 0); |
| 724 | +@@ -344,18 +470,28 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) |
| 725 | + REG_BAND(reg_backup_list[6], AGG_MRCR); |
| 726 | + REG_BAND(reg_backup_list[7], TMAC_TFCR0); |
| 727 | + REG_BAND(reg_backup_list[8], TMAC_TCR0); |
| 728 | +- REG_BAND(reg_backup_list[9], AGG_ATCR1); |
| 729 | +- REG_BAND(reg_backup_list[10], AGG_ATCR3); |
| 730 | +- REG_BAND(reg_backup_list[11], TMAC_TRCR0); |
| 731 | +- REG_BAND(reg_backup_list[12], TMAC_ICR0); |
| 732 | +- REG_BAND_IDX(reg_backup_list[13], ARB_DRNGR0, 0); |
| 733 | +- REG_BAND_IDX(reg_backup_list[14], ARB_DRNGR0, 1); |
| 734 | +- REG_BAND(reg_backup_list[15], WF_RFCR); |
| 735 | +- REG_BAND(reg_backup_list[16], WF_RFCR1); |
| 736 | ++ REG_BAND(reg_backup_list[9], TMAC_TCR2); |
| 737 | ++ REG_BAND(reg_backup_list[10], AGG_ATCR1); |
| 738 | ++ REG_BAND(reg_backup_list[11], AGG_ATCR3); |
| 739 | ++ REG_BAND(reg_backup_list[12], TMAC_TRCR0); |
| 740 | ++ REG_BAND(reg_backup_list[13], TMAC_ICR0); |
| 741 | ++ REG_BAND_IDX(reg_backup_list[14], ARB_DRNGR0, 0); |
| 742 | ++ REG_BAND_IDX(reg_backup_list[15], ARB_DRNGR0, 1); |
| 743 | ++ REG_BAND(reg_backup_list[16], WF_RFCR); |
| 744 | ++ REG_BAND(reg_backup_list[17], WF_RFCR1); |
| 745 | ++ |
| 746 | ++ if (is_mt7916(&dev->mt76)) { |
| 747 | ++ reg_backup_list[18].band[phy->band_idx] = MT_MDP_TOP_DBG_WDT_CTRL; |
| 748 | ++ reg_backup_list[19].band[phy->band_idx] = MT_MDP_TOP_DBG_CTRL; |
| 749 | ++ } |
| 750 | + |
| 751 | + if (phy->mt76->test.state == MT76_TM_STATE_OFF) { |
| 752 | +- for (i = 0; i < n_regs; i++) |
| 753 | +- mt76_wr(dev, reg_backup_list[i].band[phy->band_idx], b[i]); |
| 754 | ++ for (i = 0; i < n_regs; i++) { |
| 755 | ++ u8 reg = reg_backup_list[i].band[phy->band_idx]; |
| 756 | ++ |
| 757 | ++ if (reg) |
| 758 | ++ mt76_wr(dev, reg, b[i]); |
| 759 | ++ } |
| 760 | + return; |
| 761 | + } |
| 762 | + |
| 763 | +@@ -375,8 +511,13 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) |
| 764 | + MT_AGG_PCR0_BW40_PROT | MT_AGG_PCR0_BW80_PROT); |
| 765 | + mt76_set(dev, MT_AGG_PCR0(phy->band_idx, 0), MT_AGG_PCR0_PTA_WIN_DIS); |
| 766 | + |
| 767 | +- mt76_wr(dev, MT_AGG_PCR0(phy->band_idx, 1), MT_AGG_PCR1_RTS0_NUM_THRES | |
| 768 | +- MT_AGG_PCR1_RTS0_LEN_THRES); |
| 769 | ++ if (is_mt7915(&dev->mt76)) |
| 770 | ++ val = MT_AGG_PCR1_RTS0_NUM_THRES | MT_AGG_PCR1_RTS0_LEN_THRES; |
| 771 | ++ else |
| 772 | ++ val = MT_AGG_PCR1_RTS0_NUM_THRES_MT7916 | |
| 773 | ++ MT_AGG_PCR1_RTS0_LEN_THRES_MT7916; |
| 774 | ++ |
| 775 | ++ mt76_wr(dev, MT_AGG_PCR0(phy->band_idx, 1), val); |
| 776 | + |
| 777 | + mt76_clear(dev, MT_AGG_MRCR(phy->band_idx), MT_AGG_MRCR_BAR_CNT_LIMIT | |
| 778 | + MT_AGG_MRCR_LAST_RTS_CTS_RN | MT_AGG_MRCR_RTS_FAIL_LIMIT | |
| 779 | +@@ -389,31 +530,124 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy) |
| 780 | + |
| 781 | + mt76_wr(dev, MT_TMAC_TFCR0(phy->band_idx), 0); |
| 782 | + mt76_clear(dev, MT_TMAC_TCR0(phy->band_idx), MT_TMAC_TCR0_TBTT_STOP_CTRL); |
| 783 | ++ mt76_set(dev, MT_TMAC_TCR2(phy->band_idx), MT_TMAC_TCR2_SCH_DET_DIS); |
| 784 | + |
| 785 | + /* config rx filter for testmode rx */ |
| 786 | + mt76_wr(dev, MT_WF_RFCR(phy->band_idx), 0xcf70a); |
| 787 | + mt76_wr(dev, MT_WF_RFCR1(phy->band_idx), 0); |
| 788 | ++ |
| 789 | ++ if (is_mt7916(&dev->mt76)) { |
| 790 | ++ /* enable MDP Tx block mode */ |
| 791 | ++ mt76_clear(dev, MT_MDP_TOP_DBG_WDT_CTRL, |
| 792 | ++ MT_MDP_TOP_DBG_WDT_CTRL_TDP_DIS_BLK); |
| 793 | ++ mt76_clear(dev, MT_MDP_TOP_DBG_CTRL, |
| 794 | ++ MT_MDP_TOP_DBG_CTRL_ENQ_MODE); |
| 795 | ++ } |
| 796 | ++} |
| 797 | ++ |
| 798 | ++static int |
| 799 | ++mt7915_tm_sta_add(struct mt7915_phy *phy, u8 aid, |
| 800 | ++ struct mt76_testmode_sta_data *sd) |
| 801 | ++{ |
| 802 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 803 | ++ struct mt76_testmode_sta *tm_sta; |
| 804 | ++ |
| 805 | ++ if (!aid) |
| 806 | ++ return 0; |
| 807 | ++ |
| 808 | ++ if (!td->tm_wcid[aid]) { |
| 809 | ++ struct ieee80211_vif *vif = phy->monitor_vif; |
| 810 | ++ struct ieee80211_sband_iftype_data *data; |
| 811 | ++ struct ieee80211_supported_band *sband; |
| 812 | ++ struct ieee80211_sta *sta; |
| 813 | ++ struct mt7915_sta *msta; |
| 814 | ++ int ret; |
| 815 | ++ |
| 816 | ++ sta = kzalloc(sizeof(*sta) + phy->mt76->hw->sta_data_size + |
| 817 | ++ sizeof(*tm_sta), GFP_KERNEL); |
| 818 | ++ if (!sta) |
| 819 | ++ return -ENOMEM; |
| 820 | ++ |
| 821 | ++ if (phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ) { |
| 822 | ++ sband = &phy->mt76->sband_5g.sband; |
| 823 | ++ data = phy->iftype[NL80211_BAND_5GHZ]; |
| 824 | ++ } else { |
| 825 | ++ sband = &phy->mt76->sband_2g.sband; |
| 826 | ++ data = phy->iftype[NL80211_BAND_2GHZ]; |
| 827 | ++ } |
| 828 | ++ |
| 829 | ++ ether_addr_copy(sta->addr, phy->mt76->macaddr); |
| 830 | ++ sta->addr[0] += aid * 4; |
| 831 | ++ memcpy(&sta->ht_cap, &sband->ht_cap, sizeof(sta->ht_cap)); |
| 832 | ++ memcpy(&sta->vht_cap, &sband->vht_cap, sizeof(sta->vht_cap)); |
| 833 | ++ memcpy(&sta->he_cap, &data[NL80211_IFTYPE_STATION].he_cap, |
| 834 | ++ sizeof(sta->he_cap)); |
| 835 | ++ sta->aid = aid; |
| 836 | ++ sta->wme = 1; |
| 837 | ++ |
| 838 | ++ ret = mt7915_mac_sta_add(&phy->dev->mt76, vif, sta); |
| 839 | ++ if (ret) { |
| 840 | ++ kfree(sta); |
| 841 | ++ return ret; |
| 842 | ++ } |
| 843 | ++ |
| 844 | ++ msta = (struct mt7915_sta *)sta->drv_priv; |
| 845 | ++ td->tm_wcid[aid] = &msta->wcid; |
| 846 | ++ td->tm_sta_mask |= BIT(aid - 1); |
| 847 | ++ } |
| 848 | ++ |
| 849 | ++ tm_sta = mt76_testmode_aid_get_sta(phy->mt76, aid); |
| 850 | ++ memcpy(&tm_sta->sd, sd, sizeof(tm_sta->sd)); |
| 851 | ++ |
| 852 | ++ return 0; |
| 853 | + } |
| 854 | + |
| 855 | + static void |
| 856 | +-mt7915_tm_init(struct mt7915_phy *phy, bool en) |
| 857 | ++mt7915_tm_sta_remove(struct mt7915_phy *phy, u8 aid) |
| 858 | + { |
| 859 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 860 | ++ struct mt76_wcid *wcid = td->tm_wcid[aid]; |
| 861 | + struct mt7915_dev *dev = phy->dev; |
| 862 | ++ struct ieee80211_sta *sta = wcid_to_sta(wcid); |
| 863 | + |
| 864 | +- if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) |
| 865 | ++ mt7915_mac_sta_remove(&dev->mt76, phy->monitor_vif, sta); |
| 866 | ++ mt76_wcid_mask_clear(dev->mt76.wcid_mask, wcid->idx); |
| 867 | ++ |
| 868 | ++ kfree(sta); |
| 869 | ++ td->tm_wcid[aid] = NULL; |
| 870 | ++ td->tm_sta_mask &= ~BIT(aid - 1); |
| 871 | ++} |
| 872 | ++ |
| 873 | ++static void |
| 874 | ++mt7915_tm_sta_remove_all(struct mt7915_phy *phy) |
| 875 | ++{ |
| 876 | ++ int i; |
| 877 | ++ |
| 878 | ++ if (!mt76_testmode_has_sta(phy->mt76)) |
| 879 | + return; |
| 880 | + |
| 881 | +- mt7915_mcu_set_sku_en(phy, !en); |
| 882 | ++ for (i = 1; i < ARRAY_SIZE(phy->mt76->test.tm_wcid); i++) { |
| 883 | ++ if (phy->mt76->test.tm_wcid[i]) |
| 884 | ++ mt7915_tm_sta_remove(phy, i); |
| 885 | ++ } |
| 886 | ++} |
| 887 | + |
| 888 | +- mt7915_tm_mode_ctrl(dev, en); |
| 889 | +- mt7915_tm_reg_backup_restore(phy); |
| 890 | +- mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en); |
| 891 | ++static int |
| 892 | ++mt7915_tm_set_sta(struct mt7915_phy *phy) |
| 893 | ++{ |
| 894 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 895 | + |
| 896 | +- mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en); |
| 897 | +- mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en); |
| 898 | ++ if (!td->aid) { |
| 899 | ++ mt7915_tm_sta_remove_all(phy); |
| 900 | ++ return 0; |
| 901 | ++ } |
| 902 | + |
| 903 | +- if (!en) |
| 904 | +- mt7915_tm_set_tam_arb(phy, en, 0); |
| 905 | ++ if (td->tx_count == 0) { |
| 906 | ++ mt7915_tm_sta_remove(phy, td->aid); |
| 907 | ++ return 0; |
| 908 | ++ } |
| 909 | ++ |
| 910 | ++ return mt7915_tm_sta_add(phy, td->aid, &td->sd); |
| 911 | + } |
| 912 | + |
| 913 | + static void |
| 914 | +@@ -426,59 +660,122 @@ mt7915_tm_update_channel(struct mt7915_phy *phy) |
| 915 | + mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); |
| 916 | + } |
| 917 | + |
| 918 | ++static bool |
| 919 | ++mt7915_tm_check_skb(struct mt7915_phy *phy) |
| 920 | ++{ |
| 921 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 922 | ++ struct ieee80211_tx_info *info; |
| 923 | ++ |
| 924 | ++ if (!mt76_testmode_has_sta(phy->mt76)) { |
| 925 | ++ if (!td->tx_skb) |
| 926 | ++ return false; |
| 927 | ++ |
| 928 | ++ info = IEEE80211_SKB_CB(td->tx_skb); |
| 929 | ++ info->control.vif = phy->monitor_vif; |
| 930 | ++ } else { |
| 931 | ++ struct mt76_testmode_sta *tm_sta; |
| 932 | ++ int i; |
| 933 | ++ |
| 934 | ++ mt76_testmode_for_each_sta(phy->mt76, i, tm_sta) { |
| 935 | ++ if (!tm_sta->tx_skb) |
| 936 | ++ return false; |
| 937 | ++ |
| 938 | ++ info = IEEE80211_SKB_CB(tm_sta->tx_skb); |
| 939 | ++ info->control.vif = phy->monitor_vif; |
| 940 | ++ } |
| 941 | ++ } |
| 942 | ++ |
| 943 | ++ return true; |
| 944 | ++} |
| 945 | ++ |
| 946 | + static void |
| 947 | + mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) |
| 948 | + { |
| 949 | + static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0, |
| 950 | + 9, 8, 6, 10, 16, 12, 18, 0}; |
| 951 | + struct mt76_testmode_data *td = &phy->mt76->test; |
| 952 | +- struct mt7915_dev *dev = phy->dev; |
| 953 | +- struct ieee80211_tx_info *info; |
| 954 | +- u8 duty_cycle = td->tx_duty_cycle; |
| 955 | +- u32 tx_time = td->tx_time; |
| 956 | +- u32 ipg = td->tx_ipg; |
| 957 | + |
| 958 | + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); |
| 959 | +- mt7915_tm_clean_hwq(phy, dev->mt76.global_wcid.idx); |
| 960 | ++ mt7915_tm_set_trx(phy, TM_MAC_TX, false); |
| 961 | + |
| 962 | + if (en) { |
| 963 | ++ u32 tx_time = td->tx_time, ipg = td->tx_ipg; |
| 964 | ++ u8 duty_cycle = td->tx_duty_cycle; |
| 965 | ++ |
| 966 | + mt7915_tm_update_channel(phy); |
| 967 | + |
| 968 | + if (td->tx_spe_idx) { |
| 969 | + phy->test.spe_idx = td->tx_spe_idx; |
| 970 | + } else { |
| 971 | +- u8 tx_ant = td->tx_antenna_mask; |
| 972 | ++ phy->test.spe_idx = spe_idx_map[td->tx_antenna_mask]; |
| 973 | ++ } |
| 974 | + |
| 975 | +- if (phy != &dev->phy) |
| 976 | +- tx_ant >>= dev->chainshift; |
| 977 | +- phy->test.spe_idx = spe_idx_map[tx_ant]; |
| 978 | ++ /* if all three params are set, duty_cycle will be ignored */ |
| 979 | ++ if (duty_cycle && tx_time && !ipg) { |
| 980 | ++ ipg = tx_time * 100 / duty_cycle - tx_time; |
| 981 | ++ } else if (duty_cycle && !tx_time && ipg) { |
| 982 | ++ if (duty_cycle < 100) |
| 983 | ++ tx_time = duty_cycle * ipg / (100 - duty_cycle); |
| 984 | + } |
| 985 | ++ |
| 986 | ++ mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode); |
| 987 | ++ mt7915_tm_set_tx_len(phy, tx_time); |
| 988 | ++ |
| 989 | ++ if (ipg) |
| 990 | ++ td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2; |
| 991 | ++ |
| 992 | ++ if (!mt7915_tm_check_skb(phy)) |
| 993 | ++ return; |
| 994 | ++ } else { |
| 995 | ++ mt7915_tm_clean_hwq(phy); |
| 996 | + } |
| 997 | + |
| 998 | + mt7915_tm_set_tam_arb(phy, en, |
| 999 | + td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU); |
| 1000 | + |
| 1001 | +- /* if all three params are set, duty_cycle will be ignored */ |
| 1002 | +- if (duty_cycle && tx_time && !ipg) { |
| 1003 | +- ipg = tx_time * 100 / duty_cycle - tx_time; |
| 1004 | +- } else if (duty_cycle && !tx_time && ipg) { |
| 1005 | +- if (duty_cycle < 100) |
| 1006 | +- tx_time = duty_cycle * ipg / (100 - duty_cycle); |
| 1007 | +- } |
| 1008 | ++ mt7915_tm_set_trx(phy, TM_MAC_TX, en); |
| 1009 | ++} |
| 1010 | + |
| 1011 | +- mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode); |
| 1012 | +- mt7915_tm_set_tx_len(phy, tx_time); |
| 1013 | ++static int |
| 1014 | ++mt7915_tm_get_rx_stats(struct mt7915_phy *phy, bool clear) |
| 1015 | ++{ |
| 1016 | ++#define CMD_RX_STAT_BAND 0x3 |
| 1017 | ++ struct mt76_testmode_data *td = &phy->mt76->test; |
| 1018 | ++ struct mt7915_tm_rx_stat_band *rs_band; |
| 1019 | ++ struct mt7915_dev *dev = phy->dev; |
| 1020 | ++ struct sk_buff *skb; |
| 1021 | ++ struct { |
| 1022 | ++ u8 format_id; |
| 1023 | ++ u8 band; |
| 1024 | ++ u8 _rsv[2]; |
| 1025 | ++ } __packed req = { |
| 1026 | ++ .format_id = CMD_RX_STAT_BAND, |
| 1027 | ++ .band = phy != &dev->phy, |
| 1028 | ++ }; |
| 1029 | ++ int ret; |
| 1030 | + |
| 1031 | +- if (ipg) |
| 1032 | +- td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2; |
| 1033 | ++ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_CMD(RX_STAT), |
| 1034 | ++ &req, sizeof(req), true, &skb); |
| 1035 | ++ if (ret) |
| 1036 | ++ return ret; |
| 1037 | + |
| 1038 | +- if (!en || !td->tx_skb) |
| 1039 | +- return; |
| 1040 | ++ rs_band = (struct mt7915_tm_rx_stat_band *)skb->data; |
| 1041 | ++ /* pr_info("mdrdy_cnt = %d\n", le32_to_cpu(rs_band->mdrdy_cnt)); */ |
| 1042 | ++ /* pr_info("fcs_err = %d\n", le16_to_cpu(rs_band->fcs_err)); */ |
| 1043 | ++ /* pr_info("len_mismatch = %d\n", le16_to_cpu(rs_band->len_mismatch)); */ |
| 1044 | ++ /* pr_info("fcs_ok = %d\n", le16_to_cpu(rs_band->fcs_succ)); */ |
| 1045 | + |
| 1046 | +- info = IEEE80211_SKB_CB(td->tx_skb); |
| 1047 | +- info->control.vif = phy->monitor_vif; |
| 1048 | ++ if (!clear) { |
| 1049 | ++ enum mt76_rxq_id q = req.band ? MT_RXQ_EXT : MT_RXQ_MAIN; |
| 1050 | + |
| 1051 | +- mt7915_tm_set_trx(phy, TM_MAC_TX, en); |
| 1052 | ++ td->rx_stats.packets[q] += le32_to_cpu(rs_band->mdrdy_cnt); |
| 1053 | ++ td->rx_stats.fcs_error[q] += le16_to_cpu(rs_band->fcs_err); |
| 1054 | ++ td->rx_stats.len_mismatch += le16_to_cpu(rs_band->len_mismatch); |
| 1055 | ++ } |
| 1056 | ++ |
| 1057 | ++ dev_kfree_skb(skb); |
| 1058 | ++ |
| 1059 | ++ return 0; |
| 1060 | + } |
| 1061 | + |
| 1062 | + static void |
| 1063 | +@@ -487,12 +784,15 @@ mt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) |
| 1064 | + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); |
| 1065 | + |
| 1066 | + if (en) { |
| 1067 | +- struct mt7915_dev *dev = phy->dev; |
| 1068 | +- |
| 1069 | + mt7915_tm_update_channel(phy); |
| 1070 | + |
| 1071 | + /* read-clear */ |
| 1072 | +- mt76_rr(dev, MT_MIB_SDR3(phy != &dev->phy)); |
| 1073 | ++ mt7915_tm_get_rx_stats(phy, true); |
| 1074 | ++ |
| 1075 | ++ /* clear fw count */ |
| 1076 | ++ mt7915_tm_set_phy_count(phy, 0); |
| 1077 | ++ mt7915_tm_set_phy_count(phy, 1); |
| 1078 | ++ |
| 1079 | + mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); |
| 1080 | + } |
| 1081 | + } |
| 1082 | +@@ -631,6 +931,31 @@ out: |
| 1083 | + sizeof(req), true); |
| 1084 | + } |
| 1085 | + |
| 1086 | ++static void |
| 1087 | ++mt7915_tm_init(struct mt7915_phy *phy, bool en) |
| 1088 | ++{ |
| 1089 | ++ struct mt7915_dev *dev = phy->dev; |
| 1090 | ++ |
| 1091 | ++ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) |
| 1092 | ++ return; |
| 1093 | ++ |
| 1094 | ++ mt7915_mcu_set_sku_en(phy, !en); |
| 1095 | ++ |
| 1096 | ++ mt7915_tm_mode_ctrl(dev, en); |
| 1097 | ++ mt7915_tm_reg_backup_restore(phy); |
| 1098 | ++ mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en); |
| 1099 | ++ |
| 1100 | ++ mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en); |
| 1101 | ++ mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en); |
| 1102 | ++ |
| 1103 | ++ phy->mt76->test.flag |= MT_TM_FW_RX_COUNT; |
| 1104 | ++ |
| 1105 | ++ if (!en) { |
| 1106 | ++ mt7915_tm_set_tam_arb(phy, en, 0); |
| 1107 | ++ mt7915_tm_sta_remove_all(phy); |
| 1108 | ++ } |
| 1109 | ++} |
| 1110 | ++ |
| 1111 | + static void |
| 1112 | + mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed) |
| 1113 | + { |
| 1114 | +@@ -641,6 +966,12 @@ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed) |
| 1115 | + mt7915_tm_set_freq_offset(phy, en, en ? td->freq_offset : 0); |
| 1116 | + if (changed & BIT(TM_CHANGED_TXPOWER)) |
| 1117 | + mt7915_tm_set_tx_power(phy); |
| 1118 | ++ if (changed & BIT(TM_CHANGED_CFG)) |
| 1119 | ++ mt7915_tm_set_cfg(phy); |
| 1120 | ++ if (changed & BIT(TM_CHANGED_OFF_CH_SCAN_CH)) |
| 1121 | ++ mt7915_tm_set_off_channel_scan(phy); |
| 1122 | ++ if (changed & BIT(TM_CHANGED_AID)) |
| 1123 | ++ mt7915_tm_set_sta(phy); |
| 1124 | + } |
| 1125 | + |
| 1126 | + static int |
| 1127 | +@@ -700,9 +1031,6 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, |
| 1128 | + td->state == MT76_TM_STATE_OFF) |
| 1129 | + return 0; |
| 1130 | + |
| 1131 | +- if (td->tx_antenna_mask & ~mphy->chainmask) |
| 1132 | +- return -EINVAL; |
| 1133 | +- |
| 1134 | + for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { |
| 1135 | + if (tb[tm_change_map[i]]) |
| 1136 | + changed |= BIT(i); |
| 1137 | +@@ -717,12 +1045,8 @@ static int |
| 1138 | + mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) |
| 1139 | + { |
| 1140 | + struct mt7915_phy *phy = mphy->priv; |
| 1141 | +- struct mt7915_dev *dev = phy->dev; |
| 1142 | +- enum mt76_rxq_id q; |
| 1143 | + void *rx, *rssi; |
| 1144 | +- u16 fcs_err; |
| 1145 | + int i; |
| 1146 | +- u32 cnt; |
| 1147 | + |
| 1148 | + rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); |
| 1149 | + if (!rx) |
| 1150 | +@@ -766,19 +1090,68 @@ mt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) |
| 1151 | + |
| 1152 | + nla_nest_end(msg, rx); |
| 1153 | + |
| 1154 | +- cnt = mt76_rr(dev, MT_MIB_SDR3(phy->band_idx)); |
| 1155 | +- fcs_err = is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : |
| 1156 | +- FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); |
| 1157 | ++ return mt7915_tm_get_rx_stats(phy, false); |
| 1158 | ++} |
| 1159 | ++ |
| 1160 | ++static int |
| 1161 | ++mt7915_tm_write_back_to_efuse(struct mt7915_dev *dev) |
| 1162 | ++{ |
| 1163 | ++ struct mt7915_mcu_eeprom_info req = {}; |
| 1164 | ++ u8 *eeprom = dev->mt76.eeprom.data; |
| 1165 | ++ int i, ret = -EINVAL; |
| 1166 | + |
| 1167 | +- q = phy->band_idx ? MT_RXQ_EXT : MT_RXQ_MAIN; |
| 1168 | +- mphy->test.rx_stats.packets[q] += fcs_err; |
| 1169 | +- mphy->test.rx_stats.fcs_error[q] += fcs_err; |
| 1170 | ++ if (is_mt7986(&dev->mt76)) |
| 1171 | ++ goto out; |
| 1172 | + |
| 1173 | +- return 0; |
| 1174 | ++ /* prevent from damaging chip id in efuse */ |
| 1175 | ++ if (mt76_chip(&dev->mt76) != get_unaligned_le16(eeprom)) |
| 1176 | ++ goto out; |
| 1177 | ++ |
| 1178 | ++ for (i = 0; i < MT7915_EEPROM_SIZE; i += MT76_TM_EEPROM_BLOCK_SIZE) { |
| 1179 | ++ req.addr = cpu_to_le32(i); |
| 1180 | ++ memcpy(&req.data, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE); |
| 1181 | ++ |
| 1182 | ++ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(EFUSE_ACCESS), |
| 1183 | ++ &req, sizeof(req), true); |
| 1184 | ++ if (ret) |
| 1185 | ++ return ret; |
| 1186 | ++ } |
| 1187 | ++ |
| 1188 | ++out: |
| 1189 | ++ return ret; |
| 1190 | ++} |
| 1191 | ++ |
| 1192 | ++static int |
| 1193 | ++mt7915_tm_set_eeprom(struct mt76_phy *mphy, u32 offset, u8 *val, u8 action) |
| 1194 | ++{ |
| 1195 | ++ struct mt7915_phy *phy = mphy->priv; |
| 1196 | ++ struct mt7915_dev *dev = phy->dev; |
| 1197 | ++ u8 *eeprom = dev->mt76.eeprom.data; |
| 1198 | ++ int ret = 0; |
| 1199 | ++ |
| 1200 | ++ if (offset >= MT7915_EEPROM_SIZE) |
| 1201 | ++ return -EINVAL; |
| 1202 | ++ |
| 1203 | ++ switch (action) { |
| 1204 | ++ case MT76_TM_EEPROM_ACTION_UPDATE_DATA: |
| 1205 | ++ memcpy(eeprom + offset, val, MT76_TM_EEPROM_BLOCK_SIZE); |
| 1206 | ++ break; |
| 1207 | ++ case MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE: |
| 1208 | ++ ret = mt7915_mcu_set_eeprom(dev, true); |
| 1209 | ++ break; |
| 1210 | ++ case MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE: |
| 1211 | ++ ret = mt7915_tm_write_back_to_efuse(dev); |
| 1212 | ++ break; |
| 1213 | ++ default: |
| 1214 | ++ break; |
| 1215 | ++ } |
| 1216 | ++ |
| 1217 | ++ return ret; |
| 1218 | + } |
| 1219 | + |
| 1220 | + const struct mt76_testmode_ops mt7915_testmode_ops = { |
| 1221 | + .set_state = mt7915_tm_set_state, |
| 1222 | + .set_params = mt7915_tm_set_params, |
| 1223 | + .dump_stats = mt7915_tm_dump_stats, |
| 1224 | ++ .set_eeprom = mt7915_tm_set_eeprom, |
| 1225 | + }; |
| 1226 | +diff --git a/mt7915/testmode.h b/mt7915/testmode.h |
| 1227 | +index 5573ac3..d22aabe 100644 |
| 1228 | +--- a/mt7915/testmode.h |
| 1229 | ++++ b/mt7915/testmode.h |
| 1230 | +@@ -33,6 +33,12 @@ struct mt7915_tm_clean_txq { |
| 1231 | + u8 rsv; |
| 1232 | + }; |
| 1233 | + |
| 1234 | ++struct mt7915_tm_cfg { |
| 1235 | ++ u8 enable; |
| 1236 | ++ u8 band; |
| 1237 | ++ u8 _rsv[2]; |
| 1238 | ++}; |
| 1239 | ++ |
| 1240 | + struct mt7915_tm_cmd { |
| 1241 | + u8 testmode_en; |
| 1242 | + u8 param_idx; |
| 1243 | +@@ -43,6 +49,7 @@ struct mt7915_tm_cmd { |
| 1244 | + struct mt7915_tm_freq_offset freq; |
| 1245 | + struct mt7915_tm_slot_time slot; |
| 1246 | + struct mt7915_tm_clean_txq clean; |
| 1247 | ++ struct mt7915_tm_cfg cfg; |
| 1248 | + u8 test[72]; |
| 1249 | + } param; |
| 1250 | + } __packed; |
| 1251 | +@@ -102,4 +109,35 @@ enum { |
| 1252 | + TAM_ARB_OP_MODE_FORCE_SU = 5, |
| 1253 | + }; |
| 1254 | + |
| 1255 | ++struct mt7915_tm_rx_stat_band { |
| 1256 | ++ u8 category; |
| 1257 | ++ |
| 1258 | ++ /* mac */ |
| 1259 | ++ __le16 fcs_err; |
| 1260 | ++ __le16 len_mismatch; |
| 1261 | ++ __le16 fcs_succ; |
| 1262 | ++ __le32 mdrdy_cnt; |
| 1263 | ++ /* phy */ |
| 1264 | ++ __le16 fcs_err_cck; |
| 1265 | ++ __le16 fcs_err_ofdm; |
| 1266 | ++ __le16 pd_cck; |
| 1267 | ++ __le16 pd_ofdm; |
| 1268 | ++ __le16 sig_err_cck; |
| 1269 | ++ __le16 sfd_err_cck; |
| 1270 | ++ __le16 sig_err_ofdm; |
| 1271 | ++ __le16 tag_err_ofdm; |
| 1272 | ++ __le16 mdrdy_cnt_cck; |
| 1273 | ++ __le16 mdrdy_cnt_ofdm; |
| 1274 | ++}; |
| 1275 | ++ |
| 1276 | ++enum { |
| 1277 | ++ TM_CBW_20MHZ, |
| 1278 | ++ TM_CBW_40MHZ, |
| 1279 | ++ TM_CBW_80MHZ, |
| 1280 | ++ TM_CBW_10MHZ, |
| 1281 | ++ TM_CBW_5MHZ, |
| 1282 | ++ TM_CBW_160MHZ, |
| 1283 | ++ TM_CBW_8080MHZ, |
| 1284 | ++}; |
| 1285 | ++ |
| 1286 | + #endif |
| 1287 | +diff --git a/testmode.c b/testmode.c |
| 1288 | +index 382b456..9da490c 100644 |
| 1289 | +--- a/testmode.c |
| 1290 | ++++ b/testmode.c |
| 1291 | +@@ -25,18 +25,18 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = { |
| 1292 | + }; |
| 1293 | + EXPORT_SYMBOL_GPL(mt76_tm_policy); |
| 1294 | + |
| 1295 | +-void mt76_testmode_tx_pending(struct mt76_phy *phy) |
| 1296 | ++static u16 |
| 1297 | ++mt76_testmode_queue_tx(struct mt76_phy *phy, struct mt76_wcid *wcid, |
| 1298 | ++ struct sk_buff *skb, u32 limit) |
| 1299 | + { |
| 1300 | + struct mt76_testmode_data *td = &phy->test; |
| 1301 | + struct mt76_dev *dev = phy->dev; |
| 1302 | +- struct mt76_wcid *wcid = &dev->global_wcid; |
| 1303 | +- struct sk_buff *skb = td->tx_skb; |
| 1304 | + struct mt76_queue *q; |
| 1305 | +- u16 tx_queued_limit; |
| 1306 | ++ u16 tx_queued_limit, count = 0; |
| 1307 | + int qid; |
| 1308 | + |
| 1309 | +- if (!skb || !td->tx_pending) |
| 1310 | +- return; |
| 1311 | ++ if (!skb) |
| 1312 | ++ return 0; |
| 1313 | + |
| 1314 | + qid = skb_get_queue_mapping(skb); |
| 1315 | + q = phy->q_tx[qid]; |
| 1316 | +@@ -45,7 +45,7 @@ void mt76_testmode_tx_pending(struct mt76_phy *phy) |
| 1317 | + |
| 1318 | + spin_lock_bh(&q->lock); |
| 1319 | + |
| 1320 | +- while (td->tx_pending > 0 && |
| 1321 | ++ while (count < limit && |
| 1322 | + td->tx_queued - td->tx_done < tx_queued_limit && |
| 1323 | + q->queued < q->ndesc / 2) { |
| 1324 | + int ret; |
| 1325 | +@@ -55,13 +55,56 @@ void mt76_testmode_tx_pending(struct mt76_phy *phy) |
| 1326 | + if (ret < 0) |
| 1327 | + break; |
| 1328 | + |
| 1329 | +- td->tx_pending--; |
| 1330 | + td->tx_queued++; |
| 1331 | ++ count++; |
| 1332 | + } |
| 1333 | + |
| 1334 | + dev->queue_ops->kick(dev, q); |
| 1335 | + |
| 1336 | + spin_unlock_bh(&q->lock); |
| 1337 | ++ |
| 1338 | ++ return count; |
| 1339 | ++} |
| 1340 | ++ |
| 1341 | ++void mt76_testmode_tx_pending(struct mt76_phy *phy) |
| 1342 | ++{ |
| 1343 | ++ struct mt76_testmode_data *td = &phy->test; |
| 1344 | ++ u16 count; |
| 1345 | ++ |
| 1346 | ++ if (!td->tx_pending) |
| 1347 | ++ return; |
| 1348 | ++ |
| 1349 | ++ if (!mt76_testmode_has_sta(phy)) { |
| 1350 | ++ count = mt76_testmode_queue_tx(phy, &phy->dev->global_wcid, |
| 1351 | ++ td->tx_skb, td->tx_pending); |
| 1352 | ++ td->tx_pending -= count; |
| 1353 | ++ |
| 1354 | ++ return; |
| 1355 | ++ } |
| 1356 | ++ |
| 1357 | ++ while (true) { |
| 1358 | ++ struct mt76_testmode_sta *tm_sta; |
| 1359 | ++ struct mt76_wcid *wcid; |
| 1360 | ++ u32 limit, per_sta_cnt = 1; |
| 1361 | ++ |
| 1362 | ++ if (td->tx_rate_mode != MT76_TM_TX_MODE_HE_MU) |
| 1363 | ++ per_sta_cnt = td->tx_count / hweight16(phy->test.tm_sta_mask); |
| 1364 | ++ |
| 1365 | ++ limit = td->tx_pending % per_sta_cnt; |
| 1366 | ++ if (limit == 0) |
| 1367 | ++ limit = per_sta_cnt; |
| 1368 | ++ |
| 1369 | ++ tm_sta = mt76_testmode_aid_get_sta(phy, td->cur_aid); |
| 1370 | ++ wcid = td->tm_wcid[td->cur_aid]; |
| 1371 | ++ count = mt76_testmode_queue_tx(phy, wcid, tm_sta->tx_skb, limit); |
| 1372 | ++ |
| 1373 | ++ td->tx_pending -= count; |
| 1374 | ++ |
| 1375 | ++ if (td->tx_pending && (td->tx_pending % per_sta_cnt == 0)) |
| 1376 | ++ td->cur_aid = ffs(td->tm_sta_mask >> td->cur_aid) + td->cur_aid; |
| 1377 | ++ else |
| 1378 | ++ break; |
| 1379 | ++ } |
| 1380 | + } |
| 1381 | + |
| 1382 | + static u32 |
| 1383 | +@@ -87,15 +130,34 @@ mt76_testmode_max_mpdu_len(struct mt76_phy *phy, u8 tx_rate_mode) |
| 1384 | + } |
| 1385 | + |
| 1386 | + static void |
| 1387 | +-mt76_testmode_free_skb(struct mt76_phy *phy) |
| 1388 | ++mt76_testmode_free_skb(struct sk_buff **tx_skb) |
| 1389 | ++{ |
| 1390 | ++ dev_kfree_skb(*tx_skb); |
| 1391 | ++ *tx_skb = NULL; |
| 1392 | ++} |
| 1393 | ++ |
| 1394 | ++static void |
| 1395 | ++mt76_testmode_free_skb_all(struct mt76_phy *phy) |
| 1396 | + { |
| 1397 | + struct mt76_testmode_data *td = &phy->test; |
| 1398 | + |
| 1399 | +- dev_kfree_skb(td->tx_skb); |
| 1400 | +- td->tx_skb = NULL; |
| 1401 | ++ if (mt76_testmode_has_sta(phy)) { |
| 1402 | ++ struct mt76_testmode_sta *tm_sta; |
| 1403 | ++ int i; |
| 1404 | ++ |
| 1405 | ++ mt76_testmode_for_each_sta(phy, i, tm_sta) { |
| 1406 | ++ mt76_testmode_free_skb(&tm_sta->tx_skb); |
| 1407 | ++ } |
| 1408 | ++ |
| 1409 | ++ return; |
| 1410 | ++ } |
| 1411 | ++ |
| 1412 | ++ mt76_testmode_free_skb(&td->tx_skb); |
| 1413 | + } |
| 1414 | + |
| 1415 | +-int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) |
| 1416 | ++static int |
| 1417 | ++mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len, |
| 1418 | ++ struct sk_buff **tx_skb, u8 *da) |
| 1419 | + { |
| 1420 | + #define MT_TXP_MAX_LEN 4095 |
| 1421 | + u16 fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | |
| 1422 | +@@ -128,7 +190,9 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) |
| 1423 | + hdr->frame_control = cpu_to_le16(fc); |
| 1424 | + memcpy(hdr->addr1, td->addr[0], ETH_ALEN); |
| 1425 | + memcpy(hdr->addr2, td->addr[1], ETH_ALEN); |
| 1426 | +- memcpy(hdr->addr3, td->addr[2], ETH_ALEN); |
| 1427 | ++ /* memcpy(hdr->addr3, td->addr[2], ETH_ALEN); */ |
| 1428 | ++ memcpy(hdr->addr3, da, ETH_ALEN); |
| 1429 | ++ |
| 1430 | + skb_set_queue_mapping(head, IEEE80211_AC_BE); |
| 1431 | + |
| 1432 | + info = IEEE80211_SKB_CB(head); |
| 1433 | +@@ -152,7 +216,7 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) |
| 1434 | + |
| 1435 | + frag = alloc_skb(frag_len, GFP_KERNEL); |
| 1436 | + if (!frag) { |
| 1437 | +- mt76_testmode_free_skb(phy); |
| 1438 | ++ mt76_testmode_free_skb(tx_skb); |
| 1439 | + dev_kfree_skb(head); |
| 1440 | + return -ENOMEM; |
| 1441 | + } |
| 1442 | +@@ -165,23 +229,25 @@ int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len) |
| 1443 | + frag_tail = &(*frag_tail)->next; |
| 1444 | + } |
| 1445 | + |
| 1446 | +- mt76_testmode_free_skb(phy); |
| 1447 | +- td->tx_skb = head; |
| 1448 | ++ mt76_testmode_free_skb(tx_skb); |
| 1449 | ++ *tx_skb = head; |
| 1450 | + |
| 1451 | + return 0; |
| 1452 | + } |
| 1453 | +-EXPORT_SYMBOL(mt76_testmode_alloc_skb); |
| 1454 | + |
| 1455 | +-static int |
| 1456 | +-mt76_testmode_tx_init(struct mt76_phy *phy) |
| 1457 | ++int mt76_testmode_init_skb(struct mt76_phy *phy, u32 len, u8 aid, |
| 1458 | ++ struct sk_buff **tx_skb) |
| 1459 | + { |
| 1460 | + struct mt76_testmode_data *td = &phy->test; |
| 1461 | + struct ieee80211_tx_info *info; |
| 1462 | + struct ieee80211_tx_rate *rate; |
| 1463 | + u8 max_nss = hweight8(phy->antenna_mask); |
| 1464 | ++ u8 da[ETH_ALEN]; |
| 1465 | + int ret; |
| 1466 | + |
| 1467 | +- ret = mt76_testmode_alloc_skb(phy, td->tx_mpdu_len); |
| 1468 | ++ ether_addr_copy(da, phy->macaddr); |
| 1469 | ++ da[0] += aid * 4; |
| 1470 | ++ ret = mt76_testmode_alloc_skb(phy, len, tx_skb, da); |
| 1471 | + if (ret) |
| 1472 | + return ret; |
| 1473 | + |
| 1474 | +@@ -191,7 +257,7 @@ mt76_testmode_tx_init(struct mt76_phy *phy) |
| 1475 | + if (td->tx_antenna_mask) |
| 1476 | + max_nss = min_t(u8, max_nss, hweight8(td->tx_antenna_mask)); |
| 1477 | + |
| 1478 | +- info = IEEE80211_SKB_CB(td->tx_skb); |
| 1479 | ++ info = IEEE80211_SKB_CB(*tx_skb); |
| 1480 | + rate = &info->control.rates[0]; |
| 1481 | + rate->count = 1; |
| 1482 | + rate->idx = td->tx_rate_idx; |
| 1483 | +@@ -263,6 +329,28 @@ mt76_testmode_tx_init(struct mt76_phy *phy) |
| 1484 | + out: |
| 1485 | + return 0; |
| 1486 | + } |
| 1487 | ++EXPORT_SYMBOL(mt76_testmode_init_skb); |
| 1488 | ++ |
| 1489 | ++static int |
| 1490 | ++mt76_testmode_tx_init(struct mt76_phy *phy) |
| 1491 | ++{ |
| 1492 | ++ struct mt76_testmode_data *td = &phy->test; |
| 1493 | ++ struct mt76_testmode_sta *tm_sta; |
| 1494 | ++ int ret, i; |
| 1495 | ++ |
| 1496 | ++ if (!mt76_testmode_has_sta(phy)) |
| 1497 | ++ return mt76_testmode_init_skb(phy, td->tx_mpdu_len, |
| 1498 | ++ 0, &td->tx_skb); |
| 1499 | ++ |
| 1500 | ++ mt76_testmode_for_each_sta(phy, i, tm_sta) { |
| 1501 | ++ ret = mt76_testmode_init_skb(phy, tm_sta->sd.tx_mpdu_len, |
| 1502 | ++ tm_sta->sd.aid, &tm_sta->tx_skb); |
| 1503 | ++ if (ret) |
| 1504 | ++ return ret; |
| 1505 | ++ } |
| 1506 | ++ |
| 1507 | ++ return 0; |
| 1508 | ++} |
| 1509 | + |
| 1510 | + static void |
| 1511 | + mt76_testmode_tx_start(struct mt76_phy *phy) |
| 1512 | +@@ -273,6 +361,17 @@ mt76_testmode_tx_start(struct mt76_phy *phy) |
| 1513 | + td->tx_queued = 0; |
| 1514 | + td->tx_done = 0; |
| 1515 | + td->tx_pending = td->tx_count; |
| 1516 | ++ |
| 1517 | ++ if (mt76_testmode_has_sta(phy)) { |
| 1518 | ++ td->cur_aid = ffs(td->tm_sta_mask); |
| 1519 | ++ |
| 1520 | ++ /* The actual tx count of MU packets will be pass to FW |
| 1521 | ++ * by a mcu command in testmode. |
| 1522 | ++ */ |
| 1523 | ++ if (td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU) |
| 1524 | ++ td->tx_pending = hweight16(phy->test.tm_sta_mask); |
| 1525 | ++ } |
| 1526 | ++ |
| 1527 | + mt76_worker_schedule(&dev->tx_worker); |
| 1528 | + } |
| 1529 | + |
| 1530 | +@@ -291,7 +390,7 @@ mt76_testmode_tx_stop(struct mt76_phy *phy) |
| 1531 | + wait_event_timeout(dev->tx_wait, td->tx_done == td->tx_queued, |
| 1532 | + MT76_TM_TIMEOUT * HZ); |
| 1533 | + |
| 1534 | +- mt76_testmode_free_skb(phy); |
| 1535 | ++ mt76_testmode_free_skb_all(phy); |
| 1536 | + } |
| 1537 | + |
| 1538 | + static inline void |
| 1539 | +@@ -331,8 +430,11 @@ __mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state) |
| 1540 | + struct mt76_dev *dev = phy->dev; |
| 1541 | + int err; |
| 1542 | + |
| 1543 | +- if (prev_state == MT76_TM_STATE_TX_FRAMES) |
| 1544 | ++ if (prev_state == MT76_TM_STATE_TX_FRAMES) { |
| 1545 | ++ if (phy->test.tx_rate_mode == MT76_TM_TX_MODE_HE_MU) |
| 1546 | ++ dev->test_ops->set_state(phy, MT76_TM_STATE_IDLE); |
| 1547 | + mt76_testmode_tx_stop(phy); |
| 1548 | ++ } |
| 1549 | + |
| 1550 | + if (state == MT76_TM_STATE_TX_FRAMES) { |
| 1551 | + err = mt76_testmode_tx_init(phy); |
| 1552 | +@@ -382,7 +484,6 @@ int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state |
| 1553 | + } |
| 1554 | + |
| 1555 | + return __mt76_testmode_set_state(phy, state); |
| 1556 | +- |
| 1557 | + } |
| 1558 | + EXPORT_SYMBOL(mt76_testmode_set_state); |
| 1559 | + |
| 1560 | +@@ -402,6 +503,44 @@ mt76_tm_get_u8(struct nlattr *attr, u8 *dest, u8 min, u8 max) |
| 1561 | + return 0; |
| 1562 | + } |
| 1563 | + |
| 1564 | ++static int |
| 1565 | ++mt76_testmode_set_eeprom(struct mt76_phy *phy, struct nlattr **tb) |
| 1566 | ++{ |
| 1567 | ++ struct mt76_dev *dev = phy->dev; |
| 1568 | ++ u8 action, val[MT76_TM_EEPROM_BLOCK_SIZE]; |
| 1569 | ++ u32 offset = 0; |
| 1570 | ++ int err = -EINVAL; |
| 1571 | ++ |
| 1572 | ++ if (!dev->test_ops->set_eeprom) |
| 1573 | ++ return -EOPNOTSUPP; |
| 1574 | ++ |
| 1575 | ++ if (mt76_tm_get_u8(tb[MT76_TM_ATTR_EEPROM_ACTION], &action, |
| 1576 | ++ 0, MT76_TM_EEPROM_ACTION_MAX)) |
| 1577 | ++ goto out; |
| 1578 | ++ |
| 1579 | ++ if (tb[MT76_TM_ATTR_EEPROM_OFFSET]) { |
| 1580 | ++ struct nlattr *cur; |
| 1581 | ++ int rem, idx = 0; |
| 1582 | ++ |
| 1583 | ++ offset = nla_get_u32(tb[MT76_TM_ATTR_EEPROM_OFFSET]); |
| 1584 | ++ if (!!(offset % MT76_TM_EEPROM_BLOCK_SIZE) || |
| 1585 | ++ !tb[MT76_TM_ATTR_EEPROM_VAL]) |
| 1586 | ++ goto out; |
| 1587 | ++ |
| 1588 | ++ nla_for_each_nested(cur, tb[MT76_TM_ATTR_EEPROM_VAL], rem) { |
| 1589 | ++ if (nla_len(cur) != 1 || idx >= ARRAY_SIZE(val)) |
| 1590 | ++ goto out; |
| 1591 | ++ |
| 1592 | ++ val[idx++] = nla_get_u8(cur); |
| 1593 | ++ } |
| 1594 | ++ } |
| 1595 | ++ |
| 1596 | ++ err = dev->test_ops->set_eeprom(phy, offset, val, action); |
| 1597 | ++ |
| 1598 | ++out: |
| 1599 | ++ return err; |
| 1600 | ++} |
| 1601 | ++ |
| 1602 | + int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1603 | + void *data, int len) |
| 1604 | + { |
| 1605 | +@@ -425,6 +564,11 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1606 | + |
| 1607 | + mutex_lock(&dev->mutex); |
| 1608 | + |
| 1609 | ++ if (tb[MT76_TM_ATTR_EEPROM_ACTION]) { |
| 1610 | ++ err = mt76_testmode_set_eeprom(phy, tb); |
| 1611 | ++ goto out; |
| 1612 | ++ } |
| 1613 | ++ |
| 1614 | + if (tb[MT76_TM_ATTR_RESET]) { |
| 1615 | + mt76_testmode_set_state(phy, MT76_TM_STATE_OFF); |
| 1616 | + memset(td, 0, sizeof(*td)); |
| 1617 | +@@ -446,13 +590,16 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1618 | + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_LDPC], &td->tx_rate_ldpc, 0, 1) || |
| 1619 | + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_RATE_STBC], &td->tx_rate_stbc, 0, 1) || |
| 1620 | + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_LTF], &td->tx_ltf, 0, 2) || |
| 1621 | +- mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], |
| 1622 | +- &td->tx_antenna_mask, 0, 0xff) || |
| 1623 | ++ mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_ANTENNA], &td->tx_antenna_mask, |
| 1624 | ++ 1, phy->antenna_mask) || |
| 1625 | + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_SPE_IDX], &td->tx_spe_idx, 0, 27) || |
| 1626 | + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_DUTY_CYCLE], |
| 1627 | + &td->tx_duty_cycle, 0, 99) || |
| 1628 | + mt76_tm_get_u8(tb[MT76_TM_ATTR_TX_POWER_CONTROL], |
| 1629 | +- &td->tx_power_control, 0, 1)) |
| 1630 | ++ &td->tx_power_control, 0, 1) || |
| 1631 | ++ mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &td->aid, 0, 16) || |
| 1632 | ++ mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_ALLOC], &td->ru_alloc, 0, 0xff) || |
| 1633 | ++ mt76_tm_get_u8(tb[MT76_TM_ATTR_RU_IDX], &td->ru_idx, 0, 68)) |
| 1634 | + goto out; |
| 1635 | + |
| 1636 | + if (tb[MT76_TM_ATTR_TX_LENGTH]) { |
| 1637 | +@@ -484,8 +631,7 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1638 | + |
| 1639 | + if (tb[MT76_TM_ATTR_TX_POWER]) { |
| 1640 | + struct nlattr *cur; |
| 1641 | +- int idx = 0; |
| 1642 | +- int rem; |
| 1643 | ++ int rem, idx = 0; |
| 1644 | + |
| 1645 | + nla_for_each_nested(cur, tb[MT76_TM_ATTR_TX_POWER], rem) { |
| 1646 | + if (nla_len(cur) != 1 || |
| 1647 | +@@ -505,11 +651,47 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| 1648 | + if (nla_len(cur) != ETH_ALEN || idx >= 3) |
| 1649 | + goto out; |
| 1650 | + |
| 1651 | +- memcpy(td->addr[idx], nla_data(cur), ETH_ALEN); |
| 1652 | ++ memcpy(td->addr[idx++], nla_data(cur), ETH_ALEN); |
| 1653 | ++ } |
| 1654 | ++ } |
| 1655 | ++ |
| 1656 | ++ if (tb[MT76_TM_ATTR_CFG]) { |
| 1657 | ++ struct nlattr *cur; |
| 1658 | ++ int rem, idx = 0; |
| 1659 | ++ |
| 1660 | ++ nla_for_each_nested(cur, tb[MT76_TM_ATTR_CFG], rem) { |
| 1661 | ++ if (nla_len(cur) != 1 || idx >= 2) |
| 1662 | ++ goto out; |
| 1663 | ++ |
| 1664 | ++ if (idx == 0) |
| 1665 | ++ td->cfg.type = nla_get_u8(cur); |
| 1666 | ++ else |
| 1667 | ++ td->cfg.enable = nla_get_u8(cur); |
| 1668 | + idx++; |
| 1669 | + } |
| 1670 | + } |
| 1671 | + |
| 1672 | ++ if (tb[MT76_TM_ATTR_OFF_CH_SCAN_CH]) { |
| 1673 | ++ u8 ch = nla_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CH]); |
| 1674 | ++ struct ieee80211_supported_band *sband; |
| 1675 | ++ |
| 1676 | ++ sband = ch > 14 ? &phy->sband_5g.sband : |
| 1677 | ++ &phy->sband_2g.sband; |
| 1678 | ++ if (ch && (ch < sband->channels[0].hw_value || |
| 1679 | ++ ch > sband->channels[sband->n_channels - 1].hw_value)) |
| 1680 | ++ goto out; |
| 1681 | ++ |
| 1682 | ++ td->off_ch_scan_ch = ch; |
| 1683 | ++ |
| 1684 | ++ if (mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH], |
| 1685 | ++ &td->off_ch_scan_center_ch, ch - 6, ch + 6) || |
| 1686 | ++ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_BW], |
| 1687 | ++ &td->off_ch_scan_bw, 0, 6) || |
| 1688 | ++ mt76_tm_get_u8(tb[MT76_TM_ATTR_OFF_CH_SCAN_PATH], |
| 1689 | ++ &td->off_ch_scan_path, 1, 0xff)) |
| 1690 | ++ goto out; |
| 1691 | ++ } |
| 1692 | ++ |
| 1693 | + if (dev->test_ops->set_params) { |
| 1694 | + err = dev->test_ops->set_params(phy, tb, state); |
| 1695 | + if (err) |
| 1696 | +@@ -559,6 +741,9 @@ mt76_testmode_dump_stats(struct mt76_phy *phy, struct sk_buff *msg) |
| 1697 | + nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_PACKETS, rx_packets, |
| 1698 | + MT76_TM_STATS_ATTR_PAD) || |
| 1699 | + nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_FCS_ERROR, rx_fcs_error, |
| 1700 | ++ MT76_TM_STATS_ATTR_PAD) || |
| 1701 | ++ nla_put_u64_64bit(msg, MT76_TM_STATS_ATTR_RX_LEN_MISMATCH, |
| 1702 | ++ td->rx_stats.len_mismatch, |
| 1703 | + MT76_TM_STATS_ATTR_PAD)) |
| 1704 | + return -EMSGSIZE; |
| 1705 | + |
| 1706 | +@@ -571,6 +756,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, |
| 1707 | + struct mt76_phy *phy = hw->priv; |
| 1708 | + struct mt76_dev *dev = phy->dev; |
| 1709 | + struct mt76_testmode_data *td = &phy->test; |
| 1710 | ++ struct mt76_testmode_sta_data *sd = &td->sd; |
| 1711 | + struct nlattr *tb[NUM_MT76_TM_ATTRS] = {}; |
| 1712 | + int err = 0; |
| 1713 | + void *a; |
| 1714 | +@@ -603,6 +789,23 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, |
| 1715 | + goto out; |
| 1716 | + } |
| 1717 | + |
| 1718 | ++ if (tb[MT76_TM_ATTR_AID]) { |
| 1719 | ++ struct mt76_testmode_sta *tm_sta; |
| 1720 | ++ u8 aid; |
| 1721 | ++ |
| 1722 | ++ err = mt76_tm_get_u8(tb[MT76_TM_ATTR_AID], &aid, 1, 16); |
| 1723 | ++ if (err) |
| 1724 | ++ goto out; |
| 1725 | ++ |
| 1726 | ++ tm_sta = mt76_testmode_aid_get_sta(phy, aid); |
| 1727 | ++ if (!tm_sta) { |
| 1728 | ++ err = -EINVAL; |
| 1729 | ++ goto out; |
| 1730 | ++ } |
| 1731 | ++ |
| 1732 | ++ sd = &tm_sta->sd; |
| 1733 | ++ } |
| 1734 | ++ |
| 1735 | + mt76_testmode_init_defaults(phy); |
| 1736 | + |
| 1737 | + err = -EMSGSIZE; |
| 1738 | +@@ -615,12 +818,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, |
| 1739 | + goto out; |
| 1740 | + |
| 1741 | + if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) || |
| 1742 | +- nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, td->tx_mpdu_len) || |
| 1743 | + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_MODE, td->tx_rate_mode) || |
| 1744 | +- nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, td->tx_rate_nss) || |
| 1745 | +- nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, td->tx_rate_idx) || |
| 1746 | + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) || |
| 1747 | +- nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) || |
| 1748 | + nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) || |
| 1749 | + (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) && |
| 1750 | + nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) || |
| 1751 | +@@ -640,6 +839,15 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg, |
| 1752 | + nla_put_u8(msg, MT76_TM_ATTR_FREQ_OFFSET, td->freq_offset))) |
| 1753 | + goto out; |
| 1754 | + |
| 1755 | ++ if (nla_put_u8(msg, MT76_TM_ATTR_AID, sd->aid) || |
| 1756 | ++ nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_NSS, sd->tx_rate_nss) || |
| 1757 | ++ nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_IDX, sd->tx_rate_idx) || |
| 1758 | ++ nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, sd->tx_rate_ldpc) || |
| 1759 | ++ nla_put_u8(msg, MT76_TM_ATTR_RU_ALLOC, sd->ru_alloc) || |
| 1760 | ++ nla_put_u8(msg, MT76_TM_ATTR_RU_IDX, sd->ru_idx) || |
| 1761 | ++ nla_put_u32(msg, MT76_TM_ATTR_TX_LENGTH, sd->tx_mpdu_len)) |
| 1762 | ++ goto out; |
| 1763 | ++ |
| 1764 | + if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) { |
| 1765 | + a = nla_nest_start(msg, MT76_TM_ATTR_TX_POWER); |
| 1766 | + if (!a) |
| 1767 | +diff --git a/testmode.h b/testmode.h |
| 1768 | +index 5e2792d..b360d7a 100644 |
| 1769 | +--- a/testmode.h |
| 1770 | ++++ b/testmode.h |
| 1771 | +@@ -6,6 +6,8 @@ |
| 1772 | + #define __MT76_TESTMODE_H |
| 1773 | + |
| 1774 | + #define MT76_TM_TIMEOUT 10 |
| 1775 | ++#define MT76_TM_EEPROM_BLOCK_SIZE 16 |
| 1776 | ++#define MT76_TM_MAX_STA_NUM 16 |
| 1777 | + |
| 1778 | + /** |
| 1779 | + * enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA |
| 1780 | +@@ -47,6 +49,20 @@ |
| 1781 | + * @MT76_TM_ATTR_DRV_DATA: driver specific netlink attrs (nested) |
| 1782 | + * |
| 1783 | + * @MT76_TM_ATTR_MAC_ADDRS: array of nested MAC addresses (nested) |
| 1784 | ++ * |
| 1785 | ++ * @MT76_TM_ATTR_EEPROM_ACTION: eeprom setting actions |
| 1786 | ++ * (u8, see &enum mt76_testmode_eeprom_action) |
| 1787 | ++ * @MT76_TM_ATTR_EEPROM_OFFSET: offset of eeprom data block for writing (u32) |
| 1788 | ++ * @MT76_TM_ATTR_EEPROM_VAL: values for writing into a 16-byte data block |
| 1789 | ++ * (nested, u8 attrs) |
| 1790 | ++ * |
| 1791 | ++ * @MT76_TM_ATTR_CFG: config testmode rf feature (nested, see &mt76_testmode_cfg) |
| 1792 | ++ * |
| 1793 | ++ * @MT76_TM_ATTR_OFF_CH_SCAN_CH: monitored channel for off channel scan (u8) |
| 1794 | ++ * @MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH: monitored channel for off channel scan (u8) |
| 1795 | ++ * @MT76_TM_ATTR_OFF_CH_SCAN_BW: monitored bw for off channel scan (u8) |
| 1796 | ++ * @MT76_TM_ATTR_OFF_CH_SCAN_PATH: monitored rx path for off channel scan (u8) |
| 1797 | ++ * |
| 1798 | + */ |
| 1799 | + enum mt76_testmode_attr { |
| 1800 | + MT76_TM_ATTR_UNSPEC, |
| 1801 | +@@ -85,6 +101,21 @@ enum mt76_testmode_attr { |
| 1802 | + |
| 1803 | + MT76_TM_ATTR_MAC_ADDRS, |
| 1804 | + |
| 1805 | ++ MT76_TM_ATTR_EEPROM_ACTION, |
| 1806 | ++ MT76_TM_ATTR_EEPROM_OFFSET, |
| 1807 | ++ MT76_TM_ATTR_EEPROM_VAL, |
| 1808 | ++ |
| 1809 | ++ MT76_TM_ATTR_CFG, |
| 1810 | ++ |
| 1811 | ++ MT76_TM_ATTR_OFF_CH_SCAN_CH, |
| 1812 | ++ MT76_TM_ATTR_OFF_CH_SCAN_CENTER_CH, |
| 1813 | ++ MT76_TM_ATTR_OFF_CH_SCAN_BW, |
| 1814 | ++ MT76_TM_ATTR_OFF_CH_SCAN_PATH, |
| 1815 | ++ |
| 1816 | ++ MT76_TM_ATTR_AID, |
| 1817 | ++ MT76_TM_ATTR_RU_ALLOC, |
| 1818 | ++ MT76_TM_ATTR_RU_IDX, |
| 1819 | ++ |
| 1820 | + /* keep last */ |
| 1821 | + NUM_MT76_TM_ATTRS, |
| 1822 | + MT76_TM_ATTR_MAX = NUM_MT76_TM_ATTRS - 1, |
| 1823 | +@@ -101,6 +132,8 @@ enum mt76_testmode_attr { |
| 1824 | + * @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64) |
| 1825 | + * @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet |
| 1826 | + * see &enum mt76_testmode_rx_attr |
| 1827 | ++ * @MT76_TM_STATS_ATTR_RX_LEN_MISMATCH: number of rx packets with length |
| 1828 | ++ * mismatch error (u64) |
| 1829 | + */ |
| 1830 | + enum mt76_testmode_stats_attr { |
| 1831 | + MT76_TM_STATS_ATTR_UNSPEC, |
| 1832 | +@@ -113,6 +146,7 @@ enum mt76_testmode_stats_attr { |
| 1833 | + MT76_TM_STATS_ATTR_RX_PACKETS, |
| 1834 | + MT76_TM_STATS_ATTR_RX_FCS_ERROR, |
| 1835 | + MT76_TM_STATS_ATTR_LAST_RX, |
| 1836 | ++ MT76_TM_STATS_ATTR_RX_LEN_MISMATCH, |
| 1837 | + |
| 1838 | + /* keep last */ |
| 1839 | + NUM_MT76_TM_STATS_ATTRS, |
| 1840 | +@@ -195,4 +229,41 @@ enum mt76_testmode_tx_mode { |
| 1841 | + |
| 1842 | + extern const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS]; |
| 1843 | + |
| 1844 | ++/** |
| 1845 | ++ * enum mt76_testmode_eeprom_action - eeprom setting actions |
| 1846 | ++ * |
| 1847 | ++ * @MT76_TM_EEPROM_ACTION_UPDATE_DATA: update rf values to specific |
| 1848 | ++ * eeprom data block |
| 1849 | ++ * @MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE: send updated eeprom data to fw |
| 1850 | ++ * @MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE: write eeprom data back to efuse |
| 1851 | ++ */ |
| 1852 | ++enum mt76_testmode_eeprom_action { |
| 1853 | ++ MT76_TM_EEPROM_ACTION_UPDATE_DATA, |
| 1854 | ++ MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE, |
| 1855 | ++ MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE, |
| 1856 | ++ |
| 1857 | ++ /* keep last */ |
| 1858 | ++ NUM_MT76_TM_EEPROM_ACTION, |
| 1859 | ++ MT76_TM_EEPROM_ACTION_MAX = NUM_MT76_TM_EEPROM_ACTION - 1, |
| 1860 | ++}; |
| 1861 | ++ |
| 1862 | ++/** |
| 1863 | ++ * enum mt76_testmode_cfg - packet tx phy mode |
| 1864 | ++ * |
| 1865 | ++ * @MT76_TM_EEPROM_ACTION_UPDATE_DATA: update rf values to specific |
| 1866 | ++ * eeprom data block |
| 1867 | ++ * @MT76_TM_EEPROM_ACTION_UPDATE_BUFFER_MODE: send updated eeprom data to fw |
| 1868 | ++ * @MT76_TM_EEPROM_ACTION_WRITE_TO_EFUSE: write eeprom data back to efuse |
| 1869 | ++ */ |
| 1870 | ++enum mt76_testmode_cfg { |
| 1871 | ++ MT76_TM_CFG_TSSI, |
| 1872 | ++ MT76_TM_CFG_DPD, |
| 1873 | ++ MT76_TM_CFG_RATE_POWER_OFFSET, |
| 1874 | ++ MT76_TM_CFG_THERMAL_COMP, |
| 1875 | ++ |
| 1876 | ++ /* keep last */ |
| 1877 | ++ NUM_MT76_TM_CFG, |
| 1878 | ++ MT76_TM_CFG_MAX = NUM_MT76_TM_CFG - 1, |
| 1879 | ++}; |
| 1880 | ++ |
| 1881 | + #endif |
| 1882 | +diff --git a/tools/fields.c b/tools/fields.c |
| 1883 | +index e3f6908..036406c 100644 |
| 1884 | +--- a/tools/fields.c |
| 1885 | ++++ b/tools/fields.c |
| 1886 | +@@ -10,6 +10,7 @@ static const char * const testmode_state[] = { |
| 1887 | + [MT76_TM_STATE_IDLE] = "idle", |
| 1888 | + [MT76_TM_STATE_TX_FRAMES] = "tx_frames", |
| 1889 | + [MT76_TM_STATE_RX_FRAMES] = "rx_frames", |
| 1890 | ++ [MT76_TM_STATE_TX_CONT] = "tx_cont", |
| 1891 | + }; |
| 1892 | + |
| 1893 | + static const char * const testmode_tx_mode[] = { |
| 1894 | +@@ -201,6 +202,63 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb) |
| 1895 | + printf("%srx_per=%.02f%%\n", prefix, 100 * failed / total); |
| 1896 | + } |
| 1897 | + |
| 1898 | ++static bool parse_mac(const struct tm_field *field, int idx, |
| 1899 | ++ struct nl_msg *msg, const char *val) |
| 1900 | ++{ |
| 1901 | ++#define ETH_ALEN 6 |
| 1902 | ++ bool ret = true; |
| 1903 | ++ char *str, *cur, *ap; |
| 1904 | ++ void *a; |
| 1905 | ++ |
| 1906 | ++ ap = str = strdup(val); |
| 1907 | ++ |
| 1908 | ++ a = nla_nest_start(msg, idx); |
| 1909 | ++ |
| 1910 | ++ idx = 0; |
| 1911 | ++ while ((cur = strsep(&ap, ",")) != NULL) { |
| 1912 | ++ unsigned char addr[ETH_ALEN]; |
| 1913 | ++ char *val, *tmp = cur; |
| 1914 | ++ int i = 0; |
| 1915 | ++ |
| 1916 | ++ while ((val = strsep(&tmp, ":")) != NULL) { |
| 1917 | ++ if (i >= ETH_ALEN) |
| 1918 | ++ break; |
| 1919 | ++ |
| 1920 | ++ addr[i++] = strtoul(val, NULL, 16); |
| 1921 | ++ } |
| 1922 | ++ |
| 1923 | ++ nla_put(msg, idx, ETH_ALEN, addr); |
| 1924 | ++ |
| 1925 | ++ idx++; |
| 1926 | ++ } |
| 1927 | ++ |
| 1928 | ++ nla_nest_end(msg, a); |
| 1929 | ++ |
| 1930 | ++ free(str); |
| 1931 | ++ |
| 1932 | ++ return ret; |
| 1933 | ++} |
| 1934 | ++ |
| 1935 | ++static void print_mac(const struct tm_field *field, struct nlattr *attr) |
| 1936 | ++{ |
| 1937 | ++#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] |
| 1938 | ++#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" |
| 1939 | ++ unsigned char addr[3][6]; |
| 1940 | ++ struct nlattr *cur; |
| 1941 | ++ int idx = 0; |
| 1942 | ++ int rem; |
| 1943 | ++ |
| 1944 | ++ nla_for_each_nested(cur, attr, rem) { |
| 1945 | ++ if (nla_len(cur) != 6) |
| 1946 | ++ continue; |
| 1947 | ++ memcpy(addr[idx++], nla_data(cur), 6); |
| 1948 | ++ } |
| 1949 | ++ |
| 1950 | ++ printf("" MACSTR "," MACSTR "," MACSTR "", |
| 1951 | ++ MAC2STR(addr[0]), MAC2STR(addr[1]), MAC2STR(addr[2])); |
| 1952 | ++ |
| 1953 | ++ return; |
| 1954 | ++} |
| 1955 | + |
| 1956 | + #define FIELD_GENERIC(_field, _name, ...) \ |
| 1957 | + [FIELD_NAME(_field)] = { \ |
| 1958 | +@@ -250,6 +308,13 @@ static void print_extra_stats(const struct tm_field *field, struct nlattr **tb) |
| 1959 | + ##__VA_ARGS__ \ |
| 1960 | + ) |
| 1961 | + |
| 1962 | ++#define FIELD_MAC(_field, _name) \ |
| 1963 | ++ [FIELD_NAME(_field)] = { \ |
| 1964 | ++ .name = _name, \ |
| 1965 | ++ .parse = parse_mac, \ |
| 1966 | ++ .print = print_mac \ |
| 1967 | ++ } |
| 1968 | ++ |
| 1969 | + #define FIELD_NAME(_field) MT76_TM_RX_ATTR_##_field |
| 1970 | + static const struct tm_field rx_fields[NUM_MT76_TM_RX_ATTRS] = { |
| 1971 | + FIELD_RO(s32, FREQ_OFFSET, "freq_offset"), |
| 1972 | +@@ -300,10 +365,16 @@ static const struct tm_field testdata_fields[NUM_MT76_TM_ATTRS] = { |
| 1973 | + FIELD(u8, TX_RATE_LDPC, "tx_rate_ldpc"), |
| 1974 | + FIELD(u8, TX_RATE_STBC, "tx_rate_stbc"), |
| 1975 | + FIELD(u8, TX_LTF, "tx_ltf"), |
| 1976 | ++ FIELD(u8, TX_DUTY_CYCLE, "tx_duty_cycle"), |
| 1977 | ++ FIELD(u32, TX_IPG, "tx_ipg"), |
| 1978 | ++ FIELD(u32, TX_TIME, "tx_time"), |
| 1979 | + FIELD(u8, TX_POWER_CONTROL, "tx_power_control"), |
| 1980 | + FIELD_ARRAY(u8, TX_POWER, "tx_power"), |
| 1981 | + FIELD(u8, TX_ANTENNA, "tx_antenna"), |
| 1982 | ++ FIELD(u8, TX_SPE_IDX, "tx_spe_idx"), |
| 1983 | + FIELD(u32, FREQ_OFFSET, "freq_offset"), |
| 1984 | ++ FIELD(u8, AID, "aid"), |
| 1985 | ++ FIELD_MAC(MAC_ADDRS, "mac_addrs"), |
| 1986 | + FIELD_NESTED_RO(STATS, stats, "", |
| 1987 | + .print_extra = print_extra_stats), |
| 1988 | + }; |
| 1989 | +@@ -322,9 +393,14 @@ static struct nla_policy testdata_policy[NUM_MT76_TM_ATTRS] = { |
| 1990 | + [MT76_TM_ATTR_TX_RATE_LDPC] = { .type = NLA_U8 }, |
| 1991 | + [MT76_TM_ATTR_TX_RATE_STBC] = { .type = NLA_U8 }, |
| 1992 | + [MT76_TM_ATTR_TX_LTF] = { .type = NLA_U8 }, |
| 1993 | ++ [MT76_TM_ATTR_TX_DUTY_CYCLE] = { .type = NLA_U8 }, |
| 1994 | ++ [MT76_TM_ATTR_TX_IPG] = { .type = NLA_U32 }, |
| 1995 | ++ [MT76_TM_ATTR_TX_TIME] = { .type = NLA_U32 }, |
| 1996 | + [MT76_TM_ATTR_TX_POWER_CONTROL] = { .type = NLA_U8 }, |
| 1997 | + [MT76_TM_ATTR_TX_ANTENNA] = { .type = NLA_U8 }, |
| 1998 | ++ [MT76_TM_ATTR_TX_SPE_IDX] = { .type = NLA_U8 }, |
| 1999 | + [MT76_TM_ATTR_FREQ_OFFSET] = { .type = NLA_U32 }, |
| 2000 | ++ [MT76_TM_ATTR_AID] = { .type = NLA_U8 }, |
| 2001 | + [MT76_TM_ATTR_STATS] = { .type = NLA_NESTED }, |
| 2002 | + }; |
| 2003 | + |
| 2004 | +diff --git a/tx.c b/tx.c |
| 2005 | +index 6b8c9dc..ca5e6d9 100644 |
| 2006 | +--- a/tx.c |
| 2007 | ++++ b/tx.c |
| 2008 | +@@ -245,8 +245,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff * |
| 2009 | + if (mt76_is_testmode_skb(dev, skb, &hw)) { |
| 2010 | + struct mt76_phy *phy = hw->priv; |
| 2011 | + |
| 2012 | +- if (skb == phy->test.tx_skb) |
| 2013 | +- phy->test.tx_done++; |
| 2014 | ++ phy->test.tx_done++; |
| 2015 | + if (phy->test.tx_queued == phy->test.tx_done) |
| 2016 | + wake_up(&dev->tx_wait); |
| 2017 | + |
| 2018 | +-- |
| 2019 | +2.25.1 |
| 2020 | + |