bes2600: handle multi-function SDIO cards in mmc_hw_reset bus_reset
c5.2 (recover-wedged-firmware-via-mmc-hw-reset) wraps mmc_hw_reset()
and treats any non-zero return as a recovery failure. On
single-function SDIO cards mmc_hw_reset returns 0 after doing the
remove + rescan inline. On multi-function cards (BES2600 has WLAN
func 1 + BT companion func 2) the kernel's mmc_sdio_hw_reset() does
NOT do the rescan: it tears the card down and returns 1 to signal
"caller must trigger rescan".
Field observation on PineTab2 (linux-pinetab2 6.19.10-danctnix1):
when a real LMAC wedge fired bes2600_chrdev_wifi_force_close ->
bes2600_chrdev_do_bus_reset, mmc_hw_reset returned 1, c5.2's wrapper
treated that as "bus_reset failed: 1", logged the error, and gave
up. The card was already removed (mmc2: card 0001 removed) but
nothing scheduled a rescan; wifi (and the BT companion which shares
the same SDIO host) stayed silent until the user rebooted four
minutes later.
Fix:
- Capture the mmc_host pointer before calling mmc_hw_reset (the
card pointer is invalid after the remove).
- On positive return (multi-function path), log informationally
and call mmc_detect_change(host, 0) to schedule a rescan.
Return 0 so callers see the recovery as successful.
- Negative return is still treated as failure as before.
The mmc_detect_change side effect is asynchronous; the chrdev's
wait_event_timeout(probe_done_wq, !sbus_priv) still observes the
remove half synchronously, and the rescan + re-probe runs out of
the host detect work afterwards.
Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
This commit is contained in:
+23
-1
@@ -1810,10 +1810,32 @@ static void bes2600_sdio_halt_device(struct sbus_priv *self)
|
||||
*/
|
||||
static int bes2600_sdio_bus_reset(struct sbus_priv *self)
|
||||
{
|
||||
struct mmc_host *host;
|
||||
int ret;
|
||||
|
||||
if (!self || !self->func || !self->func->card)
|
||||
return -EINVAL;
|
||||
|
||||
return mmc_hw_reset(self->func->card);
|
||||
host = self->func->card->host;
|
||||
ret = mmc_hw_reset(self->func->card);
|
||||
|
||||
/*
|
||||
* On multi-function SDIO cards (BES2600 has WLAN func 1 + BT
|
||||
* companion func 2), mmc_sdio_hw_reset() removes the card and
|
||||
* returns 1 to signal "remove happened, caller must trigger
|
||||
* rescan". The kernel does NOT auto-rescan in this case;
|
||||
* single-function cards take the rescan path inline and return 0.
|
||||
* Treat any non-negative return as success and force a rescan if
|
||||
* mmc_hw_reset signalled the multi-function path - otherwise the
|
||||
* card stays removed indefinitely after a wedge recovery,
|
||||
* leaving wifi (and the BT companion) silent until reboot.
|
||||
*/
|
||||
if (ret > 0) {
|
||||
bes_info("multi-func mmc_hw_reset removed card; scheduling rescan\n");
|
||||
mmc_detect_change(host, 0);
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool bes2600_sdio_wakeup_source(struct sbus_priv *self)
|
||||
|
||||
Reference in New Issue
Block a user