Re: [PATCH] mmc: mtk-sd: report DMA stop timeouts as data errors
From: Ulf Hansson
Date: Wed Sep 02 2026 - 12:27:37 EST
On Thu, Jun 25, 2026 at 2:35 AM Pengpeng Hou <pengpeng@xxxxxxxxxxx> wrote:
>
> 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>
Hi Pengpeng,
Did you verify this on HW? If not, I am leaving this to the mediatek
folkz to confirm before applying.
Kind regards
Uffe
> ---
> 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)
>