aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorTrey Ramsay <tramsay@linux.vnet.ibm.com>2012-11-16 10:31:41 -0500
committerChris Ball <cjb@laptop.org>2012-12-06 13:54:42 -0500
commit8fee476b219d1869762d9ef5c189a0c85e919a4d (patch)
tree460bb7932c106fae3b84646117b82e79c2618110 /drivers/mmc/core
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')
-rw-r--r--drivers/mmc/core/core.c18
-rw-r--r--drivers/mmc/core/mmc_ops.c11
2 files changed, 28 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 @@
42#include "sd_ops.h" 42#include "sd_ops.h"
43#include "sdio_ops.h" 43#include "sdio_ops.h"
44 44
45/* If the device is not responding */
46#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
47
45/* 48/*
46 * Background operations can take a long time, depending on the housekeeping 49 * Background operations can take a long time, depending on the housekeeping
47 * operations the card has to perform. 50 * operations the card has to perform.
@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
1631{ 1634{
1632 struct mmc_command cmd = {0}; 1635 struct mmc_command cmd = {0};
1633 unsigned int qty = 0; 1636 unsigned int qty = 0;
1637 unsigned long timeout;
1634 int err; 1638 int err;
1635 1639
1636 /* 1640 /*
@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
1708 if (mmc_host_is_spi(card->host)) 1712 if (mmc_host_is_spi(card->host))
1709 goto out; 1713 goto out;
1710 1714
1715 timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
1711 do { 1716 do {
1712 memset(&cmd, 0, sizeof(struct mmc_command)); 1717 memset(&cmd, 0, sizeof(struct mmc_command));
1713 cmd.opcode = MMC_SEND_STATUS; 1718 cmd.opcode = MMC_SEND_STATUS;
@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
1721 err = -EIO; 1726 err = -EIO;
1722 goto out; 1727 goto out;
1723 } 1728 }
1729
1730 /* Timeout if the device never becomes ready for data and
1731 * never leaves the program state.
1732 */
1733 if (time_after(jiffies, timeout)) {
1734 pr_err("%s: Card stuck in programming state! %s\n",
1735 mmc_hostname(card->host), __func__);
1736 err = -EIO;
1737 goto out;
1738 }
1739
1724 } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || 1740 } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
1725 R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG); 1741 (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
1726out: 1742out:
1727 return err; 1743 return err;
1728} 1744}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index a0e172042e65..6d8f7012d73a 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -21,6 +21,8 @@
21#include "core.h" 21#include "core.h"
22#include "mmc_ops.h" 22#include "mmc_ops.h"
23 23
24#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
25
24static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) 26static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
25{ 27{
26 int err; 28 int err;
@@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
409{ 411{
410 int err; 412 int err;
411 struct mmc_command cmd = {0}; 413 struct mmc_command cmd = {0};
414 unsigned long timeout;
412 u32 status; 415 u32 status;
413 416
414 BUG_ON(!card); 417 BUG_ON(!card);
@@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
437 return 0; 440 return 0;
438 441
439 /* Must check status to be sure of no errors */ 442 /* Must check status to be sure of no errors */
443 timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
440 do { 444 do {
441 err = mmc_send_status(card, &status); 445 err = mmc_send_status(card, &status);
442 if (err) 446 if (err)
@@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
445 break; 449 break;
446 if (mmc_host_is_spi(card->host)) 450 if (mmc_host_is_spi(card->host))
447 break; 451 break;
452
453 /* Timeout if the device never leaves the program state. */
454 if (time_after(jiffies, timeout)) {
455 pr_err("%s: Card stuck in programming state! %s\n",
456 mmc_hostname(card->host), __func__);
457 return -ETIMEDOUT;
458 }
448 } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); 459 } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
449 460
450 if (mmc_host_is_spi(card->host)) { 461 if (mmc_host_is_spi(card->host)) {