[PATCH] wifi: brcmfmac: schedule bus reset when the device is unresponsive after wake

Max Engel <[email protected]>
Newsgroups org.kernel.vger.linux-wireless,dev.linux.lists.brcm80211
Message-ID <[email protected]>
On the PINE64 PineNote (CYW43455 / BCM4345C0 on an rk3566 SDIO bus,
keep-power-in-suspend), the chip intermittently loses all state across a
system suspend: the suspend-entry KSO write succeeds cleanly, but at the
first post-resume wake attempt every SLEEPCSR read returns 0xff
(all-ones, i.e. the device is electrically absent from the bus) and KSO
retries exhaust with -ETIMEDOUT. From there the driver limps (halting
operation after repeated backplane failures), the interface never
recovers, and a module reload fails to re-probe all three SDIO
functions. The only working in-kernel remedy is the existing bus reset
worker (mmc_hw_reset -> pwrseq WL_REG_ON power cycle), measured on this
hardware to recover the device in ~7 s without a reboot.

That worker's only SDIO trigger today is the firmware-halt mailbox
interrupt (HMB_DATA_FWHALT) - which a chip that is off the bus can never
deliver. Schedule the same worker from the KSO wake path when the
failure is conclusive: wake direction, retries exhausted, and the CSR
reading back all-ones.

Repeated failures are harmless: schedule_work() on an already-queued
work item is a no-op, and the reset tears down and re-probes the device.

Field reports of the same class of wedge exist beyond this board
(PNDeb/pinenote-debian-image#105; openwrt#23069 explicitly requests a
host-triggered reset path).

Signed-off-by: Max Engel <[email protected]>
---
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -770,6 +770,28 @@
 	if (try_cnt > MAX_KSO_ATTEMPTS)
 		brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err);
 
+	/* A wake attempt that gives up (whether by exhausting the KSO
+	 * retries or by bailing out on consecutive access errors) with the
+	 * sleep CSR reading back all-ones means the device has dropped off
+	 * the bus entirely, e.g. it lost state across a system suspend
+	 * despite keep-power-in-suspend (observed on CYW43455/BCM4345C0 on
+	 * rk3566). No in-band recovery is possible: the interface is gone
+	 * and a module reload fails to re-probe (-ETIMEDOUT on every
+	 * function). The bus reset worker already performs the only known
+	 * remedy (mmc_hw_reset -> pwrseq WL_REG_ON power cycle), but its
+	 * sole SDIO trigger is the firmware-halt mailbox interrupt, which
+	 * a chip that is off the bus can never deliver. Schedule it from
+	 * here instead.
+	 */
+	if (on && err && rd_val == 0xff) {
+		struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr;
+
+		if (drvr && drvr->bus_reset.func) {
+			brcmf_err("device unresponsive after wake, scheduling bus reset\n");
+			schedule_work(&drvr->bus_reset);
+		}
+	}
+
 	if (on)
 		sdio_retune_release(bus->sdiodev->func1);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.