summaryrefslogtreecommitdiff
path: root/drivers/mmc/core/core.c
diff options
context:
space:
mode:
authorTrey Ramsay <tramsay@linux.vnet.ibm.com>2012-11-16 09:31:41 -0600
committerChris Ball <cjb@laptop.org>2012-12-06 13:54:42 -0500
commit8fee476b219d1869762d9ef5c189a0c85e919a4d (patch)
tree460bb7932c106fae3b84646117b82e79c2618110 /drivers/mmc/core/core.c
parente95baf132f9709b86721a562210403473ef72249 (diff)
mmc: core: Fix some driver hangs when dealing with broken devices
There are infinite loops in the mmc code that can be caused by bad hardware. The code will loop forever if the device never comes back from program mode, R1_STATE_PRG, and it is not ready for data, R1_READY_FOR_DATA. A long timeout is added to prevent the code from looping forever. The timeout will occur if the device never comes back from program state or the device never becomes ready for data. It's not clear whether the timeout will do more than log a pr_err() and then start a fresh hang all over again. We may need to extend this patch later to perform some kind of reset of the device (is that possible?) or rejection of new I/O to the device. Signed-off-by: Trey Ramsay <tramsay@linux.vnet.ibm.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r--drivers/mmc/core/core.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 06c42cfb7c34..bccfd1858b08 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -42,6 +42,9 @@
#include "sd_ops.h"
#include "sdio_ops.h"
+/* If the device is not responding */
+#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
{
struct mmc_command cmd = {0};
unsigned int qty = 0;
+ unsigned long timeout;
int err;
/*
@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if (mmc_host_is_spi(card->host))
goto out;
+ timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
err = -EIO;
goto out;
}
+
+ /* Timeout if the device never becomes ready for data and
+ * never leaves the program state.
+ */
+ if (time_after(jiffies, timeout)) {
+ pr_err("%s: Card stuck in programming state! %s\n",
+ mmc_hostname(card->host), __func__);
+ err = -EIO;
+ goto out;
+ }
+
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
+ (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
return err;
}