wlcore: queue recovery in case of bus errors during cmd_remove_peer
authorEyal Shapira <eyal@wizery.com>
Tue, 26 Jun 2012 07:41:16 +0000 (10:41 +0300)
committerLuciano Coelho <coelho@ti.com>
Tue, 26 Jun 2012 17:30:37 +0000 (20:30 +0300)
Following the addition of propagating errors from the bus ops
there's a need to distinguish between bus errors (including timeout)
and a legitimate timeout occuring in cmd_wait_for_event_or_timeout.
In case of real bus errors we need to queue recovery even in cases
where a timeout on a response from the FW to a command is acceptable.

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

index 84dd808f65fae7185022f2f90968c8c59d8b9af1..ef139383ee9357b6f99b47b4e3b42bd5a9bfdd10 100644 (file)
@@ -133,24 +133,27 @@ fail:
  * Poll the mailbox event field until any of the bits in the mask is set or a
  * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
  */
-static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
+static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
+                                               u32 mask, bool *timeout)
 {
        u32 *events_vector;
        u32 event;
-       unsigned long timeout;
+       unsigned long timeout_time;
        int ret = 0;
 
+       *timeout = false;
+
        events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
        if (!events_vector)
                return -ENOMEM;
 
-       timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
+       timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
 
        do {
-               if (time_after(jiffies, timeout)) {
+               if (time_after(jiffies, timeout_time)) {
                        wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
                                     (int)mask);
-                       ret = -ETIMEDOUT;
+                       *timeout = true;
                        goto out;
                }
 
@@ -180,9 +183,10 @@ out:
 static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
 {
        int ret;
+       bool timeout = false;
 
-       ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
-       if (ret != 0) {
+       ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
+       if (ret != 0 || timeout) {
                wl12xx_queue_recovery_work(wl);
                return ret;
        }
@@ -1435,6 +1439,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
 {
        struct wl12xx_cmd_remove_peer *cmd;
        int ret;
+       bool timeout = false;
 
        wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
 
@@ -1455,12 +1460,16 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
                goto out_free;
        }
 
+       ret = wl1271_cmd_wait_for_event_or_timeout(wl,
+                                          PEER_REMOVE_COMPLETE_EVENT_ID,
+                                          &timeout);
        /*
         * We are ok with a timeout here. The event is sometimes not sent
-        * due to a firmware bug.
+        * due to a firmware bug. In case of another error (like SDIO timeout)
+        * queue a recovery.
         */
-       wl1271_cmd_wait_for_event_or_timeout(wl,
-                                            PEER_REMOVE_COMPLETE_EVENT_ID);
+       if (ret)
+               wl12xx_queue_recovery_work(wl);
 
 out_free:
        kfree(cmd);