blob: 343129f95650425fcdb6040d7e41e15b400bbbf0 [file] [log] [blame]
From 06c0ba03cc9ed39bee42b10a1e22f9aceeb57ecd Mon Sep 17 00:00:00 2001
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Date: Fri, 7 Jun 2024 10:44:45 +0800
Subject: [PATCH 153/199] mtk: mt76: mt7996: update TX/RX rates via MCU command
Update TX/RX rates via MCU command to address following issues:
1. TX rate was originally updated via TXS. However in MLO connection, WCID from TXS may not represent the actually used link.
2. RX rate was originally updated via RXD. However, there is no RXD when HW path is taken.
Original TX-rate update via TXS is removed.
Still, RX-rate update via RXD is not removed, because mac80211 requires driver to provide such information for each received frame.
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
---
mt76.h | 1 +
mt7996/mac.c | 117 ++++++----------------------------------
mt7996/main.c | 28 ++++------
mt7996/mcu.c | 146 +++++++++++++++++++++++++++++++++++++++++++++-----
4 files changed, 161 insertions(+), 131 deletions(-)
diff --git a/mt76.h b/mt76.h
index f544814e..a0fc8b1a 100644
--- a/mt76.h
+++ b/mt76.h
@@ -370,6 +370,7 @@ struct mt76_wcid {
int inactive_count;
struct rate_info rate;
+ struct rate_info rx_rate;
unsigned long ampdu_state;
u16 idx;
diff --git a/mt7996/mac.c b/mt7996/mac.c
index 020203ec..484b679b 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1242,15 +1242,12 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
int pid, __le32 *txs_data)
{
struct mt76_sta_stats *stats = &wcid->stats;
- struct ieee80211_supported_band *sband;
struct mt76_dev *mdev = &dev->mt76;
- struct mt76_phy *mphy;
struct ieee80211_tx_info *info;
struct sk_buff_head list;
- struct rate_info rate = {};
struct sk_buff *skb = NULL;
- bool cck = false;
- u32 txrate, txs, mode, stbc;
+ u32 txrate, txs;
+ u8 mode, bw, mcs, nss;
txs = le32_to_cpu(txs_data[0]);
@@ -1298,105 +1295,23 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
}
txrate = FIELD_GET(MT_TXS0_TX_RATE, txs);
-
- rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
- rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
- stbc = le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC);
-
- if (stbc && rate.nss > 1)
- rate.nss >>= 1;
-
- if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss))
- stats->tx_nss[rate.nss - 1]++;
- if (rate.mcs < ARRAY_SIZE(stats->tx_mcs))
- stats->tx_mcs[rate.mcs]++;
+ bw = FIELD_GET(MT_TXS0_BW, txs);
mode = FIELD_GET(MT_TX_RATE_MODE, txrate);
- switch (mode) {
- case MT_PHY_TYPE_CCK:
- cck = true;
- fallthrough;
- case MT_PHY_TYPE_OFDM:
- mphy = mt76_dev_phy(mdev, wcid->phy_idx);
-
- if (mphy->chandef.chan->band == NL80211_BAND_5GHZ)
- sband = &mphy->sband_5g.sband;
- else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ)
- sband = &mphy->sband_6g.sband;
- else
- sband = &mphy->sband_2g.sband;
-
- rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck);
- rate.legacy = sband->bitrates[rate.mcs].bitrate;
- break;
- case MT_PHY_TYPE_HT:
- case MT_PHY_TYPE_HT_GF:
- if (rate.mcs > 31)
- goto out;
-
- rate.flags = RATE_INFO_FLAGS_MCS;
- if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
- rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
- break;
- case MT_PHY_TYPE_VHT:
- if (rate.mcs > 9)
- goto out;
-
- rate.flags = RATE_INFO_FLAGS_VHT_MCS;
- if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
- rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
- break;
- case MT_PHY_TYPE_HE_SU:
- case MT_PHY_TYPE_HE_EXT_SU:
- case MT_PHY_TYPE_HE_TB:
- case MT_PHY_TYPE_HE_MU:
- if (rate.mcs > 11)
- goto out;
-
- rate.he_gi = wcid->rate.he_gi;
- rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate);
- rate.flags = RATE_INFO_FLAGS_HE_MCS;
- break;
- case MT_PHY_TYPE_EHT_SU:
- case MT_PHY_TYPE_EHT_TRIG:
- case MT_PHY_TYPE_EHT_MU:
- if (rate.mcs > 13)
- goto out;
-
- rate.eht_gi = wcid->rate.eht_gi;
- rate.flags = RATE_INFO_FLAGS_EHT_MCS;
- break;
- default:
- goto out;
- }
-
- stats->tx_mode[mode]++;
+ mcs = FIELD_GET(MT_TX_RATE_IDX, txrate);
+ nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1;
+ if (le32_get_bits(txs_data[3], MT_TXS3_RATE_STBC) && nss > 1)
+ nss >>= 1;
+
+ if (nss - 1 < ARRAY_SIZE(stats->tx_nss))
+ stats->tx_nss[nss - 1]++;
+ if (mcs < ARRAY_SIZE(stats->tx_mcs))
+ stats->tx_mcs[mcs]++;
+ if (mode < ARRAY_SIZE(stats->tx_mode))
+ stats->tx_mode[mode]++;
+ if (bw < ARRAY_SIZE(stats->tx_bw))
+ stats->tx_bw[bw]++;
- switch (FIELD_GET(MT_TXS0_BW, txs)) {
- case IEEE80211_STA_RX_BW_320:
- rate.bw = RATE_INFO_BW_320;
- stats->tx_bw[4]++;
- break;
- case IEEE80211_STA_RX_BW_160:
- rate.bw = RATE_INFO_BW_160;
- stats->tx_bw[3]++;
- break;
- case IEEE80211_STA_RX_BW_80:
- rate.bw = RATE_INFO_BW_80;
- stats->tx_bw[2]++;
- break;
- case IEEE80211_STA_RX_BW_40:
- rate.bw = RATE_INFO_BW_40;
- stats->tx_bw[1]++;
- break;
- default:
- rate.bw = RATE_INFO_BW_20;
- stats->tx_bw[0]++;
- break;
- }
- wcid->rate = rate;
-
-out:
if (skb)
mt76_tx_status_skb_done(mdev, skb, &list);
mt76_tx_status_unlock(mdev, &list);
diff --git a/mt7996/main.c b/mt7996/main.c
index 19a1c7b3..fa60b889 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -1765,32 +1765,24 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_link_sta *mlink;
- struct rate_info *txrate;
+ struct rate_info *rate;
- /* TODO: support per-link rate report */
mutex_lock(&dev->mt76.mutex);
mlink = mlink_dereference_protected(msta, msta->pri_link);
if (!mlink)
goto out;
- txrate = &mlink->wcid.rate;
- if (txrate->legacy || txrate->flags) {
- if (txrate->legacy) {
- sinfo->txrate.legacy = txrate->legacy;
- } else {
- sinfo->txrate.mcs = txrate->mcs;
- sinfo->txrate.nss = txrate->nss;
- sinfo->txrate.bw = txrate->bw;
- sinfo->txrate.he_gi = txrate->he_gi;
- sinfo->txrate.he_dcm = txrate->he_dcm;
- sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
- sinfo->txrate.eht_gi = txrate->eht_gi;
- }
- sinfo->txrate.flags = txrate->flags;
+ rate = &mlink->wcid.rate;
+ if (rate->legacy || rate->flags) {
+ sinfo->txrate = *rate;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
}
- sinfo->txrate.flags = txrate->flags;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+
+ rate = &mlink->wcid.rx_rate;
+ if (rate->legacy || rate->flags) {
+ sinfo->rxrate = *rate;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
+ }
sinfo->tx_failed = mlink->wcid.stats.tx_failed;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index 51f15928..8fd9d450 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -532,42 +532,164 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
}
static int
-mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate)
+mt7996_mcu_update_rate(struct rate_info *rate, struct ieee80211_supported_band *sband,
+ u8 mode, u8 bw, u8 mcs, u8 nss, u8 stbc, u8 gi)
{
- switch (mcu_rate->tx_mode) {
+ struct rate_info tmp_rate = {};
+
+ tmp_rate.mcs = mcs;
+ tmp_rate.nss = (stbc && nss > 1) ? nss / 2 : nss;
+
+ switch (mode) {
case MT_PHY_TYPE_CCK:
case MT_PHY_TYPE_OFDM:
+ if (mcs >= sband->n_bitrates)
+ return -EINVAL;
+
+ tmp_rate.legacy = sband->bitrates[mcs].bitrate;
break;
case MT_PHY_TYPE_HT:
case MT_PHY_TYPE_HT_GF:
+ if (mcs > 31)
+ return -EINVAL;
+
+ tmp_rate.flags |= RATE_INFO_FLAGS_MCS;
+ if (gi)
+ tmp_rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
+ break;
case MT_PHY_TYPE_VHT:
- if (mcu_rate->tx_gi)
- rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
- else
- rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
+ if (mcs > 9)
+ return -EINVAL;
+
+ tmp_rate.flags |= RATE_INFO_FLAGS_VHT_MCS;
+ if (gi)
+ tmp_rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case MT_PHY_TYPE_HE_SU:
case MT_PHY_TYPE_HE_EXT_SU:
case MT_PHY_TYPE_HE_TB:
case MT_PHY_TYPE_HE_MU:
- if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2)
+ tmp_rate.mcs = mcs & GENMASK(3, 0);
+ if (tmp_rate.mcs > 11 || gi > NL80211_RATE_INFO_HE_GI_3_2)
return -EINVAL;
- rate->he_gi = mcu_rate->tx_gi;
+
+ tmp_rate.flags |= RATE_INFO_FLAGS_HE_MCS;
+ tmp_rate.he_gi = gi;
+ tmp_rate.he_dcm = mcs & MT_PRXV_TX_DCM;
break;
case MT_PHY_TYPE_EHT_SU:
case MT_PHY_TYPE_EHT_TRIG:
case MT_PHY_TYPE_EHT_MU:
- if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2)
+ tmp_rate.mcs = mcs & GENMASK(3, 0);
+ if (tmp_rate.mcs > 13 || gi > NL80211_RATE_INFO_EHT_GI_3_2)
return -EINVAL;
- rate->eht_gi = mcu_rate->tx_gi;
+
+ tmp_rate.flags |= RATE_INFO_FLAGS_EHT_MCS;
+ tmp_rate.eht_gi = gi;
break;
default:
return -EINVAL;
}
+ switch (bw) {
+ case IEEE80211_STA_RX_BW_20:
+ tmp_rate.bw = RATE_INFO_BW_20;
+ break;
+ case IEEE80211_STA_RX_BW_40:
+ tmp_rate.bw = RATE_INFO_BW_40;
+ break;
+ case IEEE80211_STA_RX_BW_80:
+ tmp_rate.bw = RATE_INFO_BW_80;
+ break;
+ case IEEE80211_STA_RX_BW_160:
+ tmp_rate.bw = RATE_INFO_BW_160;
+ break;
+ case IEEE80211_STA_RX_BW_320:
+ tmp_rate.bw = RATE_INFO_BW_320;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (mode == MT_PHY_TYPE_HE_EXT_SU && mcs & MT_PRXV_TX_ER_SU_106T) {
+ tmp_rate.bw = RATE_INFO_BW_HE_RU;
+ tmp_rate.he_ru_alloc = NL80211_RATE_INFO_HE_RU_ALLOC_106;
+ }
+ *rate = tmp_rate;
+
return 0;
}
+static int
+mt7996_mcu_update_trx_rates(struct mt76_wcid *wcid, struct all_sta_trx_rate *mcu_rate)
+{
+ struct mt7996_link_sta *mlink = container_of(wcid, struct mt7996_link_sta, wcid);
+ struct mt76_dev *dev = &mlink->sta->vif->dev->mt76;
+ struct mt76_phy *phy = mt76_dev_phy(dev, wcid->phy_idx);
+ struct ieee80211_supported_band *sband = NULL;
+ bool cck;
+ int ret;
+
+ /* TX rate */
+ cck = false;
+
+ switch (mcu_rate->tx_mode) {
+ case MT_PHY_TYPE_CCK:
+ cck = true;
+ fallthrough;
+ case MT_PHY_TYPE_OFDM:
+ if (phy->chandef.chan->band == NL80211_BAND_2GHZ) {
+ sband = &phy->sband_2g.sband;
+ if (!cck)
+ mcu_rate->tx_mcs += 4;
+ } else if (phy->chandef.chan->band == NL80211_BAND_5GHZ)
+ sband = &phy->sband_5g.sband;
+ else
+ sband = &phy->sband_6g.sband;
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ mcu_rate->tx_mcs += ((mcu_rate->tx_nss - 1) << 3);
+ break;
+ default:
+ break;
+ }
+
+ ret = mt7996_mcu_update_rate(&wcid->rate, sband, mcu_rate->tx_mode,
+ mcu_rate->tx_bw, mcu_rate->tx_mcs,
+ mcu_rate->tx_nss, mcu_rate->tx_stbc,
+ mcu_rate->tx_gi);
+ if (ret)
+ return ret;
+
+ /* RX rate */
+ cck = false;
+
+ switch (mcu_rate->rx_mode) {
+ case MT_PHY_TYPE_CCK:
+ cck = true;
+ fallthrough;
+ case MT_PHY_TYPE_OFDM:
+ if (phy->chandef.chan->band == NL80211_BAND_2GHZ)
+ sband = &phy->sband_2g.sband;
+ else if (phy->chandef.chan->band == NL80211_BAND_5GHZ)
+ sband = &phy->sband_5g.sband;
+ else
+ sband = &phy->sband_6g.sband;
+
+ mcu_rate->rx_rate = mt76_get_rate(dev, sband, mcu_rate->rx_rate, cck);
+ break;
+ default:
+ break;
+ }
+
+ ret = mt7996_mcu_update_rate(&wcid->rx_rate, sband, mcu_rate->rx_mode,
+ mcu_rate->rx_bw, mcu_rate->rx_rate,
+ mcu_rate->rx_nsts + 1, mcu_rate->rx_stbc,
+ mcu_rate->rx_gi);
+ return ret;
+}
+
static inline void __mt7996_stat_to_netdev(struct mt76_phy *mphy,
struct mt76_wcid *wcid,
u32 tx_bytes, u32 rx_bytes,
@@ -618,8 +740,8 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
if (!wcid)
break;
- if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i]))
- dev_err(dev->mt76.dev, "Failed to update TX GI\n");
+ if (mt7996_mcu_update_trx_rates(wcid, &res->rate[i]))
+ dev_err(dev->mt76.dev, "Failed to update TX/RX rates.\n");
break;
case UNI_ALL_STA_TXRX_ADM_STAT:
wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx);
--
2.18.0