| 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 |
| |