aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-09-09 05:57:57 -0400
committerChris Ball <cjb@laptop.org>2013-10-30 20:26:24 -0400
commit878e200bbb1fbde9f21582decab95b178e5a3b83 (patch)
tree058fb92c1339c23c35d4771f07b8ad5f7ad22e3d
parentd052068a0ba43273eb9cfe32460e9445ef75fdc5 (diff)
mmc: core: Do not poll for busy with status cmd for all switch cmds
Some switch operations like poweroff notify, shall according to the spec not be followed by any other new commands. For these cases and when the host does'nt support MMC_CAP_WAIT_WHILE_BUSY, we must not send status commands to poll for busy detection. Instead wait for the stated timeout from the EXT_CSD before completing the request. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Cc: Jaehoon Chung <jh80.chung@samsung.com> Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r--drivers/mmc/core/core.c2
-rw-r--r--drivers/mmc/core/mmc.c6
-rw-r--r--drivers/mmc/core/mmc_ops.c23
-rw-r--r--include/linux/mmc/core.h3
4 files changed, 24 insertions, 10 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 006ead2fb701..0292ad448b07 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -301,7 +301,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
301 } 301 }
302 302
303 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 303 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
304 EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal); 304 EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true);
305 if (err) { 305 if (err) {
306 pr_warn("%s: Error %d starting bkops\n", 306 pr_warn("%s: Error %d starting bkops\n",
307 mmc_hostname(card->host), err); 307 mmc_hostname(card->host), err);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 6d02012a1d0b..8f0c51686849 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1404,9 +1404,9 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
1404 if (notify_type == EXT_CSD_POWER_OFF_LONG) 1404 if (notify_type == EXT_CSD_POWER_OFF_LONG)
1405 timeout = card->ext_csd.power_off_longtime; 1405 timeout = card->ext_csd.power_off_longtime;
1406 1406
1407 err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, 1407 err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
1408 EXT_CSD_POWER_OFF_NOTIFICATION, 1408 EXT_CSD_POWER_OFF_NOTIFICATION,
1409 notify_type, timeout); 1409 notify_type, timeout, true, false);
1410 if (err) 1410 if (err)
1411 pr_err("%s: Power Off Notification timed out, %u\n", 1411 pr_err("%s: Power Off Notification timed out, %u\n",
1412 mmc_hostname(card->host), timeout); 1412 mmc_hostname(card->host), timeout);
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 37f7d7059ab7..aae8d8b45549 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -404,11 +404,12 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
404 * @timeout_ms: timeout (ms) for operation performed by register write, 404 * @timeout_ms: timeout (ms) for operation performed by register write,
405 * timeout of zero implies maximum possible timeout 405 * timeout of zero implies maximum possible timeout
406 * @use_busy_signal: use the busy signal as response type 406 * @use_busy_signal: use the busy signal as response type
407 * @send_status: send status cmd to poll for busy
407 * 408 *
408 * Modifies the EXT_CSD register for selected card. 409 * Modifies the EXT_CSD register for selected card.
409 */ 410 */
410int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, 411int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
411 unsigned int timeout_ms, bool use_busy_signal) 412 unsigned int timeout_ms, bool use_busy_signal, bool send_status)
412{ 413{
413 int err; 414 int err;
414 struct mmc_command cmd = {0}; 415 struct mmc_command cmd = {0};
@@ -454,14 +455,26 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
454 455
455 timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); 456 timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
456 do { 457 do {
457 err = __mmc_send_status(card, &status, ignore_crc); 458 if (send_status) {
458 if (err) 459 err = __mmc_send_status(card, &status, ignore_crc);
459 return err; 460 if (err)
461 return err;
462 }
460 if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) 463 if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
461 break; 464 break;
462 if (mmc_host_is_spi(card->host)) 465 if (mmc_host_is_spi(card->host))
463 break; 466 break;
464 467
468 /*
469 * We are not allowed to issue a status command and the host
470 * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
471 * rely on waiting for the stated timeout to be sufficient.
472 */
473 if (!send_status) {
474 mmc_delay(timeout_ms);
475 return 0;
476 }
477
465 /* Timeout if the device never leaves the program state. */ 478 /* Timeout if the device never leaves the program state. */
466 if (time_after(jiffies, timeout)) { 479 if (time_after(jiffies, timeout)) {
467 pr_err("%s: Card stuck in programming state! %s\n", 480 pr_err("%s: Card stuck in programming state! %s\n",
@@ -488,7 +501,7 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
488int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, 501int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
489 unsigned int timeout_ms) 502 unsigned int timeout_ms)
490{ 503{
491 return __mmc_switch(card, set, index, value, timeout_ms, true); 504 return __mmc_switch(card, set, index, value, timeout_ms, true, true);
492} 505}
493EXPORT_SYMBOL_GPL(mmc_switch); 506EXPORT_SYMBOL_GPL(mmc_switch);
494 507
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index a00fc49c8434..87079fc38011 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -151,7 +151,8 @@ extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
151extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, 151extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
152 struct mmc_command *, int); 152 struct mmc_command *, int);
153extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); 153extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
154extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool); 154extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
155 bool);
155extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); 156extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
156extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); 157extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
157 158