OSDN Git Service

ath10k: disable multi-vif ps by default
authorMichal Kazior <michal.kazior@tieto.com>
Fri, 13 Feb 2015 12:30:16 +0000 (13:30 +0100)
committerKalle Valo <kvalo@qca.qualcomm.com>
Wed, 4 Mar 2015 13:39:24 +0000 (15:39 +0200)
Not all firmware revisions have a proper
multi-interface client powersaving implementation,
e.g. qca6174 WLAN.RM.2.0-00073.

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

index 7cba781..f65310c 100644 (file)
@@ -308,6 +308,7 @@ struct ath10k_vif {
        bool is_started;
        bool is_up;
        bool spectral_enabled;
+       bool ps;
        u32 aid;
        u8 bssid[ETH_ALEN];
 
@@ -433,6 +434,12 @@ enum ath10k_fw_features {
         */
        ATH10K_FW_FEATURE_WMI_10_2 = 4,
 
+       /* Some firmware revisions lack proper multi-interface client powersave
+        * implementation. Enabling PS could result in connection drops,
+        * traffic stalls, etc.
+        */
+       ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5,
+
        /* keep last */
        ATH10K_FW_FEATURE_COUNT,
 };
index 943e890..51838ed 100644 (file)
@@ -1251,6 +1251,20 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif)
        return 0;
 }
 
+static int ath10k_mac_ps_vif_count(struct ath10k *ar)
+{
+       struct ath10k_vif *arvif;
+       int num = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       list_for_each_entry(arvif, &ar->arvifs, list)
+               if (arvif->ps)
+                       num++;
+
+       return num;
+}
+
 static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
 {
        struct ath10k *ar = arvif->ar;
@@ -1260,13 +1274,24 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
        enum wmi_sta_ps_mode psmode;
        int ret;
        int ps_timeout;
+       bool enable_ps;
 
        lockdep_assert_held(&arvif->ar->conf_mutex);
 
        if (arvif->vif->type != NL80211_IFTYPE_STATION)
                return 0;
 
-       if (vif->bss_conf.ps) {
+       enable_ps = arvif->ps;
+
+       if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 &&
+           !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
+                     ar->fw_features)) {
+               ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n",
+                           arvif->vdev_id);
+               enable_ps = false;
+       }
+
+       if (enable_ps) {
                psmode = WMI_STA_PS_MODE_ENABLED;
                param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
 
@@ -3650,7 +3675,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_PS) {
-               ret = ath10k_mac_vif_setup_ps(arvif);
+               arvif->ps = vif->bss_conf.ps;
+
+               ret = ath10k_config_ps(ar);
                if (ret)
                        ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n",
                                    arvif->vdev_id, ret);