[PATCH v3 2/4] mmc: meson-gx: honour the busy timeout for R1b commands

From: Igor Velkov via B4 Relay

Date: Fri Oct 09 2026 - 13:03:47 EST


From: Igor Velkov <iav@xxxxxx>

For a command without data the driver programs a fixed 1024 ms into the
CMD_CFG timeout field, and for R1b the controller waits for the card to
release busy within that time. The core sends erase and cache flush as
R1b with busy timeouts of up to 60 s and 30 s, and the controller gives
up after one second:

mmc_erase: erase error -110, status 0x0
mmc1: cache flush error -110

Program the timeout from cmd->busy_timeout, kept between 1024 ms, the
fixed value until now, and 32768 ms, the most the field holds, and
rounded up to a power of two. The clamp comes first: MMC_IOC_CMD passes
cmd_timeout_ms from user space straight into busy_timeout, and
roundup_pow_of_two() of a value above 2^31 does not fit in unsigned
int. sdhci takes its command timeout from cmd->busy_timeout in the
same way.

Fixes: 51c5d8447bd7 ("MMC: meson: initial support for GX platforms")
Assisted-by: LLM
Signed-off-by: Igor Velkov <iav@xxxxxx>
---
drivers/mmc/host/meson-gx-mmc.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 06479ba38525..dd246ad63653 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -216,6 +216,20 @@ static unsigned int meson_mmc_get_timeout_msecs(struct mmc_data *data)
return min_t(unsigned int, timeout, SD_EMMC_CMD_TIMEOUT_MAX);
}

+/* For R1b the controller waits for busy to be released within this timeout. */
+static unsigned int meson_mmc_get_cmd_timeout_msecs(struct mmc_command *cmd)
+{
+ unsigned int timeout = cmd->busy_timeout;
+
+ if (!timeout)
+ return SD_EMMC_CMD_TIMEOUT;
+
+ timeout = clamp_t(unsigned int, timeout, SD_EMMC_CMD_TIMEOUT,
+ SD_EMMC_CMD_TIMEOUT_MAX);
+
+ return roundup_pow_of_two(timeout);
+}
+
static struct mmc_command *meson_mmc_get_next_command(struct mmc_command *cmd)
{
if (cmd->opcode == MMC_SET_BLOCK_COUNT && !cmd->error)
@@ -842,7 +856,7 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
cmd_data = host->bounce_dma_addr & CMD_DATA_MASK;
} else {
cmd_cfg |= FIELD_PREP(CMD_CFG_TIMEOUT_MASK,
- ilog2(SD_EMMC_CMD_TIMEOUT));
+ ilog2(meson_mmc_get_cmd_timeout_msecs(cmd)));
}

/* Last descriptor */

--
2.43.0