blob: 90b53eac94fb6f37375a83f1b482bef29dfc59be [file] [log] [blame]
From 8027e94f1564089d719a6fb0eab7d29bb2981bf0 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Tue, 11 May 2021 16:24:09 +0800
Subject: [PATCH 1110/1112] mt76: mt7915: implement aid support in testmode
Add support for virtual stations in mt7915 testmode.
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
.../wireless/mediatek/mt76/mt76_connac_mcu.c | 5 +
.../net/wireless/mediatek/mt76/mt7915/mac.c | 25 +-
.../wireless/mediatek/mt76/mt7915/testmode.c | 231 +++++++++++++++---
3 files changed, 216 insertions(+), 45 deletions(-)
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
index eac096c..a361ab6 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -389,6 +389,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct sk_buff *skb,
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_MONITOR:
if (vif->p2p)
conn_type = CONNECTION_P2P_GC;
else
@@ -577,6 +578,10 @@ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev,
wtbl_tlv, sta_wtbl);
spe = (struct wtbl_spe *)tlv;
spe->spe_idx = 24;
+
+ /* check */
+ if (vif->type == NL80211_IFTYPE_MONITOR)
+ rx->rca1 = 0;
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_generic_tlv);
diff --git a/mt7915/mac.c b/mt7915/mac.c
index fb42446..2ad4cb1 100644
--- a/mt7915/mac.c
+++ b/mt7915/mac.c
@@ -906,16 +906,28 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
{
#ifdef CONFIG_NL80211_TESTMODE
struct mt76_testmode_data *td = &phy->mt76->test;
+ struct mt76_testmode_sta_data *sd = &td->sd;
const struct ieee80211_rate *r;
- u8 bw, mode, nss = td->tx_rate_nss;
- u8 rate_idx = td->tx_rate_idx;
+ u8 bw, mode, nss, rate_idx;
u16 rateval = 0;
u32 val;
bool cck = false;
int band;
- if (skb != phy->mt76->test.tx_skb)
- return;
+ if (mt76_testmode_has_sta(phy->mt76)) {
+ struct mt76_testmode_sta *tm_sta;
+ int i;
+
+ mt76_testmode_for_each_sta(phy->mt76, i, tm_sta) {
+ if (tm_sta->tx_skb == skb) {
+ sd = &tm_sta->sd;
+ break;
+ }
+ }
+ }
+
+ nss = sd->tx_rate_nss;
+ rate_idx = sd->tx_rate_idx;
switch (td->tx_rate_mode) {
case MT76_TM_TX_MODE_HT:
@@ -1005,7 +1017,7 @@ mt7915_mac_write_txwi_tm(struct mt7915_phy *phy, __le32 *txwi,
if (mode >= MT_PHY_TYPE_HE_SU)
val |= FIELD_PREP(MT_TXD6_HELTF, td->tx_ltf);
- if (td->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU))
+ if (sd->tx_rate_ldpc || (bw > 0 && mode >= MT_PHY_TYPE_HE_SU))
val |= MT_TXD6_LDPC;
txwi[1] &= ~cpu_to_le32(MT_TXD1_VTA);
@@ -1474,6 +1486,9 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
continue;
msta = container_of(wcid, struct mt7915_sta, wcid);
+ if (mt76_testmode_enabled(msta->vif->phy->mt76))
+ continue;
+
spin_lock_bh(&dev->sta_poll_lock);
if (list_empty(&msta->poll_list))
list_add_tail(&msta->poll_list, &dev->sta_poll_list);
diff --git a/mt7915/testmode.c b/mt7915/testmode.c
index 054829e..29c173d 100644
--- a/mt7915/testmode.c
+++ b/mt7915/testmode.c
@@ -11,6 +11,7 @@ enum {
TM_CHANGED_FREQ_OFFSET,
TM_CHANGED_CFG,
TM_CHANGED_OFF_CH_SCAN_CH,
+ TM_CHANGED_AID,
/* must be last */
NUM_TM_CHANGED
@@ -21,6 +22,7 @@ static const u8 tm_change_map[] = {
[TM_CHANGED_FREQ_OFFSET] = MT76_TM_ATTR_FREQ_OFFSET,
[TM_CHANGED_CFG] = MT76_TM_ATTR_CFG,
[TM_CHANGED_OFF_CH_SCAN_CH] = MT76_TM_ATTR_OFF_CH_SCAN_CH,
+ [TM_CHANGED_AID] = MT76_TM_ATTR_AID,
};
struct reg_band {
@@ -142,18 +144,33 @@ mt7915_tm_set_trx(struct mt7915_phy *phy, int type, bool en)
}
static int
-mt7915_tm_clean_hwq(struct mt7915_phy *phy, u8 wcid)
+mt7915_tm_clean_hwq(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct mt7915_tm_cmd req = {
.testmode_en = 1,
.param_idx = MCU_ATE_CLEAN_TXQUEUE,
- .param.clean.wcid = wcid,
.param.clean.band = phy != &dev->phy,
};
+ struct mt76_testmode_sta *tm_sta;
+ int ret, i;
- return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL), &req,
- sizeof(req), false);
+ if (!mt76_testmode_has_sta(phy->mt76)) {
+ req.param.clean.wcid = dev->mt76.global_wcid.idx;
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL),
+ &req, sizeof(req), false);
+ }
+
+ mt76_testmode_for_each_sta(phy->mt76, i, tm_sta) {
+ req.param.clean.wcid = phy->mt76->test.tm_wcid[i]->idx;
+ ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(ATE_CTRL),
+ &req, sizeof(req), false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int
@@ -530,27 +547,109 @@ mt7915_tm_reg_backup_restore(struct mt7915_phy *phy)
}
}
+static int
+mt7915_tm_sta_add(struct mt7915_phy *phy, u8 aid,
+ struct mt76_testmode_sta_data *sd)
+{
+ struct mt76_testmode_data *td = &phy->mt76->test;
+ struct mt76_testmode_sta *tm_sta;
+
+ if (!aid)
+ return 0;
+
+ if (!td->tm_wcid[aid]) {
+ struct ieee80211_vif *vif = phy->monitor_vif;
+ struct ieee80211_sband_iftype_data *data;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_sta *sta;
+ struct mt7915_sta *msta;
+ int ret;
+
+ sta = kzalloc(sizeof(*sta) + phy->mt76->hw->sta_data_size +
+ sizeof(*tm_sta), GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+
+ if (phy->mt76->chandef.chan->band == NL80211_BAND_5GHZ) {
+ sband = &phy->mt76->sband_5g.sband;
+ data = phy->iftype[NL80211_BAND_5GHZ];
+ } else {
+ sband = &phy->mt76->sband_2g.sband;
+ data = phy->iftype[NL80211_BAND_2GHZ];
+ }
+
+ ether_addr_copy(sta->addr, phy->mt76->macaddr);
+ sta->addr[0] += aid * 4;
+ memcpy(&sta->ht_cap, &sband->ht_cap, sizeof(sta->ht_cap));
+ memcpy(&sta->vht_cap, &sband->vht_cap, sizeof(sta->vht_cap));
+ memcpy(&sta->he_cap, &data[NL80211_IFTYPE_STATION].he_cap,
+ sizeof(sta->he_cap));
+ sta->aid = aid;
+ sta->wme = 1;
+
+ ret = mt7915_mac_sta_add(&phy->dev->mt76, vif, sta);
+ if (ret) {
+ kfree(sta);
+ return ret;
+ }
+
+ msta = (struct mt7915_sta *)sta->drv_priv;
+ td->tm_wcid[aid] = &msta->wcid;
+ td->tm_sta_mask |= BIT(aid - 1);
+ }
+
+ tm_sta = mt76_testmode_aid_get_sta(phy->mt76, aid);
+ memcpy(&tm_sta->sd, sd, sizeof(tm_sta->sd));
+
+ return 0;
+}
+
static void
-mt7915_tm_init(struct mt7915_phy *phy, bool en)
+mt7915_tm_sta_remove(struct mt7915_phy *phy, u8 aid)
{
+ struct mt76_testmode_data *td = &phy->mt76->test;
+ struct mt76_wcid *wcid = td->tm_wcid[aid];
struct mt7915_dev *dev = phy->dev;
+ struct ieee80211_sta *sta = wcid_to_sta(wcid);
- if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
+ mt7915_mac_sta_remove(&dev->mt76, phy->monitor_vif, sta);
+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, wcid->idx);
+
+ kfree(sta);
+ td->tm_wcid[aid] = NULL;
+ td->tm_sta_mask &= ~BIT(aid - 1);
+}
+
+static void
+mt7915_tm_sta_remove_all(struct mt7915_phy *phy)
+{
+ int i;
+
+ if (!mt76_testmode_has_sta(phy->mt76))
return;
- mt7915_mcu_set_sku_en(phy, !en);
+ for (i = 1; i < ARRAY_SIZE(phy->mt76->test.tm_wcid); i++) {
+ if (phy->mt76->test.tm_wcid[i])
+ mt7915_tm_sta_remove(phy, i);
+ }
+}
- mt7915_tm_mode_ctrl(dev, en);
- mt7915_tm_reg_backup_restore(phy);
- mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en);
+static int
+mt7915_tm_set_sta(struct mt7915_phy *phy)
+{
+ struct mt76_testmode_data *td = &phy->mt76->test;
- mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en);
- mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en);
+ if (!td->aid) {
+ mt7915_tm_sta_remove_all(phy);
+ return 0;
+ }
- phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
+ if (td->tx_count == 0) {
+ mt7915_tm_sta_remove(phy, td->aid);
+ return 0;
+ }
- if (!en)
- mt7915_tm_set_tam_arb(phy, en, 0);
+ return mt7915_tm_sta_add(phy, td->aid, &td->sd);
}
static void
@@ -563,22 +662,48 @@ mt7915_tm_update_channel(struct mt7915_phy *phy)
mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD(SET_RX_PATH));
}
+static bool
+mt7915_tm_check_skb(struct mt7915_phy *phy)
+{
+ struct mt76_testmode_data *td = &phy->mt76->test;
+ struct ieee80211_tx_info *info;
+
+ if (!mt76_testmode_has_sta(phy->mt76)) {
+ if (!td->tx_skb)
+ return false;
+
+ info = IEEE80211_SKB_CB(td->tx_skb);
+ info->control.vif = phy->monitor_vif;
+ } else {
+ struct mt76_testmode_sta *tm_sta;
+ int i;
+
+ mt76_testmode_for_each_sta(phy->mt76, i, tm_sta) {
+ if (!tm_sta->tx_skb)
+ return false;
+
+ info = IEEE80211_SKB_CB(tm_sta->tx_skb);
+ info->control.vif = phy->monitor_vif;
+ }
+ }
+
+ return true;
+}
+
static void
mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
{
static const u8 spe_idx_map[] = {0, 0, 1, 0, 3, 2, 4, 0,
9, 8, 6, 10, 16, 12, 18, 0};
struct mt76_testmode_data *td = &phy->mt76->test;
- struct mt7915_dev *dev = phy->dev;
- struct ieee80211_tx_info *info;
- u8 duty_cycle = td->tx_duty_cycle;
- u32 tx_time = td->tx_time;
- u32 ipg = td->tx_ipg;
mt7915_tm_set_trx(phy, TM_MAC_RX_RXV, false);
- mt7915_tm_clean_hwq(phy, dev->mt76.global_wcid.idx);
+ mt7915_tm_set_trx(phy, TM_MAC_TX, false);
if (en) {
+ u32 tx_time = td->tx_time, ipg = td->tx_ipg;
+ u8 duty_cycle = td->tx_duty_cycle;
+
mt7915_tm_update_channel(phy);
if (td->tx_spe_idx) {
@@ -586,30 +711,29 @@ mt7915_tm_set_tx_frames(struct mt7915_phy *phy, bool en)
} else {
phy->test.spe_idx = spe_idx_map[td->tx_antenna_mask];
}
- }
- mt7915_tm_set_tam_arb(phy, en,
- td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU);
-
- /* if all three params are set, duty_cycle will be ignored */
- if (duty_cycle && tx_time && !ipg) {
- ipg = tx_time * 100 / duty_cycle - tx_time;
- } else if (duty_cycle && !tx_time && ipg) {
- if (duty_cycle < 100)
- tx_time = duty_cycle * ipg / (100 - duty_cycle);
- }
+ /* if all three params are set, duty_cycle will be ignored */
+ if (duty_cycle && tx_time && !ipg) {
+ ipg = tx_time * 100 / duty_cycle - tx_time;
+ } else if (duty_cycle && !tx_time && ipg) {
+ if (duty_cycle < 100)
+ tx_time = duty_cycle * ipg / (100 - duty_cycle);
+ }
- mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode);
- mt7915_tm_set_tx_len(phy, tx_time);
+ mt7915_tm_set_ipg_params(phy, ipg, td->tx_rate_mode);
+ mt7915_tm_set_tx_len(phy, tx_time);
- if (ipg)
- td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2;
+ if (ipg)
+ td->tx_queued_limit = MT76_TM_TIMEOUT * 1000000 / ipg / 2;
- if (!en || !td->tx_skb)
- return;
+ if (!mt7915_tm_check_skb(phy))
+ return;
+ } else {
+ mt7915_tm_clean_hwq(phy);
+ }
- info = IEEE80211_SKB_CB(td->tx_skb);
- info->control.vif = phy->monitor_vif;
+ mt7915_tm_set_tam_arb(phy, en,
+ td->tx_rate_mode == MT76_TM_TX_MODE_HE_MU);
mt7915_tm_set_trx(phy, TM_MAC_TX, en);
}
@@ -811,6 +935,31 @@ out:
sizeof(req), true);
}
+static void
+mt7915_tm_init(struct mt7915_phy *phy, bool en)
+{
+ struct mt7915_dev *dev = phy->dev;
+
+ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
+ return;
+
+ mt7915_mcu_set_sku_en(phy, !en);
+
+ mt7915_tm_mode_ctrl(dev, en);
+ mt7915_tm_reg_backup_restore(phy);
+ mt7915_tm_set_trx(phy, TM_MAC_TXRX, !en);
+
+ mt7915_mcu_add_bss_info(phy, phy->monitor_vif, en);
+ mt7915_mcu_add_sta(dev, phy->monitor_vif, NULL, en);
+
+ phy->mt76->test.flag |= MT_TM_FW_RX_COUNT;
+
+ if (!en) {
+ mt7915_tm_set_tam_arb(phy, en, 0);
+ mt7915_tm_sta_remove_all(phy);
+ }
+}
+
static void
mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
{
@@ -825,6 +974,8 @@ mt7915_tm_update_params(struct mt7915_phy *phy, u32 changed)
mt7915_tm_set_cfg(phy);
if (changed & BIT(TM_CHANGED_OFF_CH_SCAN_CH))
mt7915_tm_set_off_channel_scan(phy);
+ if (changed & BIT(TM_CHANGED_AID))
+ mt7915_tm_set_sta(phy);
}
static int
--
2.25.1