On some boards with broken card detection if eMMC card is not present system
hangs during mmc_rescan. The sequence is as below:
mmc_rescan_try_freq:sdio_reset:
  > send CMD52
  < irq with SDMMC_INT_RESP_ERR and SDMMC_STATUS_BUSY
  < irq with SDMMC_INT_CMD_DONE and SDMMC_STATUS_BUSY
  > dw_mci_wait_busy:dw_mci_ctrl_reset
  < irq with SDMMC_INT_RESP_ERR | SDMMC_INT_CMD_DONE and status not busy
  > send CMD52
  ... mmc_rescan waits infinitely for irq in mmc_wait_for_req

It seems hardware enters into some strange state after issuing CMD52 to
non-existing card. It stops signaling IRQs and it can even hang on accessing
some registers, for example UHS_REG or CTYPE.
The patch tries to solve it by resetting the controller and marking card
as removed, as a result no further commands will be issued until next rescan.

The issue has been observed on Odroid-XU3 boards (Exynos5422 with dw_mmc 250A).

Signed-off-by: Andrzej Hajda <a.ha...@samsung.com>
---
Hi,

I am not familiar with MMC internals so please verify patch (in-)sanity.
Especially I am not sure if (SDMMC_INT_RESP_ERR | SDMMC_INT_CMD_DONE with
status busy) occurs only in this situation, if no, more precise check should
be added, I guess. Or maybe it should be a quirk???

The patch is based on Addy's 'about data busy' patchset [1].
Alim's advice about stabilization of host voltage has been tested also,
without success [2].

[1]: http://permalink.gmane.org/gmane.linux.kernel/1888161
[2]: http://permalink.gmane.org/gmane.linux.kernel.mmc/31202

Regards
Andrzej
---
 drivers/mmc/host/dw_mmc.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 692d97a..3cba1eb 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2182,8 +2182,19 @@ static irqreturn_t dw_mci_interrupt(int irq, void 
*dev_id)
                }
 
                if (pending & SDMMC_INT_CMD_DONE) {
+                       u32 err = (pending | host->cmd_status) &
+                               SDMMC_INT_RESP_ERR;
+                       struct dw_mci_slot *slot = host->cur_slot;
+
                        mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
-                       dw_mci_cmd_interrupt(host, pending);
+                       if (err && dw_mci_card_busy(slot->mmc)) {
+                               u32 ctrl = mci_readl(host, CTRL);
+
+                               ctrl |= SDMMC_CTRL_ALL_RESET_FLAGS;
+                               mci_writel(host, CTRL, ctrl);
+                               clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+                       } else
+                               dw_mci_cmd_interrupt(host, pending);
                }
 
                if (pending & SDMMC_INT_CD) {
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to