[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