mt76: mt7915: add Tx beamformee support
authorRyder Lee <ryder.lee@mediatek.com>
Mon, 11 May 2020 16:06:34 +0000 (00:06 +0800)
committerFelix Fietkau <nbd@nbd.name>
Tue, 12 May 2020 17:52:36 +0000 (19:52 +0200)
Enable beamformee support.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Tested-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mcu.h

index 58d0adc..52e349b 100644 (file)
@@ -67,6 +67,7 @@ struct mt7915_fw_region {
 #define MCU_PATCH_ADDRESS              0x200000
 
 #define MT_STA_BFER                    BIT(0)
+#define MT_STA_BFEE                    BIT(1)
 
 #define FW_FEATURE_SET_ENCRYPT         BIT(0)
 #define FW_FEATURE_SET_KEY_IDX         GENMASK(2, 1)
@@ -1768,6 +1769,35 @@ mt7915_mcu_sta_bfer_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
        }
 }
 
+static void
+mt7915_mcu_sta_bfee_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+                       struct mt7915_phy *phy)
+{
+       struct sta_rec_bfee *bfee;
+       struct tlv *tlv;
+       int tx_ant = hweight8(phy->chainmask) - 1;
+       u8 nr = 0;
+
+       tlv = mt7915_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
+       bfee = (struct sta_rec_bfee *)tlv;
+
+       if (sta->he_cap.has_he) {
+               struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem;
+
+               nr = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
+                           pe->phy_cap_info[5]);
+       } else if (sta->vht_cap.vht_supported) {
+               struct ieee80211_sta_vht_cap *pc = &sta->vht_cap;
+
+               nr = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
+                              pc->cap);
+       }
+
+       /* reply with identity matrix to avoid 2x2 BF negative gain */
+       if (nr == 1 && tx_ant == 2)
+               bfee->fb_identity_matrix = true;
+}
+
 static u8
 mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif,
                         struct ieee80211_sta *sta)
@@ -1790,6 +1820,11 @@ mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif,
                vc = mt7915_get_he_phy_cap(phy, vif);
                ve = &vc->he_cap_elem;
 
+               if ((HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]) ||
+                    HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4])) &&
+                   HE_PHY(CAP4_SU_BEAMFORMEE, ve->phy_cap_info[4]))
+                       type |= MT_STA_BFEE;
+
                if ((HE_PHY(CAP3_SU_BEAMFORMER, ve->phy_cap_info[3]) ||
                     HE_PHY(CAP4_MU_BEAMFORMER, ve->phy_cap_info[4])) &&
                    HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]))
@@ -1806,6 +1841,9 @@ mt7915_mcu_sta_txbf_type(struct mt7915_phy *phy, struct ieee80211_vif *vif,
                ce = IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
                     IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
 
+               if ((pc->cap & cr) && (vc->cap & ce))
+                       type |= MT_STA_BFEE;
+
                if ((vc->cap & cr) && (pc->cap & ce))
                        type |= MT_STA_BFER;
        } else if (sta->ht_cap.ht_supported) {
@@ -1848,6 +1886,22 @@ mt7915_mcu_add_txbf(struct mt7915_dev *dev, struct ieee80211_vif *vif,
                        return r;
        }
 
+       /* starec bfee */
+       if (type & MT_STA_BFEE) {
+               len = sizeof(struct sta_req_hdr) + sizeof(struct sta_rec_bfee);
+
+               skb = mt7915_mcu_alloc_sta_req(dev, mvif, msta, len);
+               if (IS_ERR(skb))
+                       return PTR_ERR(skb);
+
+               mt7915_mcu_sta_bfee_tlv(skb, sta, phy);
+
+               r = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+                                           MCU_EXT_CMD_STA_REC_UPDATE, true);
+               if (r)
+                       return r;
+       }
+
        return 0;
 }
 
index 53d1e1f..cdeba5a 100644 (file)
@@ -865,6 +865,14 @@ struct sta_rec_bf {
        u8 rsv[2];
 } __packed;
 
+struct sta_rec_bfee {
+       __le16 tag;
+       __le16 len;
+       bool fb_identity_matrix;        /* 1: feedback identity matrix */
+       bool ignore_feedback;           /* 1: ignore */
+       u8 rsv[2];
+} __packed;
+
 enum {
        STA_REC_BASIC,
        STA_REC_RA,
@@ -886,6 +894,7 @@ enum {
        STA_REC_KEY_V2,
        STA_REC_MURU,
        STA_REC_MUEDCA,
+       STA_REC_BFEE,
        STA_REC_MAX_NUM
 };