sdhci_send_command() polls the interrupt status and gives up after
SDHCI_READ_STATUS_TIMEOUT, but it evaluates the timeout before it looks at
the status it has just read. When a single status read takes longer than
the timeout, the command is reported as timed out although the response
and transfer-complete bits are already set, and the caller aborts an
otherwise successful transfer.
This happens on QEMU's SDHCI/eMMC model under TCG: a large ADMA transfer
runs in a timer callback while holding the big QEMU lock, so U-Boot's next
MMIO read blocks for seconds and the subsequent command appears to have
timed out ("Timeout for status update: 00000003 00000001").
Check for completion first and only then for the timeout. The check sits
after the SDHCI_QUIRK_BROKEN_R1B handling so that, for a busy command
without data on such a controller, the quirk keeps returning as soon as
the DAT line is idle without reading the response, exactly as before.
Reviewed-by: Peng Fan <[email protected]>
Signed-off-by: Igor Opaniuk <[email protected]>
---
Changes in v2:
- move the completion check below the SDHCI_QUIRK_BROKEN_R1B block so
that the quirk keeps returning as soon as DAT is idle, without reading
the response, for a busy command without data (Tanmay Kathpalia)
- add Peng Fan's Reviewed-by from v1; only the position of the check
changed
- Link to v1:
https://patch.msgid.link/20261011-upstream-mmc_sdhci_timeout_b4-v1-1-f33c02445...@oss.qualcomm.com
---
drivers/mmc/sdhci.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 962a99cd05a..97de02c262c 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -315,6 +315,18 @@ static int sdhci_send_command(struct mmc *mmc, struct
mmc_cmd *cmd,
return 0;
}
+ /*
+ * Check completion before the timeout: the status read itself
+ * may have taken longer than SDHCI_READ_STATUS_TIMEOUT (for
+ * example when an emulated controller performs a long DMA
+ * transfer while holding the guest's MMIO path), and a command
+ * that has completed must not be reported as timed out. The
+ * BROKEN_R1B quirk above keeps precedence and returns as soon
+ * as the DAT line is idle, as it did before.
+ */
+ if ((stat & mask) == mask)
+ break;
+
if (get_timer(start) >= SDHCI_READ_STATUS_TIMEOUT) {
log_warning("Timeout for status update: %08x %08x\n",
stat, mask);
---
base-commit: ed869863c7e2aca50d57a05d843830dd843138c4
change-id: 20261011-upstream-mmc_sdhci_timeout_b4-3eef4a4546bc
Best regards,
--
Igor Opaniuk <[email protected]>