diff options
author | Venkatraman S <svenkatr@ti.com> | 2012-06-22 02:12:36 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-07-10 23:04:04 -0400 |
commit | 6af9e96e052a6d1a760c60cb340c5a6584cb92db (patch) | |
tree | 60ff946a87bcedf6a3e3eccafa994f468f955b75 /drivers/mmc | |
parent | fd0ea65d3e675e479e022b6cfc9ebe1864c76afc (diff) |
mmc: core: Fix the HPI execution sequence
mmc_execute_hpi should send the HPI command only once, and only
if the card is in PRG state.
According to eMMC spec, the command's completion time is
not dependent on OUT_OF_INTERRUPT_TIME. Only the transition
out of PRG STATE is guarded by OUT_OF_INTERRUPT_TIME - which
is defined to begin at the end of sending the command itself.
Specify the default timeout for the actual sending of HPI
command, and then use OUT_OF_INTERRUPT_TIME to wait for
the transition out of PRG state.
Reported-by: Alex Lemberg <Alex.Lemberg@sandisk.com>
Signed-off-by: Venkatraman S <svenkatr@ti.com>
Reviewed-by: Namjae Jeon <linkinjeon@gmail.com>
Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/core.c | 55 | ||||
-rw-r--r-- | drivers/mmc/core/mmc_ops.c | 1 |
2 files changed, 32 insertions, 24 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0b6141d29dbd..a7e2c4b2f18c 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card) | |||
404 | { | 404 | { |
405 | int err; | 405 | int err; |
406 | u32 status; | 406 | u32 status; |
407 | unsigned long prg_wait; | ||
407 | 408 | ||
408 | BUG_ON(!card); | 409 | BUG_ON(!card); |
409 | 410 | ||
@@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card) | |||
419 | goto out; | 420 | goto out; |
420 | } | 421 | } |
421 | 422 | ||
422 | /* | 423 | switch (R1_CURRENT_STATE(status)) { |
423 | * If the card status is in PRG-state, we can send the HPI command. | 424 | case R1_STATE_IDLE: |
424 | */ | 425 | case R1_STATE_READY: |
425 | if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { | 426 | case R1_STATE_STBY: |
426 | do { | 427 | /* |
427 | /* | 428 | * In idle states, HPI is not needed and the caller |
428 | * We don't know when the HPI command will finish | 429 | * can issue the next intended command immediately |
429 | * processing, so we need to resend HPI until out | 430 | */ |
430 | * of prg-state, and keep checking the card status | 431 | goto out; |
431 | * with SEND_STATUS. If a timeout error occurs when | 432 | case R1_STATE_PRG: |
432 | * sending the HPI command, we are already out of | 433 | break; |
433 | * prg-state. | 434 | default: |
434 | */ | 435 | /* In all other states, it's illegal to issue HPI */ |
435 | err = mmc_send_hpi_cmd(card, &status); | 436 | pr_debug("%s: HPI cannot be sent. Card state=%d\n", |
436 | if (err) | 437 | mmc_hostname(card->host), R1_CURRENT_STATE(status)); |
437 | pr_debug("%s: abort HPI (%d error)\n", | 438 | err = -EINVAL; |
438 | mmc_hostname(card->host), err); | 439 | goto out; |
440 | } | ||
439 | 441 | ||
440 | err = mmc_send_status(card, &status); | 442 | err = mmc_send_hpi_cmd(card, &status); |
441 | if (err) | 443 | if (err) |
442 | break; | 444 | goto out; |
443 | } while (R1_CURRENT_STATE(status) == R1_STATE_PRG); | 445 | |
444 | } else | 446 | prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time); |
445 | pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); | 447 | do { |
448 | err = mmc_send_status(card, &status); | ||
449 | |||
450 | if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN) | ||
451 | break; | ||
452 | if (time_after(jiffies, prg_wait)) | ||
453 | err = -ETIMEDOUT; | ||
454 | } while (!err); | ||
446 | 455 | ||
447 | out: | 456 | out: |
448 | mmc_release_host(card->host); | 457 | mmc_release_host(card->host); |
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 69370f494e05..0ed2cc5f35b6 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c | |||
@@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) | |||
569 | 569 | ||
570 | cmd.opcode = opcode; | 570 | cmd.opcode = opcode; |
571 | cmd.arg = card->rca << 16 | 1; | 571 | cmd.arg = card->rca << 16 | 1; |
572 | cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time; | ||
573 | 572 | ||
574 | err = mmc_wait_for_cmd(card->host, &cmd, 0); | 573 | err = mmc_wait_for_cmd(card->host, &cmd, 0); |
575 | if (err) { | 574 | if (err) { |