ath11k: add support for 80P80 and 160 MHz bandwidth
authorP Praneesh <ppranees@codeaurora.org>
Fri, 24 Sep 2021 13:52:46 +0000 (16:52 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 28 Sep 2021 08:51:51 +0000 (11:51 +0300)
For 160 MHz, nss_ratio_enabled flag is added to indicate firmware
supports sending NSS ratio information from firmware as a part of
service ready ext event. Extract this NSS ratio info from service
ready ext event and save this information in ath11k_pdev_cap to
calculate NSS ratio.

Current firmware configurations support two types of NSS ratio
which is WMI_NSS_RATIO_1_NSS for QCN9074 and WMI_NSS_RATIO_1BY2_NSS
for IPQ8074. Based on this two configuration, max supported
NSS getting calculated.

Move ath11k_peer_assoc_h_phymode() before ath11k_peer_assoc_h_vht()
to get arg->peer_phymode updated.

Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.4.0.1-00097-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.4.0.1-01467-QCAHKSWPL_SILICONZ-1

Co-developed-by: Ganesh Sesetti <gseset@codeaurora.org>
Signed-off-by: Ganesh Sesetti <gseset@codeaurora.org>
Co-developed-by: Sathishkumar Muruganandam <murugana@codeaurora.org>
Signed-off-by: Sathishkumar Muruganandam <murugana@codeaurora.org>
Signed-off-by: P Praneesh <ppranees@codeaurora.org>
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20210721173615.75637-2-jouni@codeaurora.org
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/mac.h
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/ath/ath11k/wmi.h

index a70d724..3dd5a69 100644 (file)
@@ -597,6 +597,8 @@ struct ath11k_pdev_cap {
        u32 tx_chain_mask_shift;
        u32 rx_chain_mask_shift;
        struct ath11k_band_cap band[NUM_NL80211_BANDS];
+       bool nss_ratio_enabled;
+       u8 nss_ratio_info;
 };
 
 struct ath11k_pdev {
index 0db93fb..a35eded 100644 (file)
@@ -1581,6 +1581,34 @@ ath11k_peer_assoc_h_vht_limit(u16 tx_mcs_set,
        return tx_mcs_set;
 }
 
+static u8 ath11k_get_nss_160mhz(struct ath11k *ar,
+                               u8 max_nss)
+{
+       u8 nss_ratio_info = ar->pdev->cap.nss_ratio_info;
+       u8 max_sup_nss = 0;
+
+       switch (nss_ratio_info) {
+       case WMI_NSS_RATIO_1BY2_NSS:
+               max_sup_nss = max_nss >> 1;
+               break;
+       case WMI_NSS_RATIO_3BY4_NSS:
+               ath11k_warn(ar->ab, "WMI_NSS_RATIO_3BY4_NSS not supported\n");
+               break;
+       case WMI_NSS_RATIO_1_NSS:
+               max_sup_nss = max_nss;
+               break;
+       case WMI_NSS_RATIO_2_NSS:
+               ath11k_warn(ar->ab, "WMI_NSS_RATIO_2_NSS not supported\n");
+               break;
+       default:
+               ath11k_warn(ar->ab, "invalid nss ratio received from firmware: %d\n",
+                           nss_ratio_info);
+               break;
+       }
+
+       return max_sup_nss;
+}
+
 static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
                                    struct ieee80211_vif *vif,
                                    struct ieee80211_sta *sta,
@@ -1595,6 +1623,7 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
        u8 max_nss, vht_mcs;
        int i, vht_nss, nss_idx;
        bool user_rate_valid = true;
+       u32 rx_nss, tx_nss, nss_160;
 
        if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
                return;
@@ -1687,10 +1716,29 @@ static void ath11k_peer_assoc_h_vht(struct ath11k *ar,
        /* TODO:  Check */
        arg->tx_max_mcs_nss = 0xFF;
 
-       ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
-                  sta->addr, arg->peer_max_mpdu, arg->peer_flags);
+       if (arg->peer_phymode == MODE_11AC_VHT160 ||
+           arg->peer_phymode == MODE_11AC_VHT80_80) {
+               tx_nss = ath11k_get_nss_160mhz(ar, max_nss);
+               rx_nss = min(arg->peer_nss, tx_nss);
+               arg->peer_bw_rxnss_override = ATH11K_BW_NSS_MAP_ENABLE;
+
+               if (!rx_nss) {
+                       ath11k_warn(ar->ab, "invalid max_nss\n");
+                       return;
+               }
+
+               if (arg->peer_phymode == MODE_11AC_VHT160)
+                       nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_160MHZ, rx_nss - 1);
+               else
+                       nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_80_80MHZ, rx_nss - 1);
 
-       /* TODO: rxnss_override */
+               arg->peer_bw_rxnss_override |= nss_160;
+       }
+
+       ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
+                  "mac vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n",
+                  sta->addr, arg->peer_max_mpdu, arg->peer_flags,
+                  arg->peer_bw_rxnss_override);
 }
 
 static int ath11k_mac_get_max_he_mcs_map(u16 mcs_map, int nss)
@@ -1774,6 +1822,7 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
        u16 he_tx_mcs = 0, v = 0;
        int i, he_nss, nss_idx;
        bool user_rate_valid = true;
+       u32 rx_nss, tx_nss, nss_160;
 
        if (WARN_ON(ath11k_mac_vif_chan(vif, &def)))
                return;
@@ -1937,9 +1986,30 @@ static void ath11k_peer_assoc_h_he(struct ath11k *ar,
        }
        arg->peer_nss = min(sta->rx_nss, max_nss);
 
+       if (arg->peer_phymode == MODE_11AX_HE160 ||
+           arg->peer_phymode == MODE_11AX_HE80_80) {
+               tx_nss = ath11k_get_nss_160mhz(ar, max_nss);
+               rx_nss = min(arg->peer_nss, tx_nss);
+               arg->peer_bw_rxnss_override = ATH11K_BW_NSS_MAP_ENABLE;
+
+               if (!rx_nss) {
+                       ath11k_warn(ar->ab, "invalid max_nss\n");
+                       return;
+               }
+
+               if (arg->peer_phymode == MODE_11AX_HE160)
+                       nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_160MHZ, rx_nss - 1);
+               else
+                       nss_160 = FIELD_PREP(ATH11K_PEER_RX_NSS_80_80MHZ, rx_nss - 1);
+
+               arg->peer_bw_rxnss_override |= nss_160;
+       }
+
        ath11k_dbg(ar->ab, ATH11K_DBG_MAC,
-                  "mac he peer %pM nss %d mcs cnt %d\n",
-                  sta->addr, arg->peer_nss, arg->peer_he_mcs_count);
+                  "mac he peer %pM nss %d mcs cnt %d nss_override 0x%x\n",
+                  sta->addr, arg->peer_nss,
+                  arg->peer_he_mcs_count,
+                  arg->peer_bw_rxnss_override);
 }
 
 static void ath11k_peer_assoc_h_smps(struct ieee80211_sta *sta,
@@ -2227,11 +2297,11 @@ static void ath11k_peer_assoc_prepare(struct ath11k *ar,
        ath11k_peer_assoc_h_basic(ar, vif, sta, arg);
        ath11k_peer_assoc_h_crypto(ar, vif, sta, arg);
        ath11k_peer_assoc_h_rates(ar, vif, sta, arg);
+       ath11k_peer_assoc_h_phymode(ar, vif, sta, arg);
        ath11k_peer_assoc_h_ht(ar, vif, sta, arg);
        ath11k_peer_assoc_h_vht(ar, vif, sta, arg);
        ath11k_peer_assoc_h_he(ar, vif, sta, arg);
        ath11k_peer_assoc_h_qos(ar, vif, sta, arg);
-       ath11k_peer_assoc_h_phymode(ar, vif, sta, arg);
        ath11k_peer_assoc_h_smps(sta, arg);
 
        /* TODO: amsdu_disable req? */
@@ -4427,11 +4497,6 @@ ath11k_create_vht_cap(struct ath11k *ar, u32 rate_cap_tx_chainmask,
 
        ath11k_set_vht_txbf_cap(ar, &vht_cap.cap);
 
-       /* TODO: Enable back VHT160 mode once association issues are fixed */
-       /* Disabling VHT160 and VHT80+80 modes */
-       vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK;
-       vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160;
-
        rxmcs_map = 0;
        txmcs_map = 0;
        for (i = 0; i < 8; i++) {
@@ -7345,7 +7410,9 @@ static int ath11k_mac_setup_iface_combinations(struct ath11k *ar)
        combinations[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
                                                BIT(NL80211_CHAN_WIDTH_20) |
                                                BIT(NL80211_CHAN_WIDTH_40) |
-                                               BIT(NL80211_CHAN_WIDTH_80);
+                                               BIT(NL80211_CHAN_WIDTH_80) |
+                                               BIT(NL80211_CHAN_WIDTH_80P80) |
+                                               BIT(NL80211_CHAN_WIDTH_160);
 
        ar->hw->wiphy->iface_combinations = combinations;
        ar->hw->wiphy->n_iface_combinations = 1;
@@ -7484,6 +7551,10 @@ static int __ath11k_mac_register(struct ath11k *ar)
        ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
        ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
        ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+
+       if (cap->nss_ratio_enabled)
+               ieee80211_hw_set(ar->hw, SUPPORTS_VHT_EXT_NSS_BW);
+
        if (ht_cap & WMI_HT_CAP_ENABLED) {
                ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
                ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
index 4bc59bd..254ca4a 100644 (file)
@@ -115,6 +115,9 @@ struct ath11k_generic_iter {
 #define WMI_MAX_SPATIAL_STREAM                 3
 
 #define ATH11K_CHAN_WIDTH_NUM                  8
+#define ATH11K_BW_NSS_MAP_ENABLE               BIT(31)
+#define ATH11K_PEER_RX_NSS_160MHZ              GENMASK(2, 0)
+#define ATH11K_PEER_RX_NSS_80_80MHZ            GENMASK(5, 3)
 
 #define ATH11K_OBSS_PD_MAX_THRESHOLD                   -82
 #define ATH11K_OBSS_PD_NON_SRG_MAX_THRESHOLD           -62
index 330b435..7ac84ac 100644 (file)
@@ -360,6 +360,10 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
                pdev_cap->he_mcs = mac_phy_caps->he_supp_mcs_5g;
                pdev_cap->tx_chain_mask = mac_phy_caps->tx_chain_mask_5g;
                pdev_cap->rx_chain_mask = mac_phy_caps->rx_chain_mask_5g;
+               pdev_cap->nss_ratio_enabled =
+                       WMI_NSS_RATIO_ENABLE_DISABLE_GET(mac_phy_caps->nss_ratio);
+               pdev_cap->nss_ratio_info =
+                       WMI_NSS_RATIO_INFO_GET(mac_phy_caps->nss_ratio);
        } else {
                return -EINVAL;
        }
@@ -783,14 +787,26 @@ int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id)
 static void ath11k_wmi_put_wmi_channel(struct wmi_channel *chan,
                                       struct wmi_vdev_start_req_arg *arg)
 {
+       u32 center_freq1 = arg->channel.band_center_freq1;
+
        memset(chan, 0, sizeof(*chan));
 
        chan->mhz = arg->channel.freq;
        chan->band_center_freq1 = arg->channel.band_center_freq1;
-       if (arg->channel.mode == MODE_11AC_VHT80_80)
+
+       if (arg->channel.mode == MODE_11AX_HE160) {
+               if (arg->channel.freq > arg->channel.band_center_freq1)
+                       chan->band_center_freq1 = center_freq1 + 40;
+               else
+                       chan->band_center_freq1 = center_freq1 - 40;
+
+               chan->band_center_freq2 = arg->channel.band_center_freq1;
+
+       } else if (arg->channel.mode == MODE_11AC_VHT80_80) {
                chan->band_center_freq2 = arg->channel.band_center_freq2;
-       else
+       } else {
                chan->band_center_freq2 = 0;
+       }
 
        chan->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, arg->channel.mode);
        if (arg->channel.passive)
index c06db3a..39bfa23 100644 (file)
@@ -2146,6 +2146,24 @@ enum wmi_direct_buffer_module {
        WMI_DIRECT_BUF_MAX
 };
 
+/* enum wmi_nss_ratio - NSS ratio received from FW during service ready ext
+ *                     event
+ * WMI_NSS_RATIO_1BY2_NSS -Max nss of 160MHz is equals to half of the max nss
+ *                        of 80MHz
+ * WMI_NSS_RATIO_3BY4_NSS - Max nss of 160MHz is equals to 3/4 of the max nss
+ *                         of 80MHz
+ * WMI_NSS_RATIO_1_NSS - Max nss of 160MHz is equals to the max nss of 80MHz
+ * WMI_NSS_RATIO_2_NSS - Max nss of 160MHz is equals to two times the max
+ *                      nss of 80MHz
+ */
+
+enum wmi_nss_ratio {
+       WMI_NSS_RATIO_1BY2_NSS = 0x0,
+       WMI_NSS_RATIO_3BY4_NSS = 0x1,
+       WMI_NSS_RATIO_1_NSS = 0x2,
+       WMI_NSS_RATIO_2_NSS = 0x3,
+};
+
 struct wmi_host_pdev_band_to_mac {
        u32 pdev_id;
        u32 start_freq;
@@ -2390,6 +2408,12 @@ struct wmi_hw_mode_capabilities {
 } __packed;
 
 #define WMI_MAX_HECAP_PHY_SIZE                 (3)
+#define WMI_NSS_RATIO_ENABLE_DISABLE_BITPOS    BIT(0)
+#define WMI_NSS_RATIO_ENABLE_DISABLE_GET(_val) \
+       FIELD_GET(WMI_NSS_RATIO_ENABLE_DISABLE_BITPOS, _val)
+#define WMI_NSS_RATIO_INFO_BITPOS              GENMASK(4, 1)
+#define WMI_NSS_RATIO_INFO_GET(_val) \
+       FIELD_GET(WMI_NSS_RATIO_INFO_BITPOS, _val)
 
 struct wmi_mac_phy_capabilities {
        u32 hw_mode_id;
@@ -2423,6 +2447,12 @@ struct wmi_mac_phy_capabilities {
        u32 he_cap_info_2g_ext;
        u32 he_cap_info_5g_ext;
        u32 he_cap_info_internal;
+       u32 wireless_modes;
+       u32 low_2ghz_chan_freq;
+       u32 high_2ghz_chan_freq;
+       u32 low_5ghz_chan_freq;
+       u32 high_5ghz_chan_freq;
+       u32 nss_ratio;
 } __packed;
 
 struct wmi_hal_reg_capabilities_ext {