summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChanho Min <chanho.min@lge.com>2014-08-30 12:40:40 +0900
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2015-10-11 00:09:01 +0200
commit891f3ac4478238d6ff890a3bd5c8536e7ef91d5e (patch)
tree1579951f128766e21e4210c6312d17536a4b97cb
parent784248a0e50058f380e87bacedf38c8eb48b5af2 (diff)
mmc: sdhci: handle busy-end interrupt during command
It is fully legal for a controller to start handling busy-end interrupt before it has signaled that the command has completed. So make sure we do things in the proper order, Or it results that command interrupt is ignored so it can cause unexpected operations. This is founded at some toshiba emmc with the bellow warning. "mmc0: Got command interrupt 0x00000001 even though no command operation was in progress." This issue has been also reported by Youssef TRIKI: It is not specific to Toshiba devices, and happens with eMMC devices as well as SD card which support Auto-CMD12 rather than CMD23. Also, similar patch is submitted by: Gwendal Grignou <gwendal@chromium.org> Changes since v1: Fixed conflict with the next of git.linaro.org/people/ulf.hansson/mmc.git and Tested if issue is fixed again. Signed-off-by: Hankyung Yu <hankyung.yu@lge.com> Signed-off-by: Chanho Min <chanho.min@lge.com> Tested-by: Youssef TRIKI <youssef.triki@st.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> (cherry picked from commit e99783a45220a2c5f5a598e0e81213ecf2dbcf2f)
-rw-r--r--drivers/mmc/host/sdhci.c17
-rw-r--r--include/linux/mmc/sdhci.h1
2 files changed, 16 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 59d6b719b0aa..1aed27869b3c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -989,6 +989,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
mod_timer(&host->timer, jiffies + 10 * HZ);
host->cmd = cmd;
+ host->busy_handle = 0;
sdhci_prepare_data(host, cmd);
@@ -2150,8 +2151,12 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
if (host->cmd->data)
DBG("Cannot wait for busy signal when also "
"doing a data transfer");
- else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
+ else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)
+ && !host->busy_handle) {
+ /* Mark that command complete before busy is ended */
+ host->busy_handle = 1;
return;
+ }
/* The controller does not support the end-of-busy IRQ,
* fall through and take the SDHCI_INT_RESPONSE */
@@ -2217,7 +2222,15 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
return;
}
if (intmask & SDHCI_INT_DATA_END) {
- sdhci_finish_command(host);
+ /*
+ * Some cards handle busy-end interrupt
+ * before the command completed, so make
+ * sure we do things in the proper order.
+ */
+ if (host->busy_handle)
+ sdhci_finish_command(host);
+ else
+ host->busy_handle = 1;
return;
}
}
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index a8b3e54755d1..ce68b69b0aa6 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -145,6 +145,7 @@ struct sdhci_host {
struct mmc_command *cmd; /* Current command */
struct mmc_data *data; /* Current data request */
unsigned int data_early:1; /* Data finished before cmd */
+ unsigned int busy_handle:1; /* Handling the order of Busy-end */
struct sg_mapping_iter sg_miter; /* SG state for PIO */
unsigned int blocks; /* remaining PIO blocks */