[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)