diff options
| author | Olivier Louvignes <olivier@mgcrea.io> | 2026-10-26 09:33:23 +0100 |
|---|---|---|
| committer | Ulf Hansson <ulfh@kernel.org> | 2026-10-29 15:19:29 +0100 |
| commit | b626aeb4fa7e4fdfbbabc5e4ae186b8af23d1a0e (patch) | |
| tree | b4751081f435175c5ae24617de7584c95cb7408a | |
| parent | bbd6715bd06fa265ebdef15baa722b2ce197a360 (diff) | |
| download | linux-next-b626aeb4fa7e4fdfbbabc5e4ae186b8af23d1a0e.tar.gz linux-next-b626aeb4fa7e4fdfbbabc5e4ae186b8af23d1a0e.zip | |
mmc: jz4740: Remove the host before resetting the controller
jz4740_mmc_remove() masks every interrupt and resets the controller
before mmc_remove_host(), which removes the card and lets the card's
driver send its last commands. Those commands then run on a controller
that was just reset, and can wait out the driver's 5 s request timeout.
With an SDIO card that cost 5 s on every unbind: on a HiBy R1 (Ingenic
X1600, a BCM43430A1 driven by brcmfmac), the CMD52 that
sdio_release_irq() sends from brcmfmac's remove waited 5.1 s. The
command had finished (END_CMD_RES set in MSC_STAT), but MSC_IMASK read
0xffffffff although the request had unmasked END_CMD_RES. MSC_STAT can
still show IS_RESETTING after jz4740_mmc_reset() returns, so the reset
most likely completed after that write and undid it.
Remove the host first, then quiesce the controller, as other host
drivers do. On the R1, unbinding the Wi-Fi's MSC now takes 0.65 s.
Fixes: 61bfbdb85687 ("MMC: Add support for the controller on JZ4740 SoCs.")
Cc: stable@vger.kernel.org
Signed-off-by: Olivier Louvignes <olivier@mgcrea.io>
Signed-off-by: Ulf Hansson <ulfh@kernel.org>
| -rw-r--r-- | drivers/mmc/host/jz4740_mmc.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 6a3c26b7c82d..923cf1450de5 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -1151,12 +1151,13 @@ static void jz4740_mmc_remove(struct platform_device *pdev) { struct jz4740_mmc_host *host = platform_get_drvdata(pdev); + /* The card's driver may still send commands as it goes */ + mmc_remove_host(host->mmc); + timer_delete_sync(&host->timeout_timer); jz4740_mmc_set_irq_enabled(host, 0xff, false); jz4740_mmc_reset(host); - mmc_remove_host(host->mmc); - free_irq(host->irq, host); if (host->use_dma) |
