Skip to content

Commit 7be5ac5

Browse files
Linus WalleijUlf Hansson
authored andcommitted
mmc: mmci: Make busy complete state machine explicit
This refactors the ->busy_complete() callback currently only used by Ux500 and STM32 to handle busy detection on hardware where one and the same IRQ is fired whether we get a start or an end signal on busy detect. The code is currently using the cached status from the command IRQ in ->busy_status as a state to select what to do next: if this state is non-zero we are waiting for IRQs and if it is zero we treat the state as the starting point for a busy detect wait cycle. Make this explicit by creating a state machine where the ->busy_complete callback moves between three states. The Ux500 busy detect code currently assumes this order: we enable the busy detect IRQ, get a busy start IRQ, then a busy end IRQ, and then we clear and mask this IRQ and proceed. We insert debug prints for unexpected states. This works as before on most cards, however on a problematic card that is not working with busy detect, and which I have been debugging, the following happens a lot: [ 3.380554] mmci-pl18x 80005000.mmc: no busy signalling in time [ 3.387420] mmci-pl18x 80005000.mmc: no busy signalling in time [ 3.394561] mmci-pl18x 80005000.mmc: lost busy status when waiting for busy start IRQ This probably means that the busy detect start IRQ has already occurred when we start executing the ->busy_complete() callbacks, and the busy detect end IRQ is counted as the start IRQ, and this is what is causing the card to not be detected properly. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://lore.kernel.org/r/20230405-pl180-busydetect-fix-v7-5-69a7164f2a61@linaro.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent e1a2485 commit 7be5ac5

2 files changed

Lines changed: 45 additions & 18 deletions

File tree

drivers/mmc/host/mmci.c

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,7 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
680680
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
681681
writel(readl(base + MMCIMASK0) &
682682
~host->variant->busy_detect_mask, base + MMCIMASK0);
683+
host->busy_state = MMCI_BUSY_DONE;
683684
host->busy_status = 0;
684685
return true;
685686
}
@@ -697,14 +698,15 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
697698
* while, to allow it to be set, but tests indicates that it
698699
* isn't needed.
699700
*/
700-
if (!host->busy_status) {
701+
if (host->busy_state == MMCI_BUSY_DONE) {
701702
status = readl(base + MMCISTATUS);
702703
if (status & host->variant->busy_detect_flag) {
703704
writel(readl(base + MMCIMASK0) |
704705
host->variant->busy_detect_mask,
705706
base + MMCIMASK0);
706707

707708
host->busy_status = status & (MCI_CMDSENT | MCI_CMDRESPEND);
709+
host->busy_state = MMCI_BUSY_WAITING_FOR_START_IRQ;
708710
return false;
709711
}
710712
}
@@ -720,25 +722,34 @@ static bool ux500_busy_complete(struct mmci_host *host, u32 status, u32 err_msk)
720722
* both the start and the end interrupts needs to be cleared,
721723
* one after the other. So, clear the busy start IRQ here.
722724
*/
723-
if (host->busy_status &&
724-
(status & host->variant->busy_detect_flag)) {
725-
host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND);
726-
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
727-
return false;
725+
if (host->busy_state == MMCI_BUSY_WAITING_FOR_START_IRQ) {
726+
if (status & host->variant->busy_detect_flag) {
727+
host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND);
728+
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
729+
host->busy_state = MMCI_BUSY_WAITING_FOR_END_IRQ;
730+
return false;
731+
} else {
732+
dev_dbg(mmc_dev(host->mmc),
733+
"lost busy status when waiting for busy start IRQ\n");
734+
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
735+
writel(readl(base + MMCIMASK0) &
736+
~host->variant->busy_detect_mask, base + MMCIMASK0);
737+
host->busy_state = MMCI_BUSY_DONE;
738+
host->busy_status = 0;
739+
return true;
740+
}
728741
}
729742

730-
/*
731-
* If there is a command in-progress that has been successfully
732-
* sent and the busy bit isn't set, it means we have received
733-
* the busy end IRQ. Clear and mask the IRQ, then continue to
734-
* process the command.
735-
*/
736-
if (host->busy_status) {
737-
writel(host->variant->busy_detect_mask, base + MMCICLEAR);
738-
739-
writel(readl(base + MMCIMASK0) &
740-
~host->variant->busy_detect_mask, base + MMCIMASK0);
741-
host->busy_status = 0;
743+
if (host->busy_state == MMCI_BUSY_WAITING_FOR_END_IRQ) {
744+
if (!(status & host->variant->busy_detect_flag)) {
745+
host->busy_status |= status & (MCI_CMDSENT | MCI_CMDRESPEND);
746+
host->busy_state = MMCI_BUSY_DONE;
747+
return true;
748+
} else {
749+
dev_dbg(mmc_dev(host->mmc),
750+
"busy status still asserted when handling busy end IRQ - will keep waiting\n");
751+
return false;
752+
}
742753
}
743754

744755
return true;
@@ -1268,6 +1279,8 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
12681279
}
12691280

12701281
host->busy_status = 0;
1282+
host->busy_state = MMCI_BUSY_DONE;
1283+
12711284
if (host->variant->busy_timeout && cmd->flags & MMC_RSP_BUSY) {
12721285
if (!cmd->busy_timeout)
12731286
cmd->busy_timeout = 10 * MSEC_PER_SEC;

drivers/mmc/host/mmci.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,19 @@ struct clk;
261261
struct dma_chan;
262262
struct mmci_host;
263263

264+
/**
265+
* enum mmci_busy_state - enumerate the busy detect wait states
266+
*
267+
* This is used for the state machine waiting for different busy detect
268+
* interrupts on hardware that fire a single IRQ for start and end of
269+
* the busy detect phase on DAT0.
270+
*/
271+
enum mmci_busy_state {
272+
MMCI_BUSY_WAITING_FOR_START_IRQ,
273+
MMCI_BUSY_WAITING_FOR_END_IRQ,
274+
MMCI_BUSY_DONE,
275+
};
276+
264277
/**
265278
* struct variant_data - MMCI variant-specific quirks
266279
* @clkreg: default value for MCICLOCK register
@@ -409,6 +422,7 @@ struct mmci_host {
409422
u32 clk_reg;
410423
u32 clk_reg_add;
411424
u32 datactrl_reg;
425+
enum mmci_busy_state busy_state;
412426
u32 busy_status;
413427
u32 mask1_reg;
414428
u8 vqmmc_enabled:1;

0 commit comments

Comments
 (0)