On 11-10-2026 18:42, Igor Opaniuk wrote:
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.

Signed-off-by: Igor Opaniuk <[email protected]>
---
  drivers/mmc/sdhci.c | 10 ++++++++++
  1 file changed, 10 insertions(+)

diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 962a99cd05a..916c7434bbc 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -306,6 +306,16 @@ static int sdhci_send_command(struct mmc *mmc, struct 
mmc_cmd *cmd,
                if (stat & SDHCI_INT_ERROR)
                        break;
+ /*
+                * 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.
+                */
+               if ((stat & mask) == mask)
+                       break;
+

I think its better to move this below the BROKEN_R1B block. For a
no-data R1B command, this now breaks out and calls sdhci_cmd_done()
when RESPONSE|DATA_END are set. The quirk currently returns success
directly once DAT is idle, without reading the response.


                if (host->quirks & SDHCI_QUIRK_BROKEN_R1B &&
                    cmd->resp_type & MMC_RSP_BUSY && !data) {
                        unsigned int state =


Reply via email to