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 --- --- 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);