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 <arik@wizery.com> Signed-off-by: Eyal Shapira <eyal@wizery.com> Signed-off-by: Luciano Coelho <coelho@ti.com>
This commit is contained in:
Родитель
7a50bdfb81
Коммит
6c15c1aae2
|
@ -133,24 +133,27 @@ fail:
|
||||||
* Poll the mailbox event field until any of the bits in the mask is set or a
|
* Poll the mailbox event field until any of the bits in the mask is set or a
|
||||||
* timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
|
* 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 *events_vector;
|
||||||
u32 event;
|
u32 event;
|
||||||
unsigned long timeout;
|
unsigned long timeout_time;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
*timeout = false;
|
||||||
|
|
||||||
events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
|
events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA);
|
||||||
if (!events_vector)
|
if (!events_vector)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
|
timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (time_after(jiffies, timeout)) {
|
if (time_after(jiffies, timeout_time)) {
|
||||||
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
|
wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
|
||||||
(int)mask);
|
(int)mask);
|
||||||
ret = -ETIMEDOUT;
|
*timeout = true;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,9 +183,10 @@ out:
|
||||||
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
bool timeout = false;
|
||||||
|
|
||||||
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
|
ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout);
|
||||||
if (ret != 0) {
|
if (ret != 0 || timeout) {
|
||||||
wl12xx_queue_recovery_work(wl);
|
wl12xx_queue_recovery_work(wl);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1435,6 +1439,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid)
|
||||||
{
|
{
|
||||||
struct wl12xx_cmd_remove_peer *cmd;
|
struct wl12xx_cmd_remove_peer *cmd;
|
||||||
int ret;
|
int ret;
|
||||||
|
bool timeout = false;
|
||||||
|
|
||||||
wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid);
|
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;
|
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
|
* 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,
|
if (ret)
|
||||||
PEER_REMOVE_COMPLETE_EVENT_ID);
|
wl12xx_queue_recovery_work(wl);
|
||||||
|
|
||||||
out_free:
|
out_free:
|
||||||
kfree(cmd);
|
kfree(cmd);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче