Re: [PATCH 0/4] mmc: dw_mmc: replace three fallback timers with a single watchdog
From: Ulf Hansson
Date: Thu Sep 10 2026 - 12:16:02 EST
On Thu, Aug 27, 2026 at 9:58 AM Shawn Lin <shawn.lin@xxxxxxxxxxxxxx> wrote:
>
>
> The driver carries three fallback timers (cmd11_timer, cto_timer,
> dto_timer) added piecemeal after the hardware failed in the field.
> dto_timer exists because Synopsys confirmed that the DTO interrupt can
> be lost entirely, leaving no hardware fallback and blocking the request
> forever without software help (57e104864bc4); cto_timer came later,
> when Rockchip's reworked sample circuit was root-caused to swallow both
> CMD_DONE and response-timeout interrupts across their whole dwmmc
> family (03de19212ea3); cmd11_timer papered over voltage-switch hangs
> that reproduced reliably when ejecting/inserting UHS cards on rk3288
> (5c935165da79).
>
> Because each callback races against the very interrupt it supplements,
> all three grew the same copy-pasted defenses: re-read MINTSTS in case
> the interrupt is merely late, check whether pending_events has been set
> meanwhile, validate host->state against the leg being guarded, and only
> then synthesize the missed event -- with timer_delete_sync() calls from
> softirq context eventually needed just to contain them. Meanwhile the
> special cases keep piling up: the EXTENDED_TMOUT quirk makes the DTO
> story differ per platform, fault injection can post DATA_ERROR ahead of
> any real completion, and every future change has to reason about up to
> three timers at once.
>
> The observation enabling the cleanup is that command, data and
> voltage-switch legs run strictly serially within a request, so a single
> hrtimer suffices. Under irq_lock it records which pending_events bits
> are awaited along with a snapshot of host->state (dw_mci_wd_arm()),
> and producers clear that awaited mask instead of deleting any timer
> (dw_mci_wd_deliver()). On expiry the one callback classifies what
> expired by comparing the awaited set against the named
> DW_MCI_WD_{CMD,DATA}_EVENTS masks, keeps the old MINTSTS latency check
> but re-arms instead of going passive so an interrupt lost for good
> can no longer wedge the request forever, and only then synthesizes
> exactly what its predecessor would have (RTO + command complete, or
> DRTO + data error/complete). The per-leg deadlines -- CTO formula,
> DRTO formula, 500ms CMD11 budget -- are carried over unchanged.
>
> Apart from three behavioral deltas called out in the individual commit
> messages as well -- a single surviving watch during voltage switch
> instead of two timers racing, a stuck CMD11 aborting after exactly
> 500ms instead of racing min(cto_ms, 500ms) with -ETIMEDOUT unchanged,
> and bounded recovery from interrupt-latency peaks instead of an
> unbounded hang -- no functional change is intended.
>
> Tested on Rockchip platforms with SD card and eMMC (rv1126/rk3568/
> rk3576 boards): normal IO, suspend/resume and card removal during
> transfer. Compile tested on every variant consuming dw_mmc.h.
>
> Next steps: first split dw_mci_work_func() into per-state handlers to
> make the transitions explicit, then go further in the sdhci direction:
> shrink the eight-state machine, drop the redundant completed_events
> bookkeeping, and end up where other host drivers already are: one state
> machine, one timer, no separate event flags.
>
>
>
> Shawn Lin (4):
> mmc: dw_mmc: add central watchdog and convert CTO onto it
> mmc: dw_mmc: convert DTO onto the central watchdog
> mmc: dw_mmc: absorb CMD11 timeout into the central watchdog
> mmc: dw_mmc: expose the watchdog state in debugfs
>
> drivers/mmc/host/dw_mmc.c | 316 +++++++++++++++++++++++-----------------------
> drivers/mmc/host/dw_mmc.h | 15 ++-
> 2 files changed, 165 insertions(+), 166 deletions(-)
>
> --
> 2.7.4
>
The series applied for next, thanks!
Kind regards
Uffe