ath9k_htc: Fix beacon miss under heavy load
Sujith Manoharan [Wed, 13 Apr 2011 05:53:44 +0000 (10:53 +0530)]
Transmission of beacons becomes erratic when TX load
is high, since the latency involved in the generation
of a SWBA interrupt on the target to the actual sending
of a beacon is quite high for USB devices.

Fix this by adjusting the beacon response time.

Signed-off-by: Sujith Manoharan <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c

index a072a9e..133fc6d 100644 (file)
@@ -358,6 +358,13 @@ struct ath_led {
 
 #define BSTUCK_THRESHOLD 10
 
+/*
+ * Adjust these when the max. no of beaconing interfaces is
+ * increased.
+ */
+#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */
+#define MIN_SWBA_RESPONSE     10 /* in TUs */
+
 struct htc_beacon_config {
        struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
        u16 beacon_interval;
index c96779c..48bc288 100644 (file)
@@ -198,6 +198,15 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
        intval /= ATH9K_HTC_MAX_BCN_VIF;
        nexttbtt = intval;
 
+       /*
+        * To reduce beacon misses under heavy TX load,
+        * set the beacon response time to a larger value.
+        */
+       if (intval > DEFAULT_SWBA_RESPONSE)
+               priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+       else
+               priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
        if (priv->op_flags & OP_TSF_RESET) {
                ath9k_hw_reset_tsf(priv->ah);
                priv->op_flags &= ~OP_TSF_RESET;
@@ -216,9 +225,10 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
                imask |= ATH9K_INT_SWBA;
 
        ath_dbg(common, ATH_DBG_CONFIG,
-               "AP Beacon config, intval: %d, nexttbtt: %u "
+               "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d "
                "imask: 0x%x\n",
-               bss_conf->beacon_interval, nexttbtt, imask);
+               bss_conf->beacon_interval, nexttbtt,
+               priv->ah->config.sw_beacon_response_time, imask);
 
        ath9k_htc_beaconq_config(priv);
 
@@ -252,12 +262,22 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
                nexttbtt += intval;
        } while (nexttbtt < tsftu);
 
+       /*
+        * Only one IBSS interfce is allowed.
+        */
+       if (intval > DEFAULT_SWBA_RESPONSE)
+               priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+       else
+               priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
        if (priv->op_flags & OP_ENABLE_BEACON)
                imask |= ATH9K_INT_SWBA;
 
        ath_dbg(common, ATH_DBG_CONFIG,
-               "IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n",
-               bss_conf->beacon_interval, nexttbtt, imask);
+               "IBSS Beacon config, intval: %d, nexttbtt: %u, "
+               "resp_time: %d, imask: 0x%x\n",
+               bss_conf->beacon_interval, nexttbtt,
+               priv->ah->config.sw_beacon_response_time, imask);
 
        WMI_CMD(WMI_DISABLE_INTR_CMDID);
        ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
@@ -317,6 +337,7 @@ static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
 static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
                                  int slot)
 {
+       struct ath_common *common = ath9k_hw_common(priv->ah);
        struct ieee80211_vif *vif;
        struct ath9k_htc_vif *avp;
        struct tx_beacon_header beacon_hdr;
@@ -325,6 +346,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
        struct ieee80211_mgmt *mgmt;
        struct sk_buff *beacon;
        u8 *tx_fhdr;
+       int ret;
 
        memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
        memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
@@ -367,7 +389,14 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
        tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
        memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
 
-       htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
+       ret = htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
+       if (ret != 0) {
+               if (ret == -ENOMEM) {
+                       ath_dbg(common, ATH_DBG_BSTUCK,
+                               "Failed to send beacon, no free TX buffer\n");
+               }
+               dev_kfree_skb_any(beacon);
+       }
 
        spin_unlock_bh(&priv->beacon_lock);
 }