[PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer completion before reset

Ulf Hansson ulf.hansson at linaro.org
Tue Dec 9 05:47:30 PST 2025


On Fri, 5 Dec 2025 at 09:12, Bough Chen <haibo.chen at nxp.com> wrote:
>
> > -----Original Message-----
> > From: Luke Wang <ziniu.wang_1 at nxp.com>
> > Sent: 2025年12月5日 15:17
> > To: adrian.hunter at intel.com; Bough Chen <haibo.chen at nxp.com>;
> > ulf.hansson at linaro.org
> > Cc: shawnguo at kernel.org; s.hauer at pengutronix.de; kernel at pengutronix.de;
> > festevam at gmail.com; linux-mmc at vger.kernel.org; imx at lists.linux.dev; dl-S32
> > <S32 at nxp.com>; linux-arm-kernel at lists.infradead.org;
> > linux-kernel at vger.kernel.org
> > Subject: [PATCH v2] mmc: sdhci-esdhc-imx: wait for data transfer completion
> > before reset
> >
> > From: Luke Wang <ziniu.wang_1 at nxp.com>
> >
> > On IMX7ULP platforms, certain SD cards (e.g. Kingston Canvas Go! Plus) cause
> > system hangs and reboots during manual tuning. These cards exhibit large gaps
> > (~16us) between tuning command response and data transmission.
> > When cmd CRC errors occur during tuning, the code assumes data errors even
> > tuning data hasn't been fully received and then reset host data circuit.
> >
> > Per IMX7ULP reference manual, reset operations (RESET_DATA/ALL) need to
> > make sure no active data transfers. Previously, resetting while data was in-flight
> > would clear data circuit, including ADMA/SDMA address, causing data to be
> > transmitted to incorrect memory address. This patch adds polling for data
> > transfer completion before executing resets.
> >
> > Signed-off-by: Luke Wang <ziniu.wang_1 at nxp.com>
> > ---
> > v2: amend commit message
> > ---
> >  drivers/mmc/host/sdhci-esdhc-imx.c | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> >
> > diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c
> > b/drivers/mmc/host/sdhci-esdhc-imx.c
> > index a7a5df673b0f..affde1936510 100644
> > --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> > +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> > @@ -1453,6 +1453,21 @@ static void esdhc_set_uhs_signaling(struct
> > sdhci_host *host, unsigned timing)
> >
> >  static void esdhc_reset(struct sdhci_host *host, u8 mask)  {
> > +     u32 present_state;
> > +     int ret;
> > +
> > +     /*
> > +      * For data or full reset, ensure any active data transfer completes
> > +      * before resetting to avoid system hang.
> > +      */
> > +     if (mask & (SDHCI_RESET_DATA | SDHCI_RESET_ALL)) {
> > +             ret = readl_poll_timeout_atomic(host->ioaddr + ESDHC_PRSSTAT,
> > present_state,
>
> I'm okay with the patch, but I find one thing here:
>
> I notice you use _atomic here, I guess you want to cover the case when the reset function is called in hardware irq handler sdhci_irq().
> I'm not sure whether it is suitable to add delay in hardware iqr handler, I find there is also udelay in sdhci_reset(), sdhci_reset can also be called in hardware irq handler when there is cmd_crc/data_crc error.
> Adrian/Ulf, do you notice this issue before? Any comments?

You are right. In general it's certainly not preferred to poll/delay
in an atomic context. But if I understand correctly here, polling in
atomic context should not happen that frequently, right?

Moreover, I wonder if we really need to have a polling-timeout of
100ms? Where did that value come from?

In any case, please add a define to specify the timeout and make sure
the define-name has the suffix corresponding to the unit (_US,
_MS,...)

>
> Regards
> Haibo Chen
>
>
> > +                                             !(present_state & SDHCI_DATA_INHIBIT), 2,
> > 100000);
> > +             if (ret == -ETIMEDOUT)
> > +                     dev_warn(mmc_dev(host->mmc),
> > +                              "timeout waiting for data transfer completion\n");
> > +     }
> > +
> >       sdhci_and_cqhci_reset(host, mask);
> >
> >       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
> > --
> > 2.34.1
>

Kind regards
Uffe



More information about the linux-arm-kernel mailing list