blob: ebdd4e357e3648b45dcaec66d97e78a8bf65ab1b [file] [log] [blame]
From 0c094b292cac8e88528a2eeb7ffc47125b2a63f4 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 141/193] 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.
Change-Id: I505f2882ada89770093ed0a31eb73ac4aff8b568
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 526b629..de6f2be 100644
--- a/mt76.h
+++ b/mt76.h
@@ -374,6 +374,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 02045b8..3933683 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1254,15 +1254,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]);
@@ -1310,105 +1307,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 cc0c5ac..73a04e9 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -1768,32 +1768,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 675af8c..66f6d46 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -537,42 +537,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 > 13 || 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 > 15 || 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,
@@ -623,8 +745,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.45.2