wifi: mt76: mt7996: fix incorrect interpretation of EHT MCS caps
authorBenjamin Lin <benjamin-jw.lin@mediatek.com>
Fri, 26 Jan 2024 09:09:15 +0000 (17:09 +0800)
committerFelix Fietkau <nbd@nbd.name>
Thu, 22 Feb 2024 08:55:18 +0000 (09:55 +0100)
The EHT MCS map subfield of 20 MHz-Only is not present in the EHT
capability of AP, so STA does not need to parse the subfield.
Moreover, AP should parse the subfield only if STA is 20 MHz-Only, which
can be confirmed by checking supported channel width in HE capability.

Fixes: 92aa2da9fa49 ("wifi: mt76: mt7996: enable EHT support in firmware")
Co-developed-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c

index 3ec813077dc24b52402c4060ae62d29a7f0745e9..024e73c948d8619de4477893d9d6fb896b563e71 100644 (file)
@@ -1240,6 +1240,9 @@ mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
 static void
 mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
 {
+       struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+       struct ieee80211_vif *vif = container_of((void *)msta->vif,
+                                                struct ieee80211_vif, drv_priv);
        struct ieee80211_eht_mcs_nss_supp *mcs_map;
        struct ieee80211_eht_cap_elem_fixed *elem;
        struct sta_rec_eht *eht;
@@ -1259,8 +1262,17 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
        eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info);
        eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);
 
-       if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
-               memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20));
+       if (vif->type != NL80211_IFTYPE_STATION &&
+           (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
+            (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+             IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+             IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+             IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)) == 0) {
+               memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz,
+                      sizeof(eht->mcs_map_bw20));
+               return;
+       }
+
        memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80));
        memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160));
        memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320));