wlcore: Disable interrupts while recovering
authorIdo Yariv <ido@wizery.com>
Sun, 20 May 2012 22:10:11 +0000 (01:10 +0300)
committerLuciano Coelho <coelho@ti.com>
Fri, 22 Jun 2012 07:46:34 +0000 (10:46 +0300)
In case a recovery is initiated, the FW can no longer be trusted, and
the driver should not handle any new FW events.

Disable the interrupt handler when a recovery is scheduled and balance
it back in the op_stop callback.

Signed-off-by: Ido Yariv <ido@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/ti/wlcore/io.c
drivers/net/wireless/ti/wlcore/io.h
drivers/net/wireless/ti/wlcore/main.c

index 7cd0081aede5f77cf6279045240d4622afe389cb..62d6573899964b9c94a7eb3f57b79eb2c155e8d4 100644 (file)
@@ -48,6 +48,12 @@ void wlcore_disable_interrupts(struct wl1271 *wl)
 }
 EXPORT_SYMBOL_GPL(wlcore_disable_interrupts);
 
+void wlcore_disable_interrupts_nosync(struct wl1271 *wl)
+{
+       disable_irq_nosync(wl->irq);
+}
+EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync);
+
 void wlcore_enable_interrupts(struct wl1271 *wl)
 {
        enable_irq(wl->irq);
index 404cb14458ebab16727389bbeb717550186eceb5..bbaf7117204e47a74fe3d2758e415655b38adc93 100644 (file)
@@ -45,6 +45,7 @@
 struct wl1271;
 
 void wlcore_disable_interrupts(struct wl1271 *wl);
+void wlcore_disable_interrupts_nosync(struct wl1271 *wl);
 void wlcore_enable_interrupts(struct wl1271 *wl);
 
 void wl1271_io_reset(struct wl1271 *wl);
index 78edc58da2102af113e51261a6b336451e9e0430..c94351a924191b3ea12ea4771eddb1478eddee4e 100644 (file)
@@ -743,8 +743,11 @@ out:
 
 void wl12xx_queue_recovery_work(struct wl1271 *wl)
 {
-       if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+       /* Avoid a recursive recovery */
+       if (!test_and_set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) {
+               wlcore_disable_interrupts_nosync(wl);
                ieee80211_queue_work(wl->hw, &wl->recovery_work);
+       }
 }
 
 size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen)
@@ -848,9 +851,6 @@ static void wl1271_recovery_work(struct work_struct *work)
        if (wl->state != WL1271_STATE_ON || wl->plt)
                goto out_unlock;
 
-       /* Avoid a recursive recovery */
-       set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
-
        wl12xx_read_fwlog_panic(wl);
 
        /* change partitions momentarily so we can read the FW pc */
@@ -902,8 +902,6 @@ static void wl1271_recovery_work(struct work_struct *work)
        mutex_unlock(&wl->mutex);
        wl1271_op_stop(wl->hw);
 
-       clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
-
        ieee80211_restart_hw(wl->hw);
 
        /*
@@ -1706,6 +1704,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        wlcore_disable_interrupts(wl);
        mutex_lock(&wl->mutex);
        if (wl->state == WL1271_STATE_OFF) {
+               if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
+                                       &wl->flags))
+                       wlcore_enable_interrupts(wl);
+
                mutex_unlock(&wl->mutex);
 
                /*
@@ -1737,6 +1739,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw)
        mutex_lock(&wl->mutex);
 
        wl1271_power_off(wl);
+       /*
+        * In case a recovery was scheduled, interrupts were disabled to avoid
+        * an interrupt storm. Now that the power is down, it is safe to
+        * re-enable interrupts to balance the disable depth
+        */
+       if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+               wlcore_enable_interrupts(wl);
 
        wl->band = IEEE80211_BAND_2GHZ;