carl9170: fix spurious restart due to high latency
authorChristian Lamparter <chunkeey@googlemail.com>
Fri, 29 Oct 2010 21:26:13 +0000 (23:26 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 15 Nov 2010 18:25:32 +0000 (13:25 -0500)
RX Stress tests of unidirectional bulk traffic with
bitrates of up to 220Mbit/s have revealed that the
fatal-event recovery logic [which was solely triggered
by an out-of-rx-buffer situation] is too aggressive.

The new method now "pings" the device and then
decides - based on the response - whenever
a restart is needed or not.

Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/carl9170/carl9170.h
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/usb.c

index b69d31972c773819da71afdff810e49375385164..d07ff7f2fd92d653103538b86353c6c986f9aca9 100644 (file)
@@ -215,7 +215,7 @@ enum carl9170_restart_reasons {
        CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS,
        CARL9170_RR_WATCHDOG,
        CARL9170_RR_STUCK_TX,
-       CARL9170_RR_SLOW_SYSTEM,
+       CARL9170_RR_UNRESPONSIVE_DEVICE,
        CARL9170_RR_COMMAND_TIMEOUT,
        CARL9170_RR_TOO_MANY_PHY_ERRORS,
        CARL9170_RR_LOST_RSP,
@@ -287,6 +287,7 @@ struct ar9170 {
 
        /* reset / stuck frames/queue detection */
        struct work_struct restart_work;
+       struct work_struct ping_work;
        unsigned int restart_counter;
        unsigned long queue_stop_timeout[__AR9170_NUM_TXQ];
        unsigned long max_queue_stop_timeout[__AR9170_NUM_TXQ];
index d521bc2b0496b37fa30c34cba2f26609d6a4fb5e..4ae6a584907618d4b45b0273615c606c33600267 100644 (file)
@@ -428,6 +428,7 @@ static void carl9170_cancel_worker(struct ar9170 *ar)
        cancel_delayed_work_sync(&ar->led_work);
 #endif /* CONFIG_CARL9170_LEDS */
        cancel_work_sync(&ar->ps_work);
+       cancel_work_sync(&ar->ping_work);
        cancel_work_sync(&ar->ampdu_work);
 }
 
@@ -533,6 +534,21 @@ void carl9170_restart(struct ar9170 *ar, const enum carl9170_restart_reasons r)
         */
 }
 
+static void carl9170_ping_work(struct work_struct *work)
+{
+       struct ar9170 *ar = container_of(work, struct ar9170, ping_work);
+       int err;
+
+       if (!IS_STARTED(ar))
+               return;
+
+       mutex_lock(&ar->mutex);
+       err = carl9170_echo_test(ar, 0xdeadbeef);
+       if (err)
+               carl9170_restart(ar, CARL9170_RR_UNRESPONSIVE_DEVICE);
+       mutex_unlock(&ar->mutex);
+}
+
 static int carl9170_init_interface(struct ar9170 *ar,
                                   struct ieee80211_vif *vif)
 {
@@ -1614,6 +1630,7 @@ void *carl9170_alloc(size_t priv_size)
                skb_queue_head_init(&ar->tx_pending[i]);
        }
        INIT_WORK(&ar->ps_work, carl9170_ps_work);
+       INIT_WORK(&ar->ping_work, carl9170_ping_work);
        INIT_WORK(&ar->restart_work, carl9170_restart_work);
        INIT_WORK(&ar->ampdu_work, carl9170_ampdu_work);
        INIT_DELAYED_WORK(&ar->tx_janitor, carl9170_tx_janitor);
index d8607f4c144d80741f26eb133323aff5cebe936c..ddf5373ee689cff0f166cfffd8c744a4cf61dff4 100644 (file)
@@ -431,7 +431,7 @@ static void carl9170_usb_rx_complete(struct urb *urb)
                         * device.
                         */
 
-                       carl9170_restart(ar, CARL9170_RR_SLOW_SYSTEM);
+                       ieee80211_queue_work(ar->hw, &ar->ping_work);
                }
        } else {
                /*