From 6c15c1aae206dc275a948a5e50f965c2382c6866 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 26 Jun 2012 10:41:16 +0300 Subject: [PATCH] wlcore: queue recovery in case of bus errors during cmd_remove_peer 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 Signed-off-by: Eyal Shapira Signed-off-by: Luciano Coelho --- drivers/net/wireless/ti/wlcore/cmd.c | 29 ++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 84dd808f65fa..ef139383ee93 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -133,24 +133,27 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, * 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 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) 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); -- GitLab