mt76: mt7915: rework .set_bitrate_mask() to support more options
authorRyder Lee <ryder.lee@mediatek.com>
Wed, 20 Oct 2021 20:57:55 +0000 (04:57 +0800)
committerFelix Fietkau <nbd@nbd.name>
Sat, 23 Oct 2021 11:23:44 +0000 (13:23 +0200)
With this patch, driver can support single rate, (HE)GI and HE_LTF
configuration through .set_bitrate_mask().

Tested-by: MeiChia Chiu <meichia.chiu@mediatek.com>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/main.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h

index 6fc12e45a0129835d3942a729efb67cb94b51018..5fcf35f2d9fbe42760c7ff28b53c3a96f68d62f8 100644 (file)
@@ -89,7 +89,7 @@ bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask)
                         0, 5000);
 }
 
-static u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw)
+u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw)
 {
        mt76_wr(dev, MT_WTBLON_TOP_WDUCR,
                FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7)));
index ca44f68c54343ccba0646796c78796aead7e1ae5..057ab27b70832a427d03da2b8537adc0413fd6db 100644 (file)
@@ -172,6 +172,9 @@ static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) {
+               mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI;
+               mvif->bitrate_mask.control[i].he_gi = GENMASK(7, 0);
+               mvif->bitrate_mask.control[i].he_ltf = GENMASK(7, 0);
                mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0);
                memset(mvif->bitrate_mask.control[i].ht_mcs, GENMASK(7, 0),
                       sizeof(mvif->bitrate_mask.control[i].ht_mcs));
@@ -994,7 +997,6 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
 {
        struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
        struct mt7915_dev *dev = msta->vif->phy->dev;
-       struct ieee80211_hw *hw = msta->vif->phy->mt76->hw;
        u32 *changed = data;
 
        spin_lock_bh(&dev->sta_poll_lock);
@@ -1002,8 +1004,6 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
        if (list_empty(&msta->rc_list))
                list_add_tail(&msta->rc_list, &dev->sta_rc_list);
        spin_unlock_bh(&dev->sta_poll_lock);
-
-       ieee80211_queue_work(hw, &dev->rc_work);
 }
 
 static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
@@ -1011,7 +1011,11 @@ static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
                                 struct ieee80211_sta *sta,
                                 u32 changed)
 {
+       struct mt7915_phy *phy = mt7915_hw_phy(hw);
+       struct mt7915_dev *dev = phy->dev;
+
        mt7915_sta_rc_work(&changed, sta);
+       ieee80211_queue_work(hw, &dev->rc_work);
 }
 
 static int
@@ -1019,22 +1023,22 @@ mt7915_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        const struct cfg80211_bitrate_mask *mask)
 {
        struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
-       enum nl80211_band band = mvif->phy->mt76->chandef.chan->band;
-       u32 changed;
-
-       if (mask->control[band].gi == NL80211_TXRATE_FORCE_LGI)
-               return -EINVAL;
+       struct mt7915_phy *phy = mt7915_hw_phy(hw);
+       struct mt7915_dev *dev = phy->dev;
+       u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
 
-       changed = IEEE80211_RC_SUPP_RATES_CHANGED;
        mvif->bitrate_mask = *mask;
 
-       /* Update firmware rate control to add a boundary on top of table
-        * to limit the rate selection for each peer, so when set bitrates
-        * vht-mcs-5 1:9, which actually means nss = 1 mcs = 0~9. This only
-        * applies to data frames as for the other mgmt, mcast, bcast still
-        * use legacy rates as it is.
+       /* if multiple rates across different preambles are given we can
+        * reconfigure this info with all peers using sta_rec command with
+        * the below exception cases.
+        * - single rate : if a rate is passed along with different preambles,
+        * we select the highest one as fixed rate. i.e VHT MCS for VHT peers.
+        * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT
+        * then multiple MCS setting (MCS 4,5,6) is not supported.
         */
        ieee80211_iterate_stations_atomic(hw, mt7915_sta_rc_work, &changed);
+       ieee80211_queue_work(hw, &dev->rc_work);
 
        return 0;
 }
index 27b741e38920c54fbeeff2598471d35f2c068692..aa7964788a1c4ecab5a8aded379893c1df946849 100644 (file)
@@ -2050,6 +2050,128 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
        bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
 }
 
+int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta,
+                                  void *data, u32 field)
+{
+       struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+       struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+       struct sta_phy *phy = data;
+       struct sta_rec_ra_fixed *ra;
+       struct sk_buff *skb;
+       struct tlv *tlv;
+       int len = sizeof(struct sta_req_hdr) + sizeof(*ra);
+
+       skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       tlv = mt7915_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_MCS:
+       case RATE_PARAM_FIXED_GI:
+       case RATE_PARAM_FIXED_HE_LTF:
+               ra->phy = *phy;
+               break;
+       default:
+               break;
+       }
+       ra->field = cpu_to_le32(field);
+
+       return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+                                    MCU_EXT_CMD(STA_REC_UPDATE), true);
+}
+
+static int
+mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta)
+{
+       struct mt7915_vif *mvif = (struct mt7915_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, _he)                           \
+       do {                                                                    \
+               u8 i, gi = mask->control[band]._gi;                             \
+               gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;               \
+               for (i = 0; i <= sta->bandwidth; i++) {                         \
+                       phy.sgi |= gi << (i << (_he));                          \
+                       phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\
+               }                                                               \
+               for (i = 0; i < ARRAY_SIZE(mask->control[band]._mcs); i++)      \
+                       nrates += hweight16(mask->control[band]._mcs[i]);       \
+               phy.mcs = ffs(mask->control[band]._mcs[0]) - 1;                 \
+       } while (0)
+
+       if (sta->he_cap.has_he) {
+               __sta_phy_bitrate_mask_check(he_mcs, he_gi, 1);
+       } else if (sta->vht_cap.vht_supported) {
+               __sta_phy_bitrate_mask_check(vht_mcs, gi, 0);
+       } else if (sta->ht_cap.ht_supported) {
+               __sta_phy_bitrate_mask_check(ht_mcs, gi, 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 = mt7915_mcu_set_fixed_rate_ctrl(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 mt7915_sta *msta = (struct mt7915_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 = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
+               if (sta->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 = mt7915_mcu_set_fixed_rate_ctrl(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 = mt7915_mcu_set_fixed_rate_ctrl(dev, vif, sta, &phy,
+                                                    RATE_PARAM_FIXED_HE_LTF);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static void
 mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
                             struct ieee80211_vif *vif, struct ieee80211_sta *sta)
@@ -2092,8 +2214,6 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
        }
 
        if (sta->ht_cap.ht_supported) {
-               const u8 *mcs_mask = mask->control[band].ht_mcs;
-
                ra->supp_mode |= MODE_HT;
                ra->af = sta->ht_cap.ampdu_factor;
                ra->ht_gf = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
@@ -2111,12 +2231,12 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
                    (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
                        cap |= STA_CAP_LDPC;
 
-               mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs, mcs_mask);
+               mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
+                                         mask->control[band].ht_mcs);
                ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
        }
 
        if (sta->vht_cap.vht_supported) {
-               const u16 *mcs_mask = mask->control[band].vht_mcs;
                u8 af;
 
                ra->supp_mode |= MODE_VHT;
@@ -2137,7 +2257,8 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
                    (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
                        cap |= STA_CAP_VHT_LDPC;
 
-               mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs, mcs_mask);
+               mt7915_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
+                                          mask->control[band].vht_mcs);
        }
 
        if (sta->he_cap.has_he) {
@@ -2154,6 +2275,7 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
        struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
        struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
        struct sk_buff *skb;
+       int ret;
 
        skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta,
                                       MT7915_STA_UPDATE_MAX_SIZE);
@@ -2167,10 +2289,21 @@ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
        if (sta->he_cap.has_he && changed)
                mt7915_mcu_sta_he_tlv(skb, sta, vif);
 
+       /* sta_rec_ra accommodates BW, NSS and only MCS range format
+        * i.e 0-{7,8,9} for VHT.
+        */
        mt7915_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
 
-       return mt76_mcu_skb_send_msg(&dev->mt76, skb,
-                                    MCU_EXT_CMD(STA_REC_UPDATE), true);
+       ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+                                   MCU_EXT_CMD(STA_REC_UPDATE), true);
+       if (ret)
+               return ret;
+
+       /* sta_rec_ra_fixed accommodates single rate, (HE)GI and HE_LTE,
+        * and updates as peer fixed rate parameters, which overrides
+        * sta_rec_ra and firmware rate control algorithm.
+        */
+       return mt7915_mcu_add_rate_ctrl_fixed(dev, vif, sta);
 }
 
 static int
index d66918d914da1c2350d45f54d9182697c098ba1d..4821adb793d14e884d52c9ac902215e89ad1992d 100644 (file)
@@ -886,7 +886,7 @@ struct sta_rec_sec {
        struct sec_key key[2];
 } __packed;
 
-struct ra_phy {
+struct sta_phy {
        u8 type;
        u8 flag;
        u8 stbc;
@@ -930,7 +930,7 @@ struct sta_rec_ra {
 
        __le32 sta_cap;
 
-       struct ra_phy phy;
+       struct sta_phy phy;
 } __packed;
 
 struct sta_rec_ra_fixed {
@@ -943,7 +943,7 @@ struct sta_rec_ra_fixed {
        u8 op_vht_rx_nss;
        u8 op_vht_rx_nss_type;
 
-       struct ra_phy phy;
+       struct sta_phy phy;
 
        u8 spe_en;
        u8 short_preamble;
@@ -951,8 +951,14 @@ struct sta_rec_ra_fixed {
        u8 mmps_mode;
 } __packed;
 
-#define RATE_PARAM_FIXED               3
-#define RATE_PARAM_AUTO                        20
+enum {
+       RATE_PARAM_FIXED = 3,
+       RATE_PARAM_FIXED_HE_LTF = 7,
+       RATE_PARAM_FIXED_MCS,
+       RATE_PARAM_FIXED_GI = 11,
+       RATE_PARAM_AUTO = 20,
+};
+
 #define RATE_CFG_MCS                   GENMASK(3, 0)
 #define RATE_CFG_NSS                   GENMASK(7, 4)
 #define RATE_CFG_GI                    GENMASK(11, 8)
index 79a33afc5920a1d1d94ec91f81eba10d97922ac8..7a328fc774a788a700d4fa9127e82c56df0a1916 100644 (file)
@@ -418,6 +418,10 @@ int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif);
 int mt7915_mcu_update_edca(struct mt7915_dev *dev, void *req);
 int mt7915_mcu_set_fixed_rate(struct mt7915_dev *dev,
                              struct ieee80211_sta *sta, u32 rate);
+int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta,
+                                  void *data, u32 field);
 int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
 int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset);
 int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
@@ -478,6 +482,7 @@ static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask)
                mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
 }
 
+u32 mt7915_mac_wtbl_lmac_addr(struct mt7915_dev *dev, u16 wcid, u8 dw);
 bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
 void mt7915_mac_reset_counters(struct mt7915_phy *phy);
 void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);