[PATCH] mmc: mtk-sd: report DMA stop timeouts as data errors
From: Pengpeng Hou
Date: Wed Jun 24 2026 - 20:37:08 EST
msdc_data_xfer_done() stops the DMA engine before completing a data
request, but it only logs failures from the DMA stop and DMA-inactive
polls.
When the interrupt status also carries MSDC_INT_XFER_COMPL, the function
can still report the full data length as transferred even though the DMA
engine did not confirm that it stopped or became inactive.
Treat DMA stop/inactive timeouts as data errors. This reuses the existing
reset/error path and prevents a timed out DMA stop from being reported as a
successful full-length transfer.
Signed-off-by: Pengpeng Hou <pengpeng@xxxxxxxxxxx>
---
drivers/mmc/host/mtk-sd.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index b2680cc05..e3caa9c32 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -1583,7 +1583,7 @@ static void msdc_data_xfer_done(struct msdc_host *host, u32 events,
| MSDC_INT_DMA_BDCSERR | MSDC_INT_DMA_GPDCSERR
| MSDC_INT_DMA_PROTECT);
u32 val;
- int ret;
+ int dma_err = 0, ret;
spin_lock_irqsave(&host->lock, flags);
done = !host->data;
@@ -1603,18 +1603,23 @@ static void msdc_data_xfer_done(struct msdc_host *host, u32 events,
ret = readl_poll_timeout_atomic(host->base + MSDC_DMA_CTRL, val,
!(val & MSDC_DMA_CTRL_STOP), 1, 20000);
- if (ret)
+ if (ret) {
dev_dbg(host->dev, "DMA stop timed out\n");
+ dma_err = ret;
+ }
ret = readl_poll_timeout_atomic(host->base + MSDC_DMA_CFG, val,
!(val & MSDC_DMA_CFG_STS), 1, 20000);
- if (ret)
+ if (ret) {
dev_dbg(host->dev, "DMA inactive timed out\n");
+ dma_err = ret;
+ }
sdr_clr_bits(host->base + MSDC_INTEN, data_ints_mask);
dev_dbg(host->dev, "DMA stop\n");
- if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) {
+ if (!dma_err && (events & MSDC_INT_XFER_COMPL) &&
+ (!stop || !stop->error)) {
data->bytes_xfered = data->blocks * data->blksz;
} else {
dev_dbg(host->dev, "interrupt events: %x\n", events);
@@ -1622,7 +1627,9 @@ static void msdc_data_xfer_done(struct msdc_host *host, u32 events,
host->error |= REQ_DAT_ERR;
data->bytes_xfered = 0;
- if (events & MSDC_INT_DATTMO)
+ if (dma_err)
+ data->error = -ETIMEDOUT;
+ else if (events & MSDC_INT_DATTMO)
data->error = -ETIMEDOUT;
else if (events & MSDC_INT_DATCRCERR)
data->error = -EILSEQ;
--
2.50.1 (Apple Git-155)