Commit 6c15c1aa authored by Eyal Shapira's avatar Eyal Shapira Committed by Luciano Coelho
Browse files

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: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarEyal Shapira <eyal@wizery.com>
Signed-off-by: default avatarLuciano Coelho <coelho@ti.com>
parent 7a50bdfb
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -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);