summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChaotian Jing <chaotian.jing@mediatek.com>2015-11-30 09:27:30 +0800
committerHaibo Chen <haibo.chen@nxp.com>2016-06-29 13:51:23 +0800
commit38ed99ec9239242860fa071536ada49e9e89203f (patch)
treeac378fc7037ce629f7dc3d82124ae719fe7a0918
parentc6c8f8d0c5b6fc1241ad21fe3e8bd7047f707a12 (diff)
mmc: core: fix __mmc_switch timeout caused by preempt
there is a time window between __mmc_send_status() and time_afer(), on some eMMC chip, the timeout_ms is only 10ms, if this thread was scheduled out during this period, then, even card has already changes to transfer state by the result of CMD13, this part of code also treat it to timeout error. So, need calculate timeout first, then call __mmc_send_status(), if already timeout and card still in programing state, then treat it to the real timeout error. Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> (cherry picked from commit 3bbb0deea6d5c6d5ed38ae927a5bf9b0cd7c8639) Signed-off-by: Haibo Chen <haibo.chen@nxp.com> (cherry picked from commit b9b8249b98b9128d8931887eccb38cd45a0f8bf3)
-rw-r--r--drivers/mmc/core/mmc_ops.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 6a50cc6faf72..72f6785e7014 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -489,6 +489,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned long timeout;
u32 status = 0;
bool use_r1b_resp = use_busy_signal;
+ bool expired = false;
mmc_retune_hold(host);
@@ -551,6 +552,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
if (send_status) {
+ /*
+ * Due to the possibility of being preempted after
+ * sending the status command, check the expiration
+ * time first.
+ */
+ expired = time_after(jiffies, timeout);
err = __mmc_send_status(card, &status, ignore_crc);
if (err)
goto out;
@@ -571,7 +578,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
/* Timeout if the device never leaves the program state. */
- if (time_after(jiffies, timeout)) {
+ if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(host), __func__);
err = -ETIMEDOUT;