]> git.karo-electronics.de Git - linux-beck.git/commitdiff
ath10k: fix SMPS support
authorMichal Kazior <michal.kazior@tieto.com>
Fri, 14 Feb 2014 13:45:51 +0000 (14:45 +0100)
committerKalle Valo <kvalo@qca.qualcomm.com>
Sat, 15 Feb 2014 06:47:36 +0000 (08:47 +0200)
Firmware ignores SMPS flags in peer assoc command.

For SMPS to work it is necessary to set peer
parameter after peer assoc command so that tx
chainmask is setup properly.

This should fix packet loss and improve throughput
with stations that have SMPS enabled upon
association.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/mac.c

index 44b550b2fcfdc3039721e03e55fdefa5a14793bc..c2aaecb4c25bfeb46a2776639d24e32be3ea4583 100644 (file)
@@ -1082,7 +1082,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                                   struct wmi_peer_assoc_complete_arg *arg)
 {
        const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
-       int smps;
        int i, n;
 
        lockdep_assert_held(&ar->conf_mutex);
@@ -1128,17 +1127,6 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
                arg->peer_flags |= WMI_PEER_STBC;
        }
 
-       smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
-       smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
-
-       if (smps == WLAN_HT_CAP_SM_PS_STATIC) {
-               arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
-               arg->peer_flags |= WMI_PEER_STATIC_MIMOPS;
-       } else if (smps == WLAN_HT_CAP_SM_PS_DYNAMIC) {
-               arg->peer_flags |= WMI_PEER_SPATIAL_MUX;
-               arg->peer_flags |= WMI_PEER_DYN_MIMOPS;
-       }
-
        if (ht_cap->mcs.rx_mask[1] && ht_cap->mcs.rx_mask[2])
                arg->peer_rate_caps |= WMI_RC_TS_FLAG;
        else if (ht_cap->mcs.rx_mask[1])
@@ -1378,6 +1366,33 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar,
        return 0;
 }
 
+static const u32 ath10k_smps_map[] = {
+       [WLAN_HT_CAP_SM_PS_STATIC] = WMI_PEER_SMPS_STATIC,
+       [WLAN_HT_CAP_SM_PS_DYNAMIC] = WMI_PEER_SMPS_DYNAMIC,
+       [WLAN_HT_CAP_SM_PS_INVALID] = WMI_PEER_SMPS_PS_NONE,
+       [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE,
+};
+
+static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
+                                 const u8 *addr,
+                                 const struct ieee80211_sta_ht_cap *ht_cap)
+{
+       int smps;
+
+       if (!ht_cap->ht_supported)
+               return 0;
+
+       smps = ht_cap->cap & IEEE80211_HT_CAP_SM_PS;
+       smps >>= IEEE80211_HT_CAP_SM_PS_SHIFT;
+
+       if (smps >= ARRAY_SIZE(ath10k_smps_map))
+               return -EINVAL;
+
+       return ath10k_wmi_peer_set_param(ar, arvif->vdev_id, addr,
+                                        WMI_PEER_SMPS_STATE,
+                                        ath10k_smps_map[smps]);
+}
+
 /* can be called only in mac80211 callbacks due to `key_count` usage */
 static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif,
@@ -1385,6 +1400,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 {
        struct ath10k *ar = hw->priv;
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       struct ieee80211_sta_ht_cap ht_cap;
        struct wmi_peer_assoc_complete_arg peer_arg;
        struct ieee80211_sta *ap_sta;
        int ret;
@@ -1401,6 +1417,10 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                return;
        }
 
+       /* ap_sta must be accessed only within rcu section which must be left
+        * before calling ath10k_setup_peer_smps() which might sleep. */
+       ht_cap = ap_sta->ht_cap;
+
        ret = ath10k_peer_assoc_prepare(ar, arvif, ap_sta,
                                        bss_conf, &peer_arg);
        if (ret) {
@@ -1419,6 +1439,12 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
                return;
        }
 
+       ret = ath10k_setup_peer_smps(ar, arvif, bss_conf->bssid, &ht_cap);
+       if (ret) {
+               ath10k_warn("failed to setup peer SMPS: %d\n", ret);
+               return;
+       }
+
        ath10k_dbg(ATH10K_DBG_MAC,
                   "mac vdev %d up (associated) bssid %pM aid %d\n",
                   arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
@@ -1500,6 +1526,12 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
                return ret;
        }
 
+       ret = ath10k_setup_peer_smps(ar, arvif, sta->addr, &sta->ht_cap);
+       if (ret) {
+               ath10k_warn("failed to setup peer SMPS: %d\n", ret);
+               return ret;
+       }
+
        ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
        if (ret) {
                ath10k_warn("could not install peer wep keys (%d)\n", ret);