ath10k: add recalc RTS/CTS protection method
authorMarek Kwaczynski <marek.kwaczynski@tieto.com>
Tue, 11 Mar 2014 10:58:00 +0000 (12:58 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 13 Mar 2014 05:14:28 +0000 (07:14 +0200)
Add recalculation of RTS/CTS protection when one or more legacy
stations are connected to ath10k. In this case enable RTS/CTS
protection and set sw retry profile are needed in the FW.
Without this change legacy station is starved and has very low
throughput.

Signed-off-by: Marek Kwaczynski <marek.kwaczynski@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
drivers/net/wireless/ath/ath10k/wmi.h

index 0e71979d837cf90888c74e4d85035c2a4d6fd4ef..ad209a61675aa5e18815e7f78e3070c27509d4cc 100644 (file)
@@ -260,6 +260,8 @@ struct ath10k_vif {
        u8 fixed_rate;
        u8 fixed_nss;
        u8 force_sgi;
+       bool use_cts_prot;
+       int num_legacy_stations;
 };
 
 struct ath10k_vif_iter {
index 9ad1869fc5d3741378c7b20aa2d0d86e556f5c62..9e24ae972ec925c62c202fb771a90f205bc7b74d 100644 (file)
@@ -739,6 +739,26 @@ static int ath10k_monitor_destroy(struct ath10k *ar)
        return ret;
 }
 
+static int ath10k_recalc_rtscts_prot(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+       u32 vdev_param, rts_cts = 0;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       vdev_param = ar->wmi.vdev_param->enable_rtscts;
+
+       if (arvif->use_cts_prot || arvif->num_legacy_stations > 0)
+               rts_cts |= SM(WMI_RTSCTS_ENABLED, WMI_RTSCTS_SET);
+
+       if (arvif->num_legacy_stations > 0)
+               rts_cts |= SM(WMI_RTSCTS_ACROSS_SW_RETRIES,
+                             WMI_RTSCTS_PROFILE);
+
+       return ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+                                        rts_cts);
+}
+
 static int ath10k_start_cac(struct ath10k *ar)
 {
        int ret;
@@ -1552,6 +1572,16 @@ static int ath10k_station_assoc(struct ath10k *ar, struct ath10k_vif *arvif,
                return ret;
        }
 
+       if (!sta->wme) {
+               arvif->num_legacy_stations++;
+               ret  = ath10k_recalc_rtscts_prot(arvif);
+               if (ret) {
+                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
+       }
+
        ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
        if (ret) {
                ath10k_warn("could not install peer wep keys for vdev %i: %d\n",
@@ -1576,6 +1606,16 @@ static int ath10k_station_disassoc(struct ath10k *ar, struct ath10k_vif *arvif,
 
        lockdep_assert_held(&ar->conf_mutex);
 
+       if (!sta->wme) {
+               arvif->num_legacy_stations--;
+               ret = ath10k_recalc_rtscts_prot(arvif);
+               if (ret) {
+                       ath10k_warn("failed to recalculate rts/cts prot for vdev %d: %d\n",
+                                   arvif->vdev_id, ret);
+                       return ret;
+               }
+       }
+
        ret = ath10k_clear_peer_keys(arvif, sta->addr);
        if (ret) {
                ath10k_warn("could not clear all peer wep keys for vdev %i: %d\n",
@@ -2869,20 +2909,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ath10k_control_beaconing(arvif, info);
 
        if (changed & BSS_CHANGED_ERP_CTS_PROT) {
-               u32 cts_prot;
-               if (info->use_cts_prot)
-                       cts_prot = 1;
-               else
-                       cts_prot = 0;
-
+               arvif->use_cts_prot = info->use_cts_prot;
                ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
-                          arvif->vdev_id, cts_prot);
+                          arvif->vdev_id, info->use_cts_prot);
 
-               vdev_param = ar->wmi.vdev_param->enable_rtscts;
-               ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
-                                               cts_prot);
+               ret = ath10k_recalc_rtscts_prot(arvif);
                if (ret)
-                       ath10k_warn("Failed to set CTS prot for vdev %d: %d\n",
+                       ath10k_warn("Failed to recalculate rts/cts prot for vdev %d: %d\n",
                                    arvif->vdev_id, ret);
        }
 
index 4fcc96aa9513b89a45e11fd9c2d8da79414204c9..e78a7adb66a4e42629275b7d815d2ff37961a056 100644 (file)
@@ -2210,6 +2210,19 @@ enum ath10k_protmode {
        ATH10K_PROT_RTSCTS   = 2,    /* RTS-CTS */
 };
 
+enum wmi_rtscts_profile {
+       WMI_RTSCTS_FOR_NO_RATESERIES = 0,
+       WMI_RTSCTS_FOR_SECOND_RATESERIES,
+       WMI_RTSCTS_ACROSS_SW_RETRIES
+};
+
+#define WMI_RTSCTS_ENABLED             1
+#define WMI_RTSCTS_SET_MASK            0x0f
+#define WMI_RTSCTS_SET_LSB             0
+
+#define WMI_RTSCTS_PROFILE_MASK                0xf0
+#define WMI_RTSCTS_PROFILE_LSB         4
+
 enum wmi_beacon_gen_mode {
        WMI_BEACON_STAGGERED_MODE = 0,
        WMI_BEACON_BURST_MODE = 1