wifi: ath11k: fix number of VHT beamformee spatial streams
authorJesus Fernandez Manzano <jesus.manzano@galgus.net>
Thu, 22 Sep 2022 07:35:14 +0000 (10:35 +0300)
committerKalle Valo <quic_kvalo@quicinc.com>
Thu, 22 Sep 2022 08:35:09 +0000 (11:35 +0300)
The number of spatial streams used when acting as a beamformee in VHT
mode are reported by the firmware as 7 (8 sts - 1) both in IPQ6018 and
IPQ8074 which respectively have 2 and 4 sts each. So the firmware should
report 1 (2 - 1) and 3 (4 - 1).

Fix this by checking that the number of VHT beamformee sts reported by
the firmware is not greater than the number of receiving antennas - 1.
The fix is based on the same approach used in this same function for
sanitizing the number of sounding dimensions reported by the firmware.

Without this change, acting as a beamformee in VHT mode is not working
properly.

Tested-on: IPQ6018 hw1.0 AHB WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.5.0.1-01208-QCAHKSWPL_SILICONZ-1

Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Signed-off-by: Jesus Fernandez Manzano <jesus.manzano@galgus.net>
Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Link: https://lore.kernel.org/r/20220616173947.21901-1-jesus.manzano@galgus.net
drivers/net/wireless/ath/ath11k/mac.c

index 2cd1e6f..dc39160 100644 (file)
@@ -4959,6 +4959,8 @@ static int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
        if (vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)) {
                nsts = vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
                nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+               if (nsts > (ar->num_rx_chains - 1))
+                       nsts = ar->num_rx_chains - 1;
                value |= SM(nsts, WMI_TXBF_STS_CAP_OFFSET);
        }
 
@@ -4999,7 +5001,7 @@ static int ath11k_mac_set_txbf_conf(struct ath11k_vif *arvif)
 static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
 {
        bool subfer, subfee;
-       int sound_dim = 0;
+       int sound_dim = 0, nsts = 0;
 
        subfer = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE));
        subfee = !!(*vht_cap & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE));
@@ -5009,6 +5011,11 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
                subfer = false;
        }
 
+       if (ar->num_rx_chains < 2) {
+               *vht_cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+               subfee = false;
+       }
+
        /* If SU Beaformer is not set, then disable MU Beamformer Capability */
        if (!subfer)
                *vht_cap &= ~(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE);
@@ -5021,7 +5028,9 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
        sound_dim >>= IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT;
        *vht_cap &= ~IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK;
 
-       /* TODO: Need to check invalid STS and Sound_dim values set by FW? */
+       nsts = (*vht_cap & IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
+       nsts >>= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+       *vht_cap &= ~IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
 
        /* Enable Sounding Dimension Field only if SU BF is enabled */
        if (subfer) {
@@ -5033,9 +5042,15 @@ static void ath11k_set_vht_txbf_cap(struct ath11k *ar, u32 *vht_cap)
                *vht_cap |= sound_dim;
        }
 
-       /* Use the STS advertised by FW unless SU Beamformee is not supported*/
-       if (!subfee)
-               *vht_cap &= ~(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK);
+       /* Enable Beamformee STS Field only if SU BF is enabled */
+       if (subfee) {
+               if (nsts > (ar->num_rx_chains - 1))
+                       nsts = ar->num_rx_chains - 1;
+
+               nsts <<= IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT;
+               nsts &=  IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
+               *vht_cap |= nsts;
+       }
 }
 
 static struct ieee80211_sta_vht_cap