[PATCH v3] mmc: sunxi: reset the controller after an update-clock timeout

From: Tam Do

Date: Wed Oct 28 2026 - 07:49:53 EST


If the clock-update command times out it stays pending in the
controller, and every later clock update times out as well, so the
card cannot be initialised until the next probe.

This happens on an R16 board whose SDIO Wi-Fi holds DAT0 busy while
its supply comes up during the first clock update.

Reset the controller on timeout so the next attempt can succeed. This
runs sunxi_mmc_init_host() with the interrupt enabled for the first
time, so write REG_IMASK from sdio_imask under host->lock, as
sunxi_mmc_enable_sdio_irq() updates both under that lock.

Fixes: 3cbcb16095f9 ("mmc: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Tam Do <tam.do@xxxxxxxxxxxxxxx>
---
v3: take host->lock only around the REG_IMASK write in
sunxi_mmc_init_host(), not across the reset; v2 polled the reset on
jiffies with interrupts off. The return value stays unchecked, as in
sunxi_mmc_runtime_resume(): if the reset itself times out the
controller is wedged either way.
v2: held host->lock across the reset (not posted)
v1: https://lore.kernel.org/all/179307312104.39863.12372814163472848752@xxxxxxxxxxxxxxx/

drivers/mmc/host/sunxi-mmc.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index fe4c0f6d73f3..55313780d06d 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -322,6 +322,7 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)

static int sunxi_mmc_init_host(struct sunxi_mmc_host *host)
{
+ unsigned long flags;
u32 rval;

if (sunxi_mmc_reset_host(host))
@@ -336,7 +337,9 @@ static int sunxi_mmc_init_host(struct sunxi_mmc_host *host)
/* Maximum timeout value */
mmc_writel(host, REG_TMOUT, 0xffffffff);
/* Unmask SDIO interrupt if needed */
+ spin_lock_irqsave(&host->lock, flags);
mmc_writel(host, REG_IMASK, host->sdio_imask);
+ spin_unlock_irqrestore(&host->lock, flags);
/* Clear all pending interrupts */
mmc_writel(host, REG_RINTR, 0xffffffff);
/* Debug register? undocumented */
@@ -688,6 +691,7 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)

if (rval & SDXC_START) {
dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
+ sunxi_mmc_init_host(host);
return -EIO;
}

--
2.39.5