wifi: mt76: mt7996: support more options for mt7996_set_bitrate_mask()
authorHoward Hsu <howard-yh.hsu@mediatek.com>
Thu, 17 Aug 2023 08:01:53 +0000 (16:01 +0800)
committerFelix Fietkau <nbd@nbd.name>
Sat, 30 Sep 2023 18:03:04 +0000 (20:03 +0200)
Add support to configure parameters at runtime, such as mcs, gi, and
he_ltf. Note that EHT mode does not support this feature yet.

Co-developed-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c

index b0e6f51041fdda3c98fc6a8b58986f538b091255..3b56b90bb956f5f744acd2fcfa4eb5039280a8a7 100644 (file)
@@ -1624,6 +1624,132 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
                                     MCU_WM_UNI_CMD(RA), true);
 }
 
+static int
+mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta, void *data, u32 field)
+{
+       struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+       struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+       struct sta_phy *phy = data;
+       struct sta_rec_ra_fixed *ra;
+       struct sk_buff *skb;
+       struct tlv *tlv;
+
+       skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
+                                             &msta->wcid,
+                                             MT7996_STA_UPDATE_MAX_SIZE);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
+       ra = (struct sta_rec_ra_fixed *)tlv;
+
+       switch (field) {
+       case RATE_PARAM_AUTO:
+               break;
+       case RATE_PARAM_FIXED:
+       case RATE_PARAM_FIXED_MCS:
+       case RATE_PARAM_FIXED_GI:
+       case RATE_PARAM_FIXED_HE_LTF:
+               if (phy)
+                       ra->phy = *phy;
+               break;
+       default:
+               break;
+       }
+       ra->field = cpu_to_le32(field);
+
+       return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+                                    MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+}
+
+static int
+mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta)
+{
+       struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+       struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
+       struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
+       enum nl80211_band band = chandef->chan->band;
+       struct sta_phy phy = {};
+       int ret, nrates = 0;
+
+#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he)                      \
+       do {                                                                    \
+               u8 i, gi = mask->control[band]._gi;                             \
+               gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;               \
+               phy.sgi = gi;                                                   \
+               phy.he_ltf = mask->control[band].he_ltf;                        \
+               for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++) {    \
+                       if (!mask->control[band]._mcs[i])                       \
+                               continue;                                       \
+                       nrates += hweight16(mask->control[band]._mcs[i]);       \
+                       phy.mcs = ffs(mask->control[band]._mcs[i]) - 1;         \
+                       if (_ht)                                                \
+                               phy.mcs += 8 * i;                               \
+               }                                                               \
+       } while (0)
+
+       if (sta->deflink.he_cap.has_he) {
+               __sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
+       } else if (sta->deflink.vht_cap.vht_supported) {
+               __sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
+       } else if (sta->deflink.ht_cap.ht_supported) {
+               __sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
+       } else {
+               nrates = hweight32(mask->control[band].legacy);
+               phy.mcs = ffs(mask->control[band].legacy) - 1;
+       }
+#undef __sta_phy_bitrate_mask_check
+
+       /* fall back to auto rate control */
+       if (mask->control[band].gi == NL80211_TXRATE_DEFAULT_GI &&
+           mask->control[band].he_gi == GENMASK(7, 0) &&
+           mask->control[band].he_ltf == GENMASK(7, 0) &&
+           nrates != 1)
+               return 0;
+
+       /* fixed single rate */
+       if (nrates == 1) {
+               ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy,
+                                                RATE_PARAM_FIXED_MCS);
+               if (ret)
+                       return ret;
+       }
+
+       /* fixed GI */
+       if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
+           mask->control[band].he_gi != GENMASK(7, 0)) {
+               struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+               u32 addr;
+
+               /* firmware updates only TXCMD but doesn't take WTBL into
+                * account, so driver should update here to reflect the
+                * actual txrate hardware sends out.
+                */
+               addr = mt7996_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
+               if (sta->deflink.he_cap.has_he)
+                       mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
+               else
+                       mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
+
+               ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy,
+                                                RATE_PARAM_FIXED_GI);
+               if (ret)
+                       return ret;
+       }
+
+       /* fixed HE_LTF */
+       if (mask->control[band].he_ltf != GENMASK(7, 0)) {
+               ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy,
+                                                RATE_PARAM_FIXED_HE_LTF);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static void
 mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
                             struct ieee80211_vif *vif, struct ieee80211_sta *sta)
@@ -1733,6 +1859,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
        struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
        struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
        struct sk_buff *skb;
+       int ret;
 
        skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
                                              &msta->wcid,
@@ -1752,8 +1879,12 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
         */
        mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
 
-       return mt76_mcu_skb_send_msg(&dev->mt76, skb,
-                                    MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+       ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+                                   MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+       if (ret)
+               return ret;
+
+       return mt7996_mcu_add_rate_ctrl_fixed(dev, vif, sta);
 }
 
 static int