Skip to content

Commit 8892b70

Browse files
diandersUlf Hansson
authored andcommitted
mmc: dw_mmc: Add locking to the CTO timer
This attempts to instill a bit of paranoia to the code dealing with the CTO timer. It's believed that this will make the CTO timer more robust in the case that we're having very long interrupt latencies. Note that I originally thought that perhaps this patch was being overly paranoid and wasn't really needed, but then while I was running mmc_test on an rk3399 board I saw one instance of the message: dwmmc_rockchip fe320000.dwmmc: Unexpected interrupt latency I had debug prints in the CTO timer code and I found that it was running CMD 13 at the time. ...so even though this patch seems like it might be overly paranoid, maybe it really isn't? Presumably the bad interrupt latency experienced was due to the fact that I had serial console enabled as serial console is typically where I place blame when I see absurdly large interrupt latencies. In this particular case there was an (unrelated) printout to the serial console just before I saw the "Unexpected interrupt latency" printout. ...and actually, I managed to even reproduce the problems by running "iw mlan0 scan > /dev/null" while mmc_test was running. That not only does a bunch of PCIe traffic but it also (on my system) outputs some SELinux log spam. Fixes: 03de192 ("mmc: dw_mmc: introduce timer for broken command transfer over scheme") Tested-by: Emil Renner Berthing <kernel@esmil.dk> Signed-off-by: Douglas Anderson <dianders@chromium.org> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent 4c2357f commit 8892b70

1 file changed

Lines changed: 81 additions & 10 deletions

File tree

drivers/mmc/host/dw_mmc.c

Lines changed: 81 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
403403
unsigned int cto_clks;
404404
unsigned int cto_div;
405405
unsigned int cto_ms;
406+
unsigned long irqflags;
406407

407408
cto_clks = mci_readl(host, TMOUT) & 0xff;
408409
cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
@@ -413,8 +414,24 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
413414
/* add a bit spare time */
414415
cto_ms += 10;
415416

416-
mod_timer(&host->cto_timer,
417-
jiffies + msecs_to_jiffies(cto_ms) + 1);
417+
/*
418+
* The durations we're working with are fairly short so we have to be
419+
* extra careful about synchronization here. Specifically in hardware a
420+
* command timeout is _at most_ 5.1 ms, so that means we expect an
421+
* interrupt (either command done or timeout) to come rather quickly
422+
* after the mci_writel. ...but just in case we have a long interrupt
423+
* latency let's add a bit of paranoia.
424+
*
425+
* In general we'll assume that at least an interrupt will be asserted
426+
* in hardware by the time the cto_timer runs. ...and if it hasn't
427+
* been asserted in hardware by that time then we'll assume it'll never
428+
* come.
429+
*/
430+
spin_lock_irqsave(&host->irq_lock, irqflags);
431+
if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
432+
mod_timer(&host->cto_timer,
433+
jiffies + msecs_to_jiffies(cto_ms) + 1);
434+
spin_unlock_irqrestore(&host->irq_lock, irqflags);
418435
}
419436

420437
static void dw_mci_start_command(struct dw_mci *host,
@@ -429,11 +446,11 @@ static void dw_mci_start_command(struct dw_mci *host,
429446
wmb(); /* drain writebuffer */
430447
dw_mci_wait_while_busy(host, cmd_flags);
431448

449+
mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
450+
432451
/* response expected command only */
433452
if (cmd_flags & SDMMC_CMD_RESP_EXP)
434453
dw_mci_set_cto(host);
435-
436-
mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
437454
}
438455

439456
static inline void send_stop_abort(struct dw_mci *host, struct mmc_data *data)
@@ -1930,6 +1947,24 @@ static void dw_mci_set_drto(struct dw_mci *host)
19301947
mod_timer(&host->dto_timer, jiffies + msecs_to_jiffies(drto_ms));
19311948
}
19321949

1950+
static bool dw_mci_clear_pending_cmd_complete(struct dw_mci *host)
1951+
{
1952+
if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
1953+
return false;
1954+
1955+
/*
1956+
* Really be certain that the timer has stopped. This is a bit of
1957+
* paranoia and could only really happen if we had really bad
1958+
* interrupt latency and the interrupt routine and timeout were
1959+
* running concurrently so that the del_timer() in the interrupt
1960+
* handler couldn't run.
1961+
*/
1962+
WARN_ON(del_timer_sync(&host->cto_timer));
1963+
clear_bit(EVENT_CMD_COMPLETE, &host->pending_events);
1964+
1965+
return true;
1966+
}
1967+
19331968
static void dw_mci_tasklet_func(unsigned long priv)
19341969
{
19351970
struct dw_mci *host = (struct dw_mci *)priv;
@@ -1956,8 +1991,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
19561991

19571992
case STATE_SENDING_CMD11:
19581993
case STATE_SENDING_CMD:
1959-
if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
1960-
&host->pending_events))
1994+
if (!dw_mci_clear_pending_cmd_complete(host))
19611995
break;
19621996

19631997
cmd = host->cmd;
@@ -2126,8 +2160,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
21262160
/* fall through */
21272161

21282162
case STATE_SENDING_STOP:
2129-
if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
2130-
&host->pending_events))
2163+
if (!dw_mci_clear_pending_cmd_complete(host))
21312164
break;
21322165

21332166
/* CMD error in data command */
@@ -2600,15 +2633,14 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
26002633
struct dw_mci *host = dev_id;
26012634
u32 pending;
26022635
struct dw_mci_slot *slot = host->slot;
2636+
unsigned long irqflags;
26032637

26042638
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
26052639

26062640
if (pending) {
26072641
/* Check volt switch first, since it can look like an error */
26082642
if ((host->state == STATE_SENDING_CMD11) &&
26092643
(pending & SDMMC_INT_VOLT_SWITCH)) {
2610-
unsigned long irqflags;
2611-
26122644
mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
26132645
pending &= ~SDMMC_INT_VOLT_SWITCH;
26142646

@@ -2624,11 +2656,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
26242656
}
26252657

26262658
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
2659+
spin_lock_irqsave(&host->irq_lock, irqflags);
2660+
26272661
del_timer(&host->cto_timer);
26282662
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
26292663
host->cmd_status = pending;
26302664
smp_wmb(); /* drain writebuffer */
26312665
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
2666+
2667+
spin_unlock_irqrestore(&host->irq_lock, irqflags);
26322668
}
26332669

26342670
if (pending & DW_MCI_DATA_ERROR_FLAGS) {
@@ -2668,8 +2704,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
26682704
}
26692705

26702706
if (pending & SDMMC_INT_CMD_DONE) {
2707+
spin_lock_irqsave(&host->irq_lock, irqflags);
2708+
26712709
mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
26722710
dw_mci_cmd_interrupt(host, pending);
2711+
2712+
spin_unlock_irqrestore(&host->irq_lock, irqflags);
26732713
}
26742714

26752715
if (pending & SDMMC_INT_CD) {
@@ -2943,7 +2983,35 @@ static void dw_mci_cmd11_timer(unsigned long arg)
29432983
static void dw_mci_cto_timer(unsigned long arg)
29442984
{
29452985
struct dw_mci *host = (struct dw_mci *)arg;
2986+
unsigned long irqflags;
2987+
u32 pending;
2988+
2989+
spin_lock_irqsave(&host->irq_lock, irqflags);
29462990

2991+
/*
2992+
* If somehow we have very bad interrupt latency it's remotely possible
2993+
* that the timer could fire while the interrupt is still pending or
2994+
* while the interrupt is midway through running. Let's be paranoid
2995+
* and detect those two cases. Note that this is paranoia is somewhat
2996+
* justified because in this function we don't actually cancel the
2997+
* pending command in the controller--we just assume it will never come.
2998+
*/
2999+
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
3000+
if (pending & (DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_CMD_DONE)) {
3001+
/* The interrupt should fire; no need to act but we can warn */
3002+
dev_warn(host->dev, "Unexpected interrupt latency\n");
3003+
goto exit;
3004+
}
3005+
if (test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) {
3006+
/* Presumably interrupt handler couldn't delete the timer */
3007+
dev_warn(host->dev, "CTO timeout when already completed\n");
3008+
goto exit;
3009+
}
3010+
3011+
/*
3012+
* Continued paranoia to make sure we're in the state we expect.
3013+
* This paranoia isn't really justified but it seems good to be safe.
3014+
*/
29473015
switch (host->state) {
29483016
case STATE_SENDING_CMD11:
29493017
case STATE_SENDING_CMD:
@@ -2962,6 +3030,9 @@ static void dw_mci_cto_timer(unsigned long arg)
29623030
host->state);
29633031
break;
29643032
}
3033+
3034+
exit:
3035+
spin_unlock_irqrestore(&host->irq_lock, irqflags);
29653036
}
29663037

29673038
static void dw_mci_dto_timer(unsigned long arg)

0 commit comments

Comments
 (0)