mmc: sdhci: handle busy-end interrupt during command
authorChanho Min <chanho.min@lge.com>
Sat, 30 Aug 2014 03:40:40 +0000 (12:40 +0900)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 9 Sep 2014 11:59:23 +0000 (13:59 +0200)
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>
drivers/mmc/host/sdhci.c
include/linux/mmc/sdhci.h

index b5e22b8c4885c67209b7e6646f27c6155f29331e..335cdf3b522437e479bad0e92c95d9561c7398c9 100644 (file)
@@ -1016,6 +1016,7 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        mod_timer(&host->timer, timeout);
 
        host->cmd = cmd;
+       host->busy_handle = 0;
 
        sdhci_prepare_data(host, cmd);
 
@@ -2261,8 +2262,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 */
@@ -2330,7 +2335,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;
                        }
                }
index 09ebe57d5ce9b4a810d82b7900dea772b99abf02..0aa85ca0c788f3dfa9d3464f766b9183dbce6462 100644 (file)
@@ -146,6 +146,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 */
This page took 0.03472 seconds and 5 git commands to generate.