wl12xx: Avoid recovery while one is already in progress
authorIdo Yariv <ido@wizery.com>
Mon, 6 Jun 2011 11:57:05 +0000 (14:57 +0300)
committerLuciano Coelho <coelho@ti.com>
Mon, 27 Jun 2011 12:05:15 +0000 (15:05 +0300)
During recovery work commands sent to the FW could fail and schedule
additional recovery work. Since the chip is going to be powered off,
avoid recursive recoveries.

Signed-off-by: Ido Yariv <ido@wizery.com>
Signed-off-by: Arik Nemtsov <arik@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/testmode.c
drivers/net/wireless/wl12xx/wl12xx.h

index cdcb324093a5e3f8fca286f7e4f733a368c0cf45..f3d332d11f813e480a2b978117129d492b57f16c 100644 (file)
@@ -105,7 +105,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
 
 fail:
        WARN_ON(1);
-       ieee80211_queue_work(wl->hw, &wl->recovery_work);
+       wl12xx_queue_recovery_work(wl);
        return ret;
 }
 
@@ -356,7 +356,7 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
 
        ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
        if (ret != 0) {
-               ieee80211_queue_work(wl->hw, &wl->recovery_work);
+               wl12xx_queue_recovery_work(wl);
                return ret;
        }
 
index c3f19463474d1121cd4da0e892e227c63da4880e..da21270183003f7202549310c36705132b13dd8f 100644 (file)
@@ -306,7 +306,7 @@ static ssize_t start_recovery_write(struct file *file,
        struct wl1271 *wl = file->private_data;
 
        mutex_lock(&wl->mutex);
-       ieee80211_queue_work(wl->hw, &wl->recovery_work);
+       wl12xx_queue_recovery_work(wl);
        mutex_unlock(&wl->mutex);
 
        return count;
index 2c03b4716d3f75c1b24deb74ef67af5442493ce0..6926d0a3e5c6ac26b0cb5f1c70d7f5236d513cc5 100644 (file)
@@ -937,7 +937,7 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
                if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) {
                        wl1271_error("watchdog interrupt received! "
                                     "starting recovery.");
-                       ieee80211_queue_work(wl->hw, &wl->recovery_work);
+                       wl12xx_queue_recovery_work(wl);
 
                        /* restarting the chip. ignore any other interrupt. */
                        goto out;
@@ -1099,6 +1099,12 @@ out:
        return ret;
 }
 
+void wl12xx_queue_recovery_work(struct wl1271 *wl)
+{
+       if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags))
+               ieee80211_queue_work(wl->hw, &wl->recovery_work);
+}
+
 static void wl1271_recovery_work(struct work_struct *work)
 {
        struct wl1271 *wl =
@@ -1109,6 +1115,9 @@ static void wl1271_recovery_work(struct work_struct *work)
        if (wl->state != WL1271_STATE_ON)
                goto out;
 
+       /* Avoid a recursive recovery */
+       set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
+
        wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
                    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 
@@ -1125,6 +1134,9 @@ static void wl1271_recovery_work(struct work_struct *work)
 
        /* reboot the chipset */
        __wl1271_op_remove_interface(wl, false);
+
+       clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags);
+
        ieee80211_restart_hw(wl->hw);
 
        /*
index 5116db0826f9076303c46475d797b7f947f37f14..3e68a664c9de220a58d7b42af96783c0021dacf9 100644 (file)
@@ -118,7 +118,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
                        &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
                if (ret == 0) {
                        wl1271_error("ELP wakeup timeout!");
-                       ieee80211_queue_work(wl->hw, &wl->recovery_work);
+                       wl12xx_queue_recovery_work(wl);
                        ret = -ETIMEDOUT;
                        goto err;
                } else if (ret < 0) {
index cb84dd5edf4d7a4b98d5a3902234f5835d829f59..5e5c66dd06d592e29ec2d16386a8d402533d789d 100644 (file)
@@ -62,7 +62,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
 
        if (wl->scan.failed) {
                wl1271_info("Scan completed due to error.");
-               ieee80211_queue_work(wl->hw, &wl->recovery_work);
+               wl12xx_queue_recovery_work(wl);
        }
 
 out:
index da351d7cd1f29ff3772f53ac27c2faad561e560d..5d5e1ef87206a4e1722510084ba4cab2783cf0bd 100644 (file)
@@ -260,7 +260,7 @@ static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[])
 {
        wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover");
 
-       ieee80211_queue_work(wl->hw, &wl->recovery_work);
+       wl12xx_queue_recovery_work(wl);
 
        return 0;
 }
index bbf4ee6d41029ce85062d55a1f15fde7e1b7df72..754a16ce5bc017ff39e68296747a8d13b37aa34a 100644 (file)
@@ -361,6 +361,7 @@ enum wl12xx_flags {
        WL1271_FLAG_PENDING_WORK,
        WL1271_FLAG_SOFT_GEMINI,
        WL1271_FLAG_RX_STREAMING_STARTED,
+       WL1271_FLAG_RECOVERY_IN_PROGRESS,
 };
 
 struct wl1271_link {
@@ -612,6 +613,7 @@ struct wl1271_station {
 int wl1271_plt_start(struct wl1271 *wl);
 int wl1271_plt_stop(struct wl1271 *wl);
 int wl1271_recalc_rx_streaming(struct wl1271 *wl);
+void wl12xx_queue_recovery_work(struct wl1271 *wl);
 
 #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */