[][MAC80211][mt76][Fix incorrect HE TX GI report]
[Description]
Change GI reporting source from static capability to rate-tuning module.
[Release-log]
N/A
Change-Id: I5a08c325fdacf9ff495cdf58319fe9d79f92edc7
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7305107
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/0005-wifi-mt76-fix-incorrect-HE-TX-GI-report.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/0005-wifi-mt76-fix-incorrect-HE-TX-GI-report.patch
new file mode 100644
index 0000000..21492d5
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/0005-wifi-mt76-fix-incorrect-HE-TX-GI-report.patch
@@ -0,0 +1,412 @@
+From c3e0f100dd0147946ba650e56c6f38cea6504265 Mon Sep 17 00:00:00 2001
+From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Date: Fri, 24 Mar 2023 18:01:27 +0800
+Subject: [PATCH 5/5] wifi: mt76: fix incorrect HE TX GI report
+
+Change GI reporting source from static capability to rate-tuning module.
+
+Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+---
+ mt76.h | 4 ++
+ mt7915/init.c | 4 ++
+ mt7915/mac.c | 54 ++++++++++++++---------
+ mt7915/main.c | 7 +++
+ mt7915/mcu.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7915/mcu.h | 39 +++++++++++++++++
+ mt7915/mt7915.h | 6 +++
+ 7 files changed, 208 insertions(+), 20 deletions(-)
+
+diff --git a/mt76.h b/mt76.h
+index 183b0fc5..11d49363 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -254,12 +254,16 @@ struct mt76_queue_ops {
+ void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q);
+ };
+
++#define MT_PHY_TYPE_LEGACY GENMASK(2, 0)
++#define MT_PHY_TYPE_EXT GENMASK(7, 3)
++
+ enum mt76_phy_type {
+ MT_PHY_TYPE_CCK,
+ MT_PHY_TYPE_OFDM,
+ MT_PHY_TYPE_HT,
+ MT_PHY_TYPE_HT_GF,
+ MT_PHY_TYPE_VHT,
++ MT_PHY_TYPE_HE_REMAP,
+ MT_PHY_TYPE_HE_SU = 8,
+ MT_PHY_TYPE_HE_EXT_SU,
+ MT_PHY_TYPE_HE_TB,
+diff --git a/mt7915/init.c b/mt7915/init.c
+index b88c3827..611a82b6 100644
+--- a/mt7915/init.c
++++ b/mt7915/init.c
+@@ -644,6 +644,8 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy)
+ struct mt76_phy *mphy = phy->mt76;
+ int ret;
+
++ INIT_LIST_HEAD(&phy->stats_list);
++ spin_lock_init(&phy->stats_lock);
+ INIT_DELAYED_WORK(&mphy->mac_work, mt7915_mac_work);
+
+ mt7915_eeprom_parse_hw_cap(dev, phy);
+@@ -1197,6 +1199,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
+ dev->phy.dev = dev;
+ dev->phy.mt76 = &dev->mt76.phy;
+ dev->mt76.phy.priv = &dev->phy;
++ INIT_LIST_HEAD(&dev->phy.stats_list);
++ spin_lock_init(&dev->phy.stats_lock);
+ INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
+ INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
+ INIT_LIST_HEAD(&dev->sta_rc_list);
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index f1fdcfde..d0520369 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -177,15 +177,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
+ rx_cur);
+ }
+
+- /*
+- * We don't support reading GI info from txs packets.
+- * For accurate tx status reporting and AQL improvement,
+- * we need to make sure that flags match so polling GI
+- * from per-sta counters directly.
+- */
+ rate = &msta->wcid.rate;
+- addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 7);
+- val = mt76_rr(dev, addr);
+
+ switch (rate->bw) {
+ case RATE_INFO_BW_160:
+@@ -202,18 +194,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
+ break;
+ }
+
+- if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
+- u8 offs = 24 + 2 * bw;
+-
+- rate->he_gi = (val & (0x3 << offs)) >> offs;
+- } else if (rate->flags &
+- (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
+- if (val & BIT(12 + bw))
+- rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+- else
+- rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
+- }
+-
+ /* get signal strength of resp frames (CTS/BA/ACK) */
+ addr = mt7915_mac_wtbl_lmac_addr(dev, idx, 30);
+ val = mt76_rr(dev, addr);
+@@ -982,6 +962,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
+ if (info & MT_TX_FREE_PAIR) {
+ struct mt7915_sta *msta;
+ struct mt76_wcid *wcid;
++ struct mt7915_phy *phy;
+ u16 idx;
+
+ idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
+@@ -991,10 +972,17 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
+ continue;
+
+ msta = container_of(wcid, struct mt7915_sta, wcid);
++ phy = msta->vif->phy;
+ spin_lock_bh(&dev->sta_poll_lock);
+ if (list_empty(&msta->poll_list))
+ list_add_tail(&msta->poll_list, &dev->sta_poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
++
++ spin_lock_bh(&phy->stats_lock);
++ if (list_empty(&msta->stats_list))
++ list_add_tail(&msta->stats_list, &phy->stats_list);
++ spin_unlock_bh(&phy->stats_lock);
++
+ continue;
+ }
+
+@@ -2016,6 +2004,27 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy)
+ phy->trb_ts = trb;
+ }
+
++static void mt7915_mac_sta_stats_work(struct mt7915_phy *phy)
++{
++ struct mt7915_sta *sta;
++ LIST_HEAD(list);
++
++ spin_lock_bh(&phy->stats_lock);
++ list_splice_init(&phy->stats_list, &list);
++
++ while (!list_empty(&list)) {
++ sta = list_first_entry(&list, struct mt7915_sta, stats_list);
++ list_del_init(&sta->stats_list);
++ spin_unlock_bh(&phy->stats_lock);
++
++ mt7915_mcu_get_tx_rate(phy, sta->wcid.idx);
++
++ spin_lock_bh(&phy->stats_lock);
++ }
++
++ spin_unlock_bh(&phy->stats_lock);
++}
++
+ void mt7915_mac_sta_rc_work(struct work_struct *work)
+ {
+ struct mt7915_dev *dev = container_of(work, struct mt7915_dev, rc_work);
+@@ -2071,6 +2080,11 @@ void mt7915_mac_work(struct work_struct *work)
+ mt7915_mac_severe_check(phy);
+ }
+
++ if (++phy->stats_work_count == 10) {
++ phy->stats_work_count = 0;
++ mt7915_mac_sta_stats_work(phy);
++ }
++
+ mutex_unlock(&mphy->dev->mutex);
+
+ mt76_tx_status_check(mphy->dev, false);
+diff --git a/mt7915/main.c b/mt7915/main.c
+index ea1d4e6a..870b7b23 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -684,6 +684,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+
+ INIT_LIST_HEAD(&msta->rc_list);
+ INIT_LIST_HEAD(&msta->poll_list);
++ INIT_LIST_HEAD(&msta->stats_list);
+ msta->vif = mvif;
+ msta->wcid.sta = 1;
+ msta->wcid.idx = idx;
+@@ -708,6 +709,7 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ {
+ struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
++ struct mt7915_phy *phy = msta->vif->phy;
+ int i;
+
+ mt7915_mcu_add_sta(dev, vif, sta, false);
+@@ -724,6 +726,11 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ if (!list_empty(&msta->rc_list))
+ list_del_init(&msta->rc_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
++
++ spin_lock_bh(&phy->stats_lock);
++ if (!list_empty(&msta->stats_list))
++ list_del_init(&msta->stats_list);
++ spin_unlock_bh(&phy->stats_lock);
+ }
+
+ static void mt7915_tx(struct ieee80211_hw *hw,
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 2a5ad033..a9f8a889 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -3752,6 +3752,120 @@ out:
+ return ret;
+ }
+
++static int
++mt7915_mcu_parse_tx_gi(struct mt7915_mcu_ra_info *mcu_rate,
++ struct rate_info *rate)
++{
++ u8 mode = mcu_rate->mode;
++ u8 gi = mcu_rate->gi;
++
++ /* Legacy drivers only use 3 bits for PHY mode. For backward
++ * compatibility, HE and newer PHY mode indices are remapped
++ * to the extended bits.
++ */
++ if (u8_get_bits(mode, MT_PHY_TYPE_LEGACY) == MT_PHY_TYPE_HE_REMAP)
++ mode = u8_get_bits(mode, MT_PHY_TYPE_EXT);
++
++ switch (mode) {
++ case MT_PHY_TYPE_CCK:
++ case MT_PHY_TYPE_OFDM:
++ break;
++ case MT_PHY_TYPE_HT:
++ case MT_PHY_TYPE_HT_GF:
++ case MT_PHY_TYPE_VHT:
++ if (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:
++ switch (mcu_rate->bw) {
++ case MCU_PHY_BW_20:
++ gi = u8_get_bits(gi, HE_GI_BW_20);
++ break;
++ case MCU_PHY_BW_40:
++ gi = u8_get_bits(gi, HE_GI_BW_40);
++ break;
++ case MCU_PHY_BW_80:
++ gi = u8_get_bits(gi, HE_GI_BW_80);
++ break;
++ case MCU_PHY_BW_160:
++ gi = u8_get_bits(gi, HE_GI_BW_160);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ if (gi > NL80211_RATE_INFO_HE_GI_3_2)
++ return -EINVAL;
++
++ rate->he_gi = gi;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++int mt7915_mcu_get_tx_rate(struct mt7915_phy *phy, u16 wcidx)
++{
++ struct ieee80211_tx_status status = {};
++ struct mt7915_dev *dev = phy->dev;
++ struct mt76_phy *mphy = phy->mt76;
++ struct mt7915_mcu_ra_info *rate;
++ struct mt76_wcid *wcid;
++ struct sk_buff *skb;
++ int ret;
++
++ struct {
++ u8 category;
++ u8 band;
++ __le16 wcidx;
++ } req = {
++ .category = MCU_GET_TX_RATE,
++ .band = mphy->band_idx,
++ .wcidx = cpu_to_le16(wcidx)
++ };
++
++ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_EXT_QUERY(GET_TX_STAT),
++ &req, sizeof(req), true, &skb);
++ if (ret)
++ return ret;
++
++ rate = (struct mt7915_mcu_ra_info *)skb->data;
++ if (le16_to_cpu(rate->wcidx) != wcidx) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ rcu_read_lock();
++ wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
++ if (!wcid) {
++ ret = -EINVAL;
++ goto unlock;
++ }
++
++ ret = mt7915_mcu_parse_tx_gi(rate, &wcid->rate);
++ if (ret)
++ goto unlock;
++
++ status.sta = wcid_to_sta(wcid);
++ if (!status.sta) {
++ ret = -EINVAL;
++ goto unlock;
++ }
++ status.rate = &wcid->rate;
++ ieee80211_tx_status_ext(mphy->hw, &status);
++unlock:
++ rcu_read_unlock();
++out:
++ dev_kfree_skb(skb);
++
++ return ret;
++}
++
+ int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct cfg80211_he_bss_color *he_bss_color)
+ {
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index 1592b5d6..3429e24f 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -152,6 +152,42 @@ struct mt7915_mcu_eeprom_info {
+ u8 data[16];
+ } __packed;
+
++enum {
++ MCU_PHY_BW_20 = 0,
++ MCU_PHY_BW_40,
++ MCU_PHY_BW_80,
++ MCU_PHY_BW_160,
++ MCU_PHY_BW_10,
++ MCU_PHY_BW_5,
++ MCU_PHY_BW_8080,
++ MCU_PHY_BW_320,
++ MCU_PHY_BW_NUM
++};
++
++#define HE_GI_BW_20 GENMASK(1, 0)
++#define HE_GI_BW_40 GENMASK(3, 2)
++#define HE_GI_BW_80 GENMASK(5, 4)
++#define HE_GI_BW_160 GENMASK(7, 6)
++
++struct mt7915_mcu_ra_info {
++ u8 category;
++ u8 rsv1;
++ __le16 num;
++ __le16 wcidx;
++
++ u8 mode;
++ u8 flags;
++ u8 stbc;
++ u8 gi;
++ u8 bw;
++ u8 ldpc;
++ u8 mcs;
++ u8 nss;
++ u8 ltf;
++
++ u8 rsv2;
++};
++
+ struct mt7915_mcu_phy_rx_info {
+ u8 category;
+ u8 rate;
+@@ -527,4 +563,7 @@ mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower)
+ return txpower;
+ }
+
++enum {
++ MCU_GET_TX_RATE = 4
++};
+ #endif
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index 376256d2..81246f37 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -131,6 +131,7 @@ struct mt7915_sta {
+
+ struct list_head poll_list;
+ struct list_head rc_list;
++ struct list_head stats_list;
+ u32 airtime_ac[8];
+
+ int ack_signal;
+@@ -280,6 +281,10 @@ struct mt7915_phy {
+ struct mib_stats mib;
+ struct mt76_channel_state state_ts;
+
++ u8 stats_work_count;
++ struct list_head stats_list;
++ spinlock_t stats_lock;
++
+ #ifdef CONFIG_NL80211_TESTMODE
+ struct {
+ u32 *reg_backup;
+@@ -553,6 +558,7 @@ int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch);
+ int mt7915_mcu_get_temperature(struct mt7915_phy *phy);
+ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state);
+ int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy);
++int mt7915_mcu_get_tx_rate(struct mt7915_phy *phy, u16 wcidx);
+ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct rate_info *rate);
+ int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
+--
+2.18.0
+