| From 61e53bd0047d58caee0c7170613045bf96de4458 Mon Sep 17 00:00:00 2001 |
| From: Adrian Hunter <adrian.hunter@intel.com> |
| Date: Fri, 2 Dec 2016 15:14:20 +0200 |
| Subject: mmc: sdhci: Fix recovery from tuning timeout |
| |
| From: Adrian Hunter <adrian.hunter@intel.com> |
| |
| commit 61e53bd0047d58caee0c7170613045bf96de4458 upstream. |
| |
| Clearing the tuning bits should reset the tuning circuit. However there is |
| more to do. Reset the command and data lines for good measure, and then |
| for eMMC ensure the card is not still trying to process a tuning command by |
| sending a stop command. |
| |
| Note the JEDEC eMMC specification says the stop command (CMD12) can be used |
| to stop a tuning command (CMD21) whereas the SD specification is silent on |
| the subject with respect to the SD tuning command (CMD19). Considering that |
| CMD12 is not a valid SDIO command, the stop command is sent only when the |
| tuning command is CMD21 i.e. for eMMC. That addresses cases seen so far |
| which have been on eMMC. |
| |
| Note that this replaces the commit fe5fb2e3b58f ("mmc: sdhci: Reset cmd and |
| data circuits after tuning failure") which is being reverted for v4.9+. |
| |
| Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> |
| Tested-by: Dan O'Donovan <dan@emutex.com> |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/mmc/host/sdhci.c | 20 ++++++++++++++++++++ |
| 1 file changed, 20 insertions(+) |
| |
| --- a/drivers/mmc/host/sdhci.c |
| +++ b/drivers/mmc/host/sdhci.c |
| @@ -2074,7 +2074,27 @@ static int sdhci_execute_tuning(struct m |
| ctrl &= ~SDHCI_CTRL_EXEC_TUNING; |
| sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); |
| |
| + sdhci_do_reset(host, SDHCI_RESET_CMD); |
| + sdhci_do_reset(host, SDHCI_RESET_DATA); |
| + |
| err = -EIO; |
| + |
| + if (cmd.opcode != MMC_SEND_TUNING_BLOCK_HS200) |
| + goto out; |
| + |
| + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); |
| + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); |
| + |
| + spin_unlock_irqrestore(&host->lock, flags); |
| + |
| + memset(&cmd, 0, sizeof(cmd)); |
| + cmd.opcode = MMC_STOP_TRANSMISSION; |
| + cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC; |
| + cmd.busy_timeout = 50; |
| + mmc_wait_for_cmd(mmc, &cmd, 0); |
| + |
| + spin_lock_irqsave(&host->lock, flags); |
| + |
| goto out; |
| } |
| |