wlcore: force recovery on resume if suspended without recovering
authorArik Nemtsov <arik@wizery.com>
Thu, 21 Jun 2012 15:10:49 +0000 (18:10 +0300)
committerLuciano Coelho <coelho@ti.com>
Sat, 23 Jun 2012 06:32:31 +0000 (09:32 +0300)
If an error is detected after mac80211 is already suspended, the recovery
work will not be queued. This will leave the driver in a bad state on
resume.

Detect this in the resume op and re-queue a recovery.

Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wlcore/main.c

index 0df28d5..0b51522 100644 (file)
@@ -1707,7 +1707,7 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
        struct wl1271 *wl = hw->priv;
        struct wl12xx_vif *wlvif;
        unsigned long flags;
-       bool run_irq_work = false;
+       bool run_irq_work = false, pending_recovery;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
                     wl->wow_enabled);
@@ -1723,17 +1723,33 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
                run_irq_work = true;
        spin_unlock_irqrestore(&wl->wl_lock, flags);
 
+       /* test the recovery flag before calling any SDIO functions */
+       pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
+                                   &wl->flags);
+
        if (run_irq_work) {
                wl1271_debug(DEBUG_MAC80211,
                             "run postponed irq_work directly");
-               wl1271_irq(0, wl);
+
+               /* don't talk to the HW if recovery is pending */
+               if (!pending_recovery)
+                       wl1271_irq(0, wl);
+
                wlcore_enable_interrupts(wl);
        }
 
        mutex_lock(&wl->mutex);
+       if (pending_recovery) {
+               wl1271_warning("queuing forgotten recovery on resume");
+               ieee80211_queue_work(wl->hw, &wl->recovery_work);
+               goto out;
+       }
+
        wl12xx_for_each_wlvif(wl, wlvif) {
                wl1271_configure_resume(wl, wlvif);
        }
+
+out:
        wl->wow_enabled = false;
        mutex_unlock(&wl->mutex);