]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
ath10k: configure rxnss_override for QCA9984
authorBen Greear <greearb@candelatech.com>
Fri, 16 Jun 2017 07:37:45 +0000 (10:37 +0300)
committerKalle Valo <kvalo@qca.qualcomm.com>
Wed, 21 Jun 2017 13:17:21 +0000 (16:17 +0300)
QCA9984 hardware can do 4x4 at 80Mhz, but only 2x2 at 160Mhz.

First, report this to user-space by setting the max-tx-speed
and max-rx-speed vht capabilities.

Second, if the peer rx-speed is configured, and if we
are in 160 or 80+80 mode, and the peer rx-speed matches
the max speed for 2x2 or 1x1 at 160Mhz (long guard interval),
then use that info to set the peer_bw_rxnss_override appropriately.

Without this, a 9984 firmware will not use 2x2 ratesets when
transmitting to peer (it will be stuck at 1x1), because
the firmware would not have configured the rxnss_override.

Signed-off-by: Ben Greear <greearb@candelatech.com>
[sven.eckelmann@openmesh.com: rebase, cleanup, drop 160Mhz workaround cleanup]
Signed-off-by: Sven Eckelmann <sven.eckelmann@openmesh.com>
[kvalo@qca.qualcomm.com: use hw_params, rename the title]
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h

index 700efe3f62255eaefd34dffd0719d9805930110d..51d05d6138e56146cae9b0f180e84726fc7997fc 100644 (file)
@@ -72,6 +72,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca988x_ops,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA9887_HW_1_0_VERSION,
@@ -93,6 +95,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca988x_ops,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA6174_HW_2_1_VERSION,
@@ -113,6 +117,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca988x_ops,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA6174_HW_2_1_VERSION,
@@ -133,6 +139,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca988x_ops,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA6174_HW_3_0_VERSION,
@@ -153,6 +161,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca988x_ops,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA6174_HW_3_2_VERSION,
@@ -176,6 +186,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .target_cpu_freq = 176000000,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA99X0_HW_2_0_DEV_VERSION,
@@ -202,6 +214,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca99x0_ops,
                .decap_align_bytes = 1,
                .spectral_bin_discard = 4,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA9984_HW_1_0_DEV_VERSION,
@@ -229,6 +243,12 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca99x0_ops,
                .decap_align_bytes = 1,
                .spectral_bin_discard = 12,
+
+               /* Can do only 2x2 VHT160 or 80+80. 1560Mbps is 4x4 80Mhz
+                * or 2x2 160Mhz, long-guard-interval.
+                */
+               .vht160_mcs_rx_highest = 1560,
+               .vht160_mcs_tx_highest = 1560,
        },
        {
                .id = QCA9888_HW_2_0_DEV_VERSION,
@@ -255,6 +275,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca99x0_ops,
                .decap_align_bytes = 1,
                .spectral_bin_discard = 12,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA9377_HW_1_0_DEV_VERSION,
@@ -275,6 +297,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca988x_ops,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA9377_HW_1_1_DEV_VERSION,
@@ -297,6 +321,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .target_cpu_freq = 176000000,
                .decap_align_bytes = 4,
                .spectral_bin_discard = 0,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
        {
                .id = QCA4019_HW_1_0_DEV_VERSION,
@@ -324,6 +350,8 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .hw_ops = &qca99x0_ops,
                .decap_align_bytes = 1,
                .spectral_bin_discard = 4,
+               .vht160_mcs_rx_highest = 0,
+               .vht160_mcs_tx_highest = 0,
        },
 };
 
index be3eea429ec67cc4008e67e39abe330175e8b993..97dc1479f44e1496b50ff0e962ff18e87e95b1a9 100644 (file)
@@ -535,6 +535,12 @@ struct ath10k_hw_params {
 
        /* Number of bytes to be discarded for each FFT sample */
        int spectral_bin_discard;
+
+       /* The board may have a restricted NSS for 160 or 80+80 vs what it
+        * can do for 80Mhz.
+        */
+       int vht160_mcs_rx_highest;
+       int vht160_mcs_tx_highest;
 };
 
 struct htt_rx_desc;
index 51551c1ec0679f727b49296707642fc02c240c49..3658d6d5faa411186aba8a322c69775f22d5814b 100644 (file)
@@ -2519,6 +2519,20 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
 
        ath10k_dbg(ar, ATH10K_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_vht_rates.rx_max_rate &&
+           (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
+               switch (arg->peer_vht_rates.rx_max_rate) {
+               case 1560:
+                       /* Must be 2x2 at 160Mhz is all it can do. */
+                       arg->peer_bw_rxnss_override = 2;
+                       break;
+               case 780:
+                       /* Can only do 1x1 at 160Mhz (Long Guard Interval) */
+                       arg->peer_bw_rxnss_override = 1;
+                       break;
+               }
+       }
 }
 
 static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
@@ -4362,6 +4376,7 @@ static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar)
 static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
 {
        struct ieee80211_sta_vht_cap vht_cap = {0};
+       struct ath10k_hw_params *hw = &ar->hw_params;
        u16 mcs_map;
        u32 val;
        int i;
@@ -4408,6 +4423,17 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
        vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(mcs_map);
        vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(mcs_map);
 
+       /* If we are supporting 160Mhz or 80+80, then the NIC may be able to do
+        * a restricted NSS for 160 or 80+80 vs what it can do for 80Mhz.  Give
+        * user-space a clue if that is the case.
+        */
+       if ((vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) &&
+           (hw->vht160_mcs_rx_highest != 0 ||
+            hw->vht160_mcs_tx_highest != 0)) {
+               vht_cap.vht_mcs.rx_highest = cpu_to_le16(hw->vht160_mcs_rx_highest);
+               vht_cap.vht_mcs.tx_highest = cpu_to_le16(hw->vht160_mcs_tx_highest);
+       }
+
        return vht_cap;
 }
 
index 472b42bff7bfcbe44538bee163cccf7f941be44f..140718c6ae908cc890ba0f195054daf82c3d4230 100644 (file)
@@ -6734,7 +6734,12 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf,
        struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
 
        ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
-       cmd->peer_bw_rxnss_override = 0;
+       if (arg->peer_bw_rxnss_override)
+               cmd->peer_bw_rxnss_override =
+                       __cpu_to_le32((arg->peer_bw_rxnss_override - 1) |
+                                     BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET));
+       else
+               cmd->peer_bw_rxnss_override = 0;
 }
 
 static int
index 1b4865a555954f8787d30a32384c1c7337857d9d..baa38c8f847c2ba8300baf71d31dee26d051b607 100644 (file)
@@ -6028,6 +6028,8 @@ struct wmi_10_2_peer_assoc_complete_cmd {
        __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
 } __packed;
 
+#define PEER_BW_RXNSS_OVERRIDE_OFFSET  31
+
 struct wmi_10_4_peer_assoc_complete_cmd {
        struct wmi_10_2_peer_assoc_complete_cmd cmd;
        __le32 peer_bw_rxnss_override;
@@ -6051,6 +6053,7 @@ struct wmi_peer_assoc_complete_arg {
        u32 peer_vht_caps;
        enum wmi_phy_mode peer_phymode;
        struct wmi_vht_rate_set_arg peer_vht_rates;
+       u32 peer_bw_rxnss_override;
 };
 
 struct wmi_peer_add_wds_entry_cmd {