aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorDoug Anderson <dianders@chromium.org>2015-03-09 19:18:21 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2015-03-31 10:50:43 -0400
commit5c935165da79644df90a647ecc140fb77b40dee5 (patch)
tree0dd8f9bbc1aaa9690fa8f8257d79a6d586b4d785 /drivers/mmc
parent488b8d63a63400e2839062a99358815ca21a2860 (diff)
mmc: dw_mmc: Add a timeout for sending CMD11
In the Designware databook's description of the "Voltage Switch Normal Scenario" it instructs us to set a timer and fail the voltage change if we don't see the voltage change interrupt within 2ms. Let's implement that. Without implementing this I have often been able to reproduce a hang while trying to send CMD11 on an rk3288-based board while constantly ejecting and inserting UHS cards. Signed-off-by: Doug Anderson <dianders@chromium.org> Signed-off-by: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/dw_mmc.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index f68ea4d57b18..8e0836d39081 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1021,6 +1021,15 @@ static void __dw_mci_start_request(struct dw_mci *host,
1021 1021
1022 dw_mci_start_command(host, cmd, cmdflags); 1022 dw_mci_start_command(host, cmd, cmdflags);
1023 1023
1024 if (cmd->opcode == SD_SWITCH_VOLTAGE) {
1025 /*
1026 * Databook says to fail after 2ms w/ no response; give an
1027 * extra jiffy just in case we're about to roll over.
1028 */
1029 mod_timer(&host->cmd11_timer,
1030 jiffies + msecs_to_jiffies(2) + 1);
1031 }
1032
1024 if (mrq->stop) 1033 if (mrq->stop)
1025 host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop); 1034 host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
1026 else 1035 else
@@ -2159,6 +2168,8 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
2159 /* Check volt switch first, since it can look like an error */ 2168 /* Check volt switch first, since it can look like an error */
2160 if ((host->state == STATE_SENDING_CMD11) && 2169 if ((host->state == STATE_SENDING_CMD11) &&
2161 (pending & SDMMC_INT_VOLT_SWITCH)) { 2170 (pending & SDMMC_INT_VOLT_SWITCH)) {
2171 del_timer(&host->cmd11_timer);
2172
2162 mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH); 2173 mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
2163 pending &= ~SDMMC_INT_VOLT_SWITCH; 2174 pending &= ~SDMMC_INT_VOLT_SWITCH;
2164 dw_mci_cmd_interrupt(host, pending); 2175 dw_mci_cmd_interrupt(host, pending);
@@ -2572,6 +2583,18 @@ ciu_out:
2572 return ret; 2583 return ret;
2573} 2584}
2574 2585
2586static void dw_mci_cmd11_timer(unsigned long arg)
2587{
2588 struct dw_mci *host = (struct dw_mci *)arg;
2589
2590 if (host->state != STATE_SENDING_CMD11)
2591 dev_info(host->dev, "Unexpected CMD11 timeout\n");
2592
2593 host->cmd_status = SDMMC_INT_RTO;
2594 set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
2595 tasklet_schedule(&host->tasklet);
2596}
2597
2575#ifdef CONFIG_OF 2598#ifdef CONFIG_OF
2576static struct dw_mci_of_quirks { 2599static struct dw_mci_of_quirks {
2577 char *quirk; 2600 char *quirk;
@@ -2746,6 +2769,9 @@ int dw_mci_probe(struct dw_mci *host)
2746 } 2769 }
2747 } 2770 }
2748 2771
2772 setup_timer(&host->cmd11_timer,
2773 dw_mci_cmd11_timer, (unsigned long)host);
2774
2749 host->quirks = host->pdata->quirks; 2775 host->quirks = host->pdata->quirks;
2750 2776
2751 spin_lock_init(&host->lock); 2777 spin_lock_init(&host->lock);