162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* Copyright (C) 2020 MediaTek Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "mt7915.h" 562306a36Sopenharmony_ci#include "mac.h" 662306a36Sopenharmony_ci#include "mcu.h" 762306a36Sopenharmony_ci#include "testmode.h" 862306a36Sopenharmony_ci 962306a36Sopenharmony_cienum { 1062306a36Sopenharmony_ci TM_CHANGED_TXPOWER, 1162306a36Sopenharmony_ci TM_CHANGED_FREQ_OFFSET, 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci /* must be last */ 1462306a36Sopenharmony_ci NUM_TM_CHANGED 1562306a36Sopenharmony_ci}; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic const u8 tm_change_map[] = { 1862306a36Sopenharmony_ci [TM_CHANGED_TXPOWER] = MT76_TM_ATTR_TX_POWER, 1962306a36Sopenharmony_ci [TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET, 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct reg_band { 2362306a36Sopenharmony_ci u32 band[2]; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define REG_BAND(_list, _reg) \ 2762306a36Sopenharmony_ci { _list.band[0] = MT_##_reg(0); \ 2862306a36Sopenharmony_ci _list.band[1] = MT_##_reg(1); } 2962306a36Sopenharmony_ci#define REG_BAND_IDX(_list, _reg, _idx) \ 3062306a36Sopenharmony_ci { _list.band[0] = MT_##_reg(0, _idx); \ 3162306a36Sopenharmony_ci _list.band[1] = MT_##_reg(1, _idx); } 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define TM_REG_MAX_ID 17 3462306a36Sopenharmony_cistatic struct reg_band reg_backup_list[TM_REG_MAX_ID]; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int 3862306a36Sopenharmony_cimt7915_tm_set_tx_power(struct mt7915_phy *phy) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 4162306a36Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 4262306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = &mphy->chandef; 4362306a36Sopenharmony_ci int freq = chandef->center_freq1; 4462306a36Sopenharmony_ci int ret; 4562306a36Sopenharmony_ci struct { 4662306a36Sopenharmony_ci u8 format_id; 4762306a36Sopenharmony_ci u8 band_idx; 4862306a36Sopenharmony_ci s8 tx_power; 4962306a36Sopenharmony_ci u8 ant_idx; /* Only 0 is valid */ 5062306a36Sopenharmony_ci u8 center_chan; 5162306a36Sopenharmony_ci u8 rsv[3]; 5262306a36Sopenharmony_ci } __packed req = { 5362306a36Sopenharmony_ci .format_id = 0xf, 5462306a36Sopenharmony_ci .band_idx = phy->mt76->band_idx, 5562306a36Sopenharmony_ci .center_chan = ieee80211_frequency_to_channel(freq), 5662306a36Sopenharmony_ci }; 5762306a36Sopenharmony_ci u8 *tx_power = NULL; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (phy->mt76->test.state != MT76_TM_STATE_OFF) 6062306a36Sopenharmony_ci tx_power = phy->mt76->test.tx_power; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Tx power of the other antennas are the same as antenna 0 */ 6362306a36Sopenharmony_ci if (tx_power && tx_power[0]) 6462306a36Sopenharmony_ci req.tx_power = tx_power[0]; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci ret = mt76_mcu_send_msg(&dev->mt76, 6762306a36Sopenharmony_ci MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), 6862306a36Sopenharmony_ci &req, sizeof(req), false); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return ret; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int 7462306a36Sopenharmony_cimt7915_tm_set_freq_offset(struct mt7915_phy *phy, bool en, u32 val) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 7762306a36Sopenharmony_ci struct mt7915_tm_cmd req = { 7862306a36Sopenharmony_ci .testmode_en = en, 7962306a36Sopenharmony_ci .param_idx = MCU_ATE_SET_FREQ_OFFSET, 8062306a36Sopenharmony_ci .param.freq.band = phy->mt76->band_idx, 8162306a36Sopenharmony_ci .param.freq.freq_offset = cpu_to_le32(val), 8262306a36Sopenharmony_ci }; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, 8562306a36Sopenharmony_ci sizeof(req), false); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int 8962306a36Sopenharmony_cimt7915_tm_mode_ctrl(struct mt7915_dev *dev, bool enable) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct { 9262306a36Sopenharmony_ci u8 format_id; 9362306a36Sopenharmony_ci bool enable; 9462306a36Sopenharmony_ci u8 rsv[2]; 9562306a36Sopenharmony_ci } __packed req = { 9662306a36Sopenharmony_ci .format_id = 0x6, 9762306a36Sopenharmony_ci .enable = enable, 9862306a36Sopenharmony_ci }; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, 10162306a36Sopenharmony_ci MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), 10262306a36Sopenharmony_ci &req, sizeof(req), false); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int 10662306a36Sopenharmony_cimt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 10962306a36Sopenharmony_ci struct mt7915_tm_cmd req = { 11062306a36Sopenharmony_ci .testmode_en = 1, 11162306a36Sopenharmony_ci .param_idx = MCU_ATE_SET_TRX, 11262306a36Sopenharmony_ci .param.trx.type = type, 11362306a36Sopenharmony_ci .param.trx.enable = en, 11462306a36Sopenharmony_ci .param.trx.band = phy->mt76->band_idx, 11562306a36Sopenharmony_ci }; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, 11862306a36Sopenharmony_ci sizeof(req), false); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int 12262306a36Sopenharmony_cimt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 12562306a36Sopenharmony_ci struct mt7915_tm_cmd req = { 12662306a36Sopenharmony_ci .testmode_en = 1, 12762306a36Sopenharmony_ci .param_idx = MCU_ATE_CLEAN_TXQUEUE, 12862306a36Sopenharmony_ci .param.clean.wcid = wcid, 12962306a36Sopenharmony_ci .param.clean.band = phy->mt76->band_idx, 13062306a36Sopenharmony_ci }; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, 13362306a36Sopenharmony_ci sizeof(req), false); 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int 13762306a36Sopenharmony_cimt7915_tm_set_slot_time(struct mt7915_phy *phy, u8 slot_time, u8 sifs) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 14062306a36Sopenharmony_ci struct mt7915_tm_cmd req = { 14162306a36Sopenharmony_ci .testmode_en = !(phy->mt76->test.state == MT76_TM_STATE_OFF), 14262306a36Sopenharmony_ci .param_idx = MCU_ATE_SET_SLOT_TIME, 14362306a36Sopenharmony_ci .param.slot.slot_time = slot_time, 14462306a36Sopenharmony_ci .param.slot.sifs = sifs, 14562306a36Sopenharmony_ci .param.slot.rifs = 2, 14662306a36Sopenharmony_ci .param.slot.eifs = cpu_to_le16(60), 14762306a36Sopenharmony_ci .param.slot.band = phy->mt76->band_idx, 14862306a36Sopenharmony_ci }; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req, 15162306a36Sopenharmony_ci sizeof(req), false); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int 15562306a36Sopenharmony_cimt7915_tm_set_tam_arb(struct mt7915_phy *phy, bool enable, bool mu) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 15862306a36Sopenharmony_ci u32 op_mode; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (!enable) 16162306a36Sopenharmony_ci op_mode = TAM_ARB_OP_MODE_NORMAL; 16262306a36Sopenharmony_ci else if (mu) 16362306a36Sopenharmony_ci op_mode = TAM_ARB_OP_MODE_TEST; 16462306a36Sopenharmony_ci else 16562306a36Sopenharmony_ci op_mode = TAM_ARB_OP_MODE_FORCE_SU; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return mt7915_mcu_set_muru_ctrl(dev, MURU_SET_ARB_OP_MODE, op_mode); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int 17162306a36Sopenharmony_cimt7915_tm_set_wmm_qid(struct mt7915_phy *phy, u8 qid, u8 aifs, u8 cw_min, 17262306a36Sopenharmony_ci u16 cw_max, u16 txop) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct mt7915_vif *mvif = (struct mt7915_vif *)phy->monitor_vif->drv_priv; 17562306a36Sopenharmony_ci struct mt7915_mcu_tx req = { .total = 1 }; 17662306a36Sopenharmony_ci struct edca *e = &req.edca[0]; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci e->queue = qid + mvif->mt76.wmm_idx * MT76_CONNAC_MAX_WMM_SETS; 17962306a36Sopenharmony_ci e->set = WMM_PARAM_SET; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci e->aifs = aifs; 18262306a36Sopenharmony_ci e->cw_min = cw_min; 18362306a36Sopenharmony_ci e->cw_max = cpu_to_le16(cw_max); 18462306a36Sopenharmony_ci e->txop = cpu_to_le16(txop); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return mt7915_mcu_update_edca(phy->dev, &req); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int 19062306a36Sopenharmony_cimt7915_tm_set_ipg_params(struct mt7915_phy *phy, u32 ipg, u8 mode) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci#define TM_DEFAULT_SIFS 10 19362306a36Sopenharmony_ci#define TM_MAX_SIFS 127 19462306a36Sopenharmony_ci#define TM_MAX_AIFSN 0xf 19562306a36Sopenharmony_ci#define TM_MIN_AIFSN 0x1 19662306a36Sopenharmony_ci#define BBP_PROC_TIME 1500 19762306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 19862306a36Sopenharmony_ci u8 sig_ext = (mode == MT76_TM_TX_MODE_CCK) ? 0 : 6; 19962306a36Sopenharmony_ci u8 slot_time = 9, sifs = TM_DEFAULT_SIFS; 20062306a36Sopenharmony_ci u8 aifsn = TM_MIN_AIFSN; 20162306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 20262306a36Sopenharmony_ci u32 i2t_time, tr2t_time, txv_time; 20362306a36Sopenharmony_ci u16 cw = 0; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (ipg < sig_ext + slot_time + sifs) 20662306a36Sopenharmony_ci ipg = 0; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (!ipg) 20962306a36Sopenharmony_ci goto done; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ipg -= sig_ext; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (ipg <= (TM_MAX_SIFS + slot_time)) { 21462306a36Sopenharmony_ci sifs = ipg - slot_time; 21562306a36Sopenharmony_ci } else { 21662306a36Sopenharmony_ci u32 val = (ipg + slot_time) / slot_time; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci while (val >>= 1) 21962306a36Sopenharmony_ci cw++; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (cw > 16) 22262306a36Sopenharmony_ci cw = 16; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci ipg -= ((1 << cw) - 1) * slot_time; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci aifsn = ipg / slot_time; 22762306a36Sopenharmony_ci if (aifsn > TM_MAX_AIFSN) 22862306a36Sopenharmony_ci aifsn = TM_MAX_AIFSN; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ipg -= aifsn * slot_time; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (ipg > TM_DEFAULT_SIFS) 23362306a36Sopenharmony_ci sifs = min_t(u32, ipg, TM_MAX_SIFS); 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_cidone: 23662306a36Sopenharmony_ci txv_time = mt76_get_field(dev, MT_TMAC_ATCR(band), 23762306a36Sopenharmony_ci MT_TMAC_ATCR_TXV_TOUT); 23862306a36Sopenharmony_ci txv_time *= 50; /* normal clock time */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci i2t_time = (slot_time * 1000 - txv_time - BBP_PROC_TIME) / 50; 24162306a36Sopenharmony_ci tr2t_time = (sifs * 1000 - txv_time - BBP_PROC_TIME) / 50; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci mt76_set(dev, MT_TMAC_TRCR0(band), 24462306a36Sopenharmony_ci FIELD_PREP(MT_TMAC_TRCR0_TR2T_CHK, tr2t_time) | 24562306a36Sopenharmony_ci FIELD_PREP(MT_TMAC_TRCR0_I2T_CHK, i2t_time)); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci mt7915_tm_set_slot_time(phy, slot_time, sifs); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return mt7915_tm_set_wmm_qid(phy, 25062306a36Sopenharmony_ci mt76_connac_lmac_mapping(IEEE80211_AC_BE), 25162306a36Sopenharmony_ci aifsn, cw, cw, 0); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int 25562306a36Sopenharmony_cimt7915_tm_set_tx_len(struct mt7915_phy *phy, u32 tx_time) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct mt76_phy *mphy = phy->mt76; 25862306a36Sopenharmony_ci struct mt76_testmode_data *td = &mphy->test; 25962306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 26062306a36Sopenharmony_ci struct rate_info rate = {}; 26162306a36Sopenharmony_ci u16 flags = 0, tx_len; 26262306a36Sopenharmony_ci u32 bitrate; 26362306a36Sopenharmony_ci int ret; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!tx_time) 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci rate.mcs = td->tx_rate_idx; 26962306a36Sopenharmony_ci rate.nss = td->tx_rate_nss; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci switch (td->tx_rate_mode) { 27262306a36Sopenharmony_ci case MT76_TM_TX_MODE_CCK: 27362306a36Sopenharmony_ci case MT76_TM_TX_MODE_OFDM: 27462306a36Sopenharmony_ci if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) 27562306a36Sopenharmony_ci sband = &mphy->sband_5g.sband; 27662306a36Sopenharmony_ci else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) 27762306a36Sopenharmony_ci sband = &mphy->sband_6g.sband; 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci sband = &mphy->sband_2g.sband; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci rate.legacy = sband->bitrates[rate.mcs].bitrate; 28262306a36Sopenharmony_ci break; 28362306a36Sopenharmony_ci case MT76_TM_TX_MODE_HT: 28462306a36Sopenharmony_ci rate.mcs += rate.nss * 8; 28562306a36Sopenharmony_ci flags |= RATE_INFO_FLAGS_MCS; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (td->tx_rate_sgi) 28862306a36Sopenharmony_ci flags |= RATE_INFO_FLAGS_SHORT_GI; 28962306a36Sopenharmony_ci break; 29062306a36Sopenharmony_ci case MT76_TM_TX_MODE_VHT: 29162306a36Sopenharmony_ci flags |= RATE_INFO_FLAGS_VHT_MCS; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (td->tx_rate_sgi) 29462306a36Sopenharmony_ci flags |= RATE_INFO_FLAGS_SHORT_GI; 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_SU: 29762306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_EXT_SU: 29862306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_TB: 29962306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_MU: 30062306a36Sopenharmony_ci rate.he_gi = td->tx_rate_sgi; 30162306a36Sopenharmony_ci flags |= RATE_INFO_FLAGS_HE_MCS; 30262306a36Sopenharmony_ci break; 30362306a36Sopenharmony_ci default: 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci rate.flags = flags; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci switch (mphy->chandef.width) { 30962306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 31062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 31162306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_160; 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 31462306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_80; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 31762306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_40; 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci default: 32062306a36Sopenharmony_ci rate.bw = RATE_INFO_BW_20; 32162306a36Sopenharmony_ci break; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci bitrate = cfg80211_calculate_bitrate(&rate); 32562306a36Sopenharmony_ci tx_len = bitrate * tx_time / 10 / 8; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci ret = mt76_testmode_alloc_skb(phy->mt76, tx_len); 32862306a36Sopenharmony_ci if (ret) 32962306a36Sopenharmony_ci return ret; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void 33562306a36Sopenharmony_cimt7915_tm_reg_backup_restore(struct mt7915_phy *phy) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int n_regs = ARRAY_SIZE(reg_backup_list); 33862306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 33962306a36Sopenharmony_ci u32 *b = phy->test.reg_backup; 34062306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 34162306a36Sopenharmony_ci int i; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[0], AGG_PCR0, 0); 34462306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[1], AGG_PCR0, 1); 34562306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[2], AGG_AWSCR0, 0); 34662306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[3], AGG_AWSCR0, 1); 34762306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[4], AGG_AWSCR0, 2); 34862306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[5], AGG_AWSCR0, 3); 34962306a36Sopenharmony_ci REG_BAND(reg_backup_list[6], AGG_MRCR); 35062306a36Sopenharmony_ci REG_BAND(reg_backup_list[7], TMAC_TFCR0); 35162306a36Sopenharmony_ci REG_BAND(reg_backup_list[8], TMAC_TCR0); 35262306a36Sopenharmony_ci REG_BAND(reg_backup_list[9], AGG_ATCR1); 35362306a36Sopenharmony_ci REG_BAND(reg_backup_list[10], AGG_ATCR3); 35462306a36Sopenharmony_ci REG_BAND(reg_backup_list[11], TMAC_TRCR0); 35562306a36Sopenharmony_ci REG_BAND(reg_backup_list[12], TMAC_ICR0); 35662306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[13], ARB_DRNGR0, 0); 35762306a36Sopenharmony_ci REG_BAND_IDX(reg_backup_list[14], ARB_DRNGR0, 1); 35862306a36Sopenharmony_ci REG_BAND(reg_backup_list[15], WF_RFCR); 35962306a36Sopenharmony_ci REG_BAND(reg_backup_list[16], WF_RFCR1); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (phy->mt76->test.state == MT76_TM_STATE_OFF) { 36262306a36Sopenharmony_ci for (i = 0; i < n_regs; i++) 36362306a36Sopenharmony_ci mt76_wr(dev, reg_backup_list[i].band[band], b[i]); 36462306a36Sopenharmony_ci return; 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (!b) { 36862306a36Sopenharmony_ci b = devm_kzalloc(dev->mt76.dev, 4 * n_regs, GFP_KERNEL); 36962306a36Sopenharmony_ci if (!b) 37062306a36Sopenharmony_ci return; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci phy->test.reg_backup = b; 37362306a36Sopenharmony_ci for (i = 0; i < n_regs; i++) 37462306a36Sopenharmony_ci b[i] = mt76_rr(dev, reg_backup_list[i].band[band]); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci mt76_clear(dev, MT_AGG_PCR0(band, 0), MT_AGG_PCR0_MM_PROT | 37862306a36Sopenharmony_ci MT_AGG_PCR0_GF_PROT | MT_AGG_PCR0_ERP_PROT | 37962306a36Sopenharmony_ci MT_AGG_PCR0_VHT_PROT | MT_AGG_PCR0_BW20_PROT | 38062306a36Sopenharmony_ci MT_AGG_PCR0_BW40_PROT | MT_AGG_PCR0_BW80_PROT); 38162306a36Sopenharmony_ci mt76_set(dev, MT_AGG_PCR0(band, 0), MT_AGG_PCR0_PTA_WIN_DIS); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci mt76_wr(dev, MT_AGG_PCR0(band, 1), MT_AGG_PCR1_RTS0_NUM_THRES | 38462306a36Sopenharmony_ci MT_AGG_PCR1_RTS0_LEN_THRES); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci mt76_clear(dev, MT_AGG_MRCR(band), MT_AGG_MRCR_BAR_CNT_LIMIT | 38762306a36Sopenharmony_ci MT_AGG_MRCR_LAST_RTS_CTS_RN | MT_AGG_MRCR_RTS_FAIL_LIMIT | 38862306a36Sopenharmony_ci MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci mt76_rmw(dev, MT_AGG_MRCR(band), MT_AGG_MRCR_RTS_FAIL_LIMIT | 39162306a36Sopenharmony_ci MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, 39262306a36Sopenharmony_ci FIELD_PREP(MT_AGG_MRCR_RTS_FAIL_LIMIT, 1) | 39362306a36Sopenharmony_ci FIELD_PREP(MT_AGG_MRCR_TXCMD_RTS_FAIL_LIMIT, 1)); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci mt76_wr(dev, MT_TMAC_TFCR0(band), 0); 39662306a36Sopenharmony_ci mt76_clear(dev, MT_TMAC_TCR0(band), MT_TMAC_TCR0_TBTT_STOP_CTRL); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* config rx filter for testmode rx */ 39962306a36Sopenharmony_ci mt76_wr(dev, MT_WF_RFCR(band), 0xcf70a); 40062306a36Sopenharmony_ci mt76_wr(dev, MT_WF_RFCR1(band), 0); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void 40462306a36Sopenharmony_cimt7915_tm_init(struct mt7915_phy *phy, bool en) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) 40962306a36Sopenharmony_ci return; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci mt7915_mcu_set_sku_en(phy, !en); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci mt7915_tm_mode_ctrl(dev, en); 41462306a36Sopenharmony_ci mt7915_tm_reg_backup_restore(phy); 41562306a36Sopenharmony_ci mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en); 41862306a36Sopenharmony_ci mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci if (!en) 42162306a36Sopenharmony_ci mt7915_tm_set_tam_arb(phy, en, 0); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic void 42562306a36Sopenharmony_cimt7915_tm_update_channel(struct mt7915_phy *phy) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci mutex_unlock(&phy->dev->mt76.mutex); 42862306a36Sopenharmony_ci mt7915_set_channel(phy); 42962306a36Sopenharmony_ci mutex_lock(&phy->dev->mt76.mutex); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH)); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void 43562306a36Sopenharmony_cimt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct mt76_testmode_data *td = &phy->mt76->test; 43862306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 43962306a36Sopenharmony_ci struct ieee80211_tx_info *info; 44062306a36Sopenharmony_ci u8 duty_cycle = td->tx_duty_cycle; 44162306a36Sopenharmony_ci u32 tx_time = td->tx_time; 44262306a36Sopenharmony_ci u32 ipg = td->tx_ipg; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); 44562306a36Sopenharmony_ci mt7915_tm_clean_hwq(phy, dev->mt76.global_wcid.idx); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (en) { 44862306a36Sopenharmony_ci mt7915_tm_update_channel(phy); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (td->tx_spe_idx) 45162306a36Sopenharmony_ci phy->test.spe_idx = td->tx_spe_idx; 45262306a36Sopenharmony_ci else 45362306a36Sopenharmony_ci phy->test.spe_idx = mt76_connac_spe_idx(td->tx_antenna_mask); 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci mt7915_tm_set_tam_arb(phy, en, 45762306a36Sopenharmony_ci td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* if all three params are set, duty_cycle will be ignored */ 46062306a36Sopenharmony_ci if (duty_cycle && tx_time && !ipg) { 46162306a36Sopenharmony_ci ipg = tx_time * 100 / duty_cycle - tx_time; 46262306a36Sopenharmony_ci } else if (duty_cycle && !tx_time && ipg) { 46362306a36Sopenharmony_ci if (duty_cycle < 100) 46462306a36Sopenharmony_ci tx_time = duty_cycle * ipg / (100 - duty_cycle); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode); 46862306a36Sopenharmony_ci mt7915_tm_set_tx_len(phy, tx_time); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (ipg) 47162306a36Sopenharmony_ci td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (!en || !td->tx_skb) 47462306a36Sopenharmony_ci return; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci info = IEEE80211_SKB_CB(td->tx_skb); 47762306a36Sopenharmony_ci info->control.vif = phy->monitor_vif; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci mt7915_tm_set_trx(phy, TM_MAC_TX, en); 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic void 48362306a36Sopenharmony_cimt7915_tm_set_rx_frames(struct mt7915_phy *phy, bool en) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (en) { 48862306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci mt7915_tm_update_channel(phy); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* read-clear */ 49362306a36Sopenharmony_ci mt76_rr(dev, MT_MIB_SDR3(phy->mt76->band_idx)); 49462306a36Sopenharmony_ci mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, en); 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic int 49962306a36Sopenharmony_cimt7915_tm_rf_switch_mode(struct mt7915_dev *dev, u32 oper) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct mt7915_tm_rf_test req = { 50262306a36Sopenharmony_ci .op.op_mode = cpu_to_le32(oper), 50362306a36Sopenharmony_ci }; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, 50662306a36Sopenharmony_ci sizeof(req), true); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int 51062306a36Sopenharmony_cimt7915_tm_set_tx_cont(struct mt7915_phy *phy, bool en) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci#define TX_CONT_START 0x05 51362306a36Sopenharmony_ci#define TX_CONT_STOP 0x06 51462306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 51562306a36Sopenharmony_ci struct cfg80211_chan_def *chandef = &phy->mt76->chandef; 51662306a36Sopenharmony_ci int freq1 = ieee80211_frequency_to_channel(chandef->center_freq1); 51762306a36Sopenharmony_ci struct mt76_testmode_data *td = &phy->mt76->test; 51862306a36Sopenharmony_ci u32 func_idx = en ? TX_CONT_START : TX_CONT_STOP; 51962306a36Sopenharmony_ci u8 rate_idx = td->tx_rate_idx, mode; 52062306a36Sopenharmony_ci u8 band = phy->mt76->band_idx; 52162306a36Sopenharmony_ci u16 rateval; 52262306a36Sopenharmony_ci struct mt7915_tm_rf_test req = { 52362306a36Sopenharmony_ci .action = 1, 52462306a36Sopenharmony_ci .icap_len = 120, 52562306a36Sopenharmony_ci .op.rf.func_idx = cpu_to_le32(func_idx), 52662306a36Sopenharmony_ci }; 52762306a36Sopenharmony_ci struct tm_tx_cont *tx_cont = &req.op.rf.param.tx_cont; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci tx_cont->control_ch = chandef->chan->hw_value; 53062306a36Sopenharmony_ci tx_cont->center_ch = freq1; 53162306a36Sopenharmony_ci tx_cont->tx_ant = td->tx_antenna_mask; 53262306a36Sopenharmony_ci tx_cont->band = band; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci switch (chandef->width) { 53562306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_40: 53662306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_40MHZ; 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80: 53962306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_80MHZ; 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_80P80: 54262306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_8080MHZ; 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_160: 54562306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_160MHZ; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_5: 54862306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_5MHZ; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_10: 55162306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_10MHZ; 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20: 55462306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_20MHZ; 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci case NL80211_CHAN_WIDTH_20_NOHT: 55762306a36Sopenharmony_ci tx_cont->bw = CMD_CBW_20MHZ; 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci default: 56062306a36Sopenharmony_ci return -EINVAL; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci if (!en) { 56462306a36Sopenharmony_ci req.op.rf.param.func_data = cpu_to_le32(band); 56562306a36Sopenharmony_ci goto out; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (td->tx_rate_mode <= MT76_TM_TX_MODE_OFDM) { 56962306a36Sopenharmony_ci struct ieee80211_supported_band *sband; 57062306a36Sopenharmony_ci u8 idx = rate_idx; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (chandef->chan->band == NL80211_BAND_5GHZ) 57362306a36Sopenharmony_ci sband = &phy->mt76->sband_5g.sband; 57462306a36Sopenharmony_ci else if (chandef->chan->band == NL80211_BAND_6GHZ) 57562306a36Sopenharmony_ci sband = &phy->mt76->sband_6g.sband; 57662306a36Sopenharmony_ci else 57762306a36Sopenharmony_ci sband = &phy->mt76->sband_2g.sband; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (td->tx_rate_mode == MT76_TM_TX_MODE_OFDM) 58062306a36Sopenharmony_ci idx += 4; 58162306a36Sopenharmony_ci rate_idx = sband->bitrates[idx].hw_value & 0xff; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci switch (td->tx_rate_mode) { 58562306a36Sopenharmony_ci case MT76_TM_TX_MODE_CCK: 58662306a36Sopenharmony_ci mode = MT_PHY_TYPE_CCK; 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci case MT76_TM_TX_MODE_OFDM: 58962306a36Sopenharmony_ci mode = MT_PHY_TYPE_OFDM; 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci case MT76_TM_TX_MODE_HT: 59262306a36Sopenharmony_ci mode = MT_PHY_TYPE_HT; 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci case MT76_TM_TX_MODE_VHT: 59562306a36Sopenharmony_ci mode = MT_PHY_TYPE_VHT; 59662306a36Sopenharmony_ci break; 59762306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_SU: 59862306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_SU; 59962306a36Sopenharmony_ci break; 60062306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_EXT_SU: 60162306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_EXT_SU; 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_TB: 60462306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_TB; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case MT76_TM_TX_MODE_HE_MU: 60762306a36Sopenharmony_ci mode = MT_PHY_TYPE_HE_MU; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci default: 61062306a36Sopenharmony_ci return -EINVAL; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci rateval = mode << 6 | rate_idx; 61462306a36Sopenharmony_ci tx_cont->rateval = cpu_to_le16(rateval); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ciout: 61762306a36Sopenharmony_ci if (!en) { 61862306a36Sopenharmony_ci int ret; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, 62162306a36Sopenharmony_ci sizeof(req), true); 62262306a36Sopenharmony_ci if (ret) 62362306a36Sopenharmony_ci return ret; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return mt7915_tm_rf_switch_mode(dev, RF_OPER_NORMAL); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci mt7915_tm_rf_switch_mode(dev, RF_OPER_RF_TEST); 62962306a36Sopenharmony_ci mt7915_tm_update_channel(phy); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RF_TEST), &req, 63262306a36Sopenharmony_ci sizeof(req), true); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void 63662306a36Sopenharmony_cimt7915_tm_update_params(struct mt7915_phy *phy, u32 changed) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct mt76_testmode_data *td = &phy->mt76->test; 63962306a36Sopenharmony_ci bool en = phy->mt76->test.state != MT76_TM_STATE_OFF; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (changed & BIT(TM_CHANGED_FREQ_OFFSET)) 64262306a36Sopenharmony_ci mt7915_tm_set_freq_offset(phy, en, en ? td->freq_offset : 0); 64362306a36Sopenharmony_ci if (changed & BIT(TM_CHANGED_TXPOWER)) 64462306a36Sopenharmony_ci mt7915_tm_set_tx_power(phy); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic int 64862306a36Sopenharmony_cimt7915_tm_set_state(struct mt76_phy *mphy, enum mt76_testmode_state state) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct mt76_testmode_data *td = &mphy->test; 65162306a36Sopenharmony_ci struct mt7915_phy *phy = mphy->priv; 65262306a36Sopenharmony_ci enum mt76_testmode_state prev_state = td->state; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci mphy->test.state = state; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (prev_state == MT76_TM_STATE_TX_FRAMES || 65762306a36Sopenharmony_ci state == MT76_TM_STATE_TX_FRAMES) 65862306a36Sopenharmony_ci mt7915_tm_set_tx_frames(phy, state == MT76_TM_STATE_TX_FRAMES); 65962306a36Sopenharmony_ci else if (prev_state == MT76_TM_STATE_RX_FRAMES || 66062306a36Sopenharmony_ci state == MT76_TM_STATE_RX_FRAMES) 66162306a36Sopenharmony_ci mt7915_tm_set_rx_frames(phy, state == MT76_TM_STATE_RX_FRAMES); 66262306a36Sopenharmony_ci else if (prev_state == MT76_TM_STATE_TX_CONT || 66362306a36Sopenharmony_ci state == MT76_TM_STATE_TX_CONT) 66462306a36Sopenharmony_ci mt7915_tm_set_tx_cont(phy, state == MT76_TM_STATE_TX_CONT); 66562306a36Sopenharmony_ci else if (prev_state == MT76_TM_STATE_OFF || 66662306a36Sopenharmony_ci state == MT76_TM_STATE_OFF) 66762306a36Sopenharmony_ci mt7915_tm_init(phy, !(state == MT76_TM_STATE_OFF)); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if ((state == MT76_TM_STATE_IDLE && 67062306a36Sopenharmony_ci prev_state == MT76_TM_STATE_OFF) || 67162306a36Sopenharmony_ci (state == MT76_TM_STATE_OFF && 67262306a36Sopenharmony_ci prev_state == MT76_TM_STATE_IDLE)) { 67362306a36Sopenharmony_ci u32 changed = 0; 67462306a36Sopenharmony_ci int i; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { 67762306a36Sopenharmony_ci u16 cur = tm_change_map[i]; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (td->param_set[cur / 32] & BIT(cur % 32)) 68062306a36Sopenharmony_ci changed |= BIT(i); 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci mt7915_tm_update_params(phy, changed); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci return 0; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic int 69062306a36Sopenharmony_cimt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, 69162306a36Sopenharmony_ci enum mt76_testmode_state new_state) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci struct mt76_testmode_data *td = &mphy->test; 69462306a36Sopenharmony_ci struct mt7915_phy *phy = mphy->priv; 69562306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 69662306a36Sopenharmony_ci u32 chainmask = mphy->chainmask, changed = 0; 69762306a36Sopenharmony_ci bool ext_phy = phy != &dev->phy; 69862306a36Sopenharmony_ci int i; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci BUILD_BUG_ON(NUM_TM_CHANGED >= 32); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (new_state == MT76_TM_STATE_OFF || 70362306a36Sopenharmony_ci td->state == MT76_TM_STATE_OFF) 70462306a36Sopenharmony_ci return 0; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci chainmask = ext_phy ? chainmask >> dev->chainshift : chainmask; 70762306a36Sopenharmony_ci if (td->tx_antenna_mask > chainmask) 70862306a36Sopenharmony_ci return -EINVAL; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tm_change_map); i++) { 71162306a36Sopenharmony_ci if (tb[tm_change_map[i]]) 71262306a36Sopenharmony_ci changed |= BIT(i); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci mt7915_tm_update_params(phy, changed); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int 72162306a36Sopenharmony_cimt7915_tm_dump_stats(struct mt76_phy *mphy, struct sk_buff *msg) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct mt7915_phy *phy = mphy->priv; 72462306a36Sopenharmony_ci struct mt7915_dev *dev = phy->dev; 72562306a36Sopenharmony_ci enum mt76_rxq_id q; 72662306a36Sopenharmony_ci void *rx, *rssi; 72762306a36Sopenharmony_ci u16 fcs_err; 72862306a36Sopenharmony_ci int i; 72962306a36Sopenharmony_ci u32 cnt; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci rx = nla_nest_start(msg, MT76_TM_STATS_ATTR_LAST_RX); 73262306a36Sopenharmony_ci if (!rx) 73362306a36Sopenharmony_ci return -ENOMEM; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (nla_put_s32(msg, MT76_TM_RX_ATTR_FREQ_OFFSET, phy->test.last_freq_offset)) 73662306a36Sopenharmony_ci return -ENOMEM; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_RCPI); 73962306a36Sopenharmony_ci if (!rssi) 74062306a36Sopenharmony_ci return -ENOMEM; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(phy->test.last_rcpi); i++) 74362306a36Sopenharmony_ci if (nla_put_u8(msg, i, phy->test.last_rcpi[i])) 74462306a36Sopenharmony_ci return -ENOMEM; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci nla_nest_end(msg, rssi); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_IB_RSSI); 74962306a36Sopenharmony_ci if (!rssi) 75062306a36Sopenharmony_ci return -ENOMEM; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(phy->test.last_ib_rssi); i++) 75362306a36Sopenharmony_ci if (nla_put_s8(msg, i, phy->test.last_ib_rssi[i])) 75462306a36Sopenharmony_ci return -ENOMEM; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci nla_nest_end(msg, rssi); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci rssi = nla_nest_start(msg, MT76_TM_RX_ATTR_WB_RSSI); 75962306a36Sopenharmony_ci if (!rssi) 76062306a36Sopenharmony_ci return -ENOMEM; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(phy->test.last_wb_rssi); i++) 76362306a36Sopenharmony_ci if (nla_put_s8(msg, i, phy->test.last_wb_rssi[i])) 76462306a36Sopenharmony_ci return -ENOMEM; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci nla_nest_end(msg, rssi); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (nla_put_u8(msg, MT76_TM_RX_ATTR_SNR, phy->test.last_snr)) 76962306a36Sopenharmony_ci return -ENOMEM; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci nla_nest_end(msg, rx); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci cnt = mt76_rr(dev, MT_MIB_SDR3(phy->mt76->band_idx)); 77462306a36Sopenharmony_ci fcs_err = is_mt7915(&dev->mt76) ? FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK, cnt) : 77562306a36Sopenharmony_ci FIELD_GET(MT_MIB_SDR3_FCS_ERR_MASK_MT7916, cnt); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci q = phy->mt76->band_idx ? MT_RXQ_BAND1 : MT_RXQ_MAIN; 77862306a36Sopenharmony_ci mphy->test.rx_stats.packets[q] += fcs_err; 77962306a36Sopenharmony_ci mphy->test.rx_stats.fcs_error[q] += fcs_err; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ciconst struct mt76_testmode_ops mt7915_testmode_ops = { 78562306a36Sopenharmony_ci .set_state = mt7915_tm_set_state, 78662306a36Sopenharmony_ci .set_params = mt7915_tm_set_params, 78762306a36Sopenharmony_ci .dump_stats = mt7915_tm_dump_stats, 78862306a36Sopenharmony_ci}; 789