[PATCH] mmc: mtk-sd: report DMA stop timeouts as data errors

Ulf Hansson ulf.hansson at oss.qualcomm.com
Wed Sep 2 09:07:23 PDT 2026


On Thu, Jun 25, 2026 at 2:35 AM Pengpeng Hou <pengpeng at iscas.ac.cn> 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 at iscas.ac.cn>

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



More information about the linux-arm-kernel mailing list