ath10k: enable firmware STA quick kickout
authorKalle Valo <kvalo@qca.qualcomm.com>
Mon, 20 Jan 2014 09:01:46 +0000 (11:01 +0200)
committerKalle Valo <kvalo@qca.qualcomm.com>
Thu, 23 Jan 2014 12:54:03 +0000 (14:54 +0200)
Firmware has a feature to track if the associated STA is not acking the frames.
When that happens, the firmware sends WMI_PEER_STA_KICKOUT_EVENTID event to the
host. Enable that to faster detect when a STA has left BSS without sending a
deauth frame.

Also set huge keepalive timeouts to avoid using the keepalive functionality in
the firmware.

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.c
drivers/net/wireless/ath/ath10k/wmi.h

index ade1781c7186c5d033a0d5bc5dda2c36b4c6a4ac..e6308f420a5c0c9d9c8c59597a6041ea568facbd 100644 (file)
 
 #define ATH10K_MAX_NUM_MGMT_PENDING 128
 
+/* number of failed packets */
+#define ATH10K_KICKOUT_THRESHOLD 50
+
+/*
+ * Use insanely high numbers to make sure that the firmware implementation
+ * won't start, we have the same functionality already in hostapd. Unit
+ * is seconds.
+ */
+#define ATH10K_KEEPALIVE_MIN_IDLE 3747
+#define ATH10K_KEEPALIVE_MAX_IDLE 3895
+#define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900
+
 struct ath10k;
 
 struct ath10k_skb_cb {
index 776e364eadcd76c82ed37a64e20601f5bb1926ab..5269cf8f2d781d70ad3df1c7dff7237e3fc16aab 100644 (file)
@@ -339,6 +339,50 @@ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
        return 0;
 }
 
+static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
+{
+       struct ath10k *ar = arvif->ar;
+       u32 param;
+       int ret;
+
+       param = ar->wmi.pdev_param->sta_kickout_th;
+       ret = ath10k_wmi_pdev_set_param(ar, param,
+                                       ATH10K_KICKOUT_THRESHOLD);
+       if (ret) {
+               ath10k_warn("Failed to set kickout threshold: %d\n", ret);
+               return ret;
+       }
+
+       param = ar->wmi.vdev_param->ap_keepalive_min_idle_inactive_time_secs;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+                                       ATH10K_KEEPALIVE_MIN_IDLE);
+       if (ret) {
+               ath10k_warn("Failed to set keepalive minimum idle time : %d\n",
+                           ret);
+               return ret;
+       }
+
+       param = ar->wmi.vdev_param->ap_keepalive_max_idle_inactive_time_secs;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+                                       ATH10K_KEEPALIVE_MAX_IDLE);
+       if (ret) {
+               ath10k_warn("Failed to set keepalive maximum idle time: %d\n",
+                           ret);
+               return ret;
+       }
+
+       param = ar->wmi.vdev_param->ap_keepalive_max_unresponsive_time_secs;
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param,
+                                       ATH10K_KEEPALIVE_MAX_UNRESPONSIVE);
+       if (ret) {
+               ath10k_warn("Failed to set keepalive maximum unresponsive time: %d\n",
+                           ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int  ath10k_mac_set_rts(struct ath10k_vif *arvif, u32 value)
 {
        struct ath10k *ar = arvif->ar;
@@ -2214,7 +2258,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
        struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
        enum wmi_sta_powersave_param param;
        int ret = 0;
-       u32 value, param_id;
+       u32 value;
        int bit;
        u32 vdev_param;
 
@@ -2307,12 +2351,12 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                        goto err_vdev_delete;
                }
 
-               param_id = ar->wmi.pdev_param->sta_kickout_th;
-
-               /* Disable STA KICKOUT functionality in FW */
-               ret = ath10k_wmi_pdev_set_param(ar, param_id, 0);
-               if (ret)
-                       ath10k_warn("Failed to disable STA KICKOUT\n");
+               ret = ath10k_mac_set_kickout(arvif);
+               if (ret) {
+                       ath10k_warn("Failed to set kickout parameters: %d\n",
+                                   ret);
+                       goto err_peer_delete;
+               }
        }
 
        if (arvif->vdev_type == WMI_VDEV_TYPE_STA) {
index f49a84276b9b317675e8146e2dc3c491c19bfc0c..f0969cd8350fffad77b3a8cc1d73a65705fc652b 100644 (file)
@@ -1116,7 +1116,27 @@ static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
 static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
                                              struct sk_buff *skb)
 {
-       ath10k_dbg(ATH10K_DBG_WMI, "WMI_PEER_STA_KICKOUT_EVENTID\n");
+       struct wmi_peer_sta_kickout_event *ev;
+       struct ieee80211_sta *sta;
+
+       ev = (struct wmi_peer_sta_kickout_event *)skb->data;
+
+       ath10k_dbg(ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
+                  ev->peer_macaddr.addr);
+
+       rcu_read_lock();
+
+       sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
+       if (!sta) {
+               ath10k_warn("Spurious quick kickout for STA %pM\n",
+                           ev->peer_macaddr.addr);
+               goto exit;
+       }
+
+       ieee80211_report_low_ack(sta, 10);
+
+exit:
+       rcu_read_unlock();
 }
 
 /*
index 4b5e7d3d32b62ff221992c6175db1d53f718b91e..9dc90c5dd0e4168871fe7788fe4ddea9a53197c7 100644 (file)
@@ -4039,6 +4039,10 @@ struct wmi_chan_info_event {
        __le32 cycle_count;
 } __packed;
 
+struct wmi_peer_sta_kickout_event {
+       struct wmi_mac_addr peer_macaddr;
+} __packed;
+
 #define WMI_CHAN_INFO_FLAG_COMPLETE BIT(0)
 
 /* FIXME: empirically extrapolated */