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>
This commit is contained in:
parent
fd0ea65d3e
commit
6af9e96e05
2 changed files with 32 additions and 24 deletions
|
@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
u32 status;
|
u32 status;
|
||||||
|
unsigned long prg_wait;
|
||||||
|
|
||||||
BUG_ON(!card);
|
BUG_ON(!card);
|
||||||
|
|
||||||
|
@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (R1_CURRENT_STATE(status)) {
|
||||||
|
case R1_STATE_IDLE:
|
||||||
|
case R1_STATE_READY:
|
||||||
|
case R1_STATE_STBY:
|
||||||
/*
|
/*
|
||||||
* If the card status is in PRG-state, we can send the HPI command.
|
* In idle states, HPI is not needed and the caller
|
||||||
*/
|
* can issue the next intended command immediately
|
||||||
if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
|
|
||||||
do {
|
|
||||||
/*
|
|
||||||
* We don't know when the HPI command will finish
|
|
||||||
* processing, so we need to resend HPI until out
|
|
||||||
* of prg-state, and keep checking the card status
|
|
||||||
* with SEND_STATUS. If a timeout error occurs when
|
|
||||||
* sending the HPI command, we are already out of
|
|
||||||
* prg-state.
|
|
||||||
*/
|
*/
|
||||||
|
goto out;
|
||||||
|
case R1_STATE_PRG:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* In all other states, it's illegal to issue HPI */
|
||||||
|
pr_debug("%s: HPI cannot be sent. Card state=%d\n",
|
||||||
|
mmc_hostname(card->host), R1_CURRENT_STATE(status));
|
||||||
|
err = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
err = mmc_send_hpi_cmd(card, &status);
|
err = mmc_send_hpi_cmd(card, &status);
|
||||||
if (err)
|
if (err)
|
||||||
pr_debug("%s: abort HPI (%d error)\n",
|
goto out;
|
||||||
mmc_hostname(card->host), err);
|
|
||||||
|
|
||||||
|
prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
|
||||||
|
do {
|
||||||
err = mmc_send_status(card, &status);
|
err = mmc_send_status(card, &status);
|
||||||
if (err)
|
|
||||||
|
if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
|
||||||
break;
|
break;
|
||||||
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
|
if (time_after(jiffies, prg_wait))
|
||||||
} else
|
err = -ETIMEDOUT;
|
||||||
pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
|
} while (!err);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
mmc_release_host(card->host);
|
mmc_release_host(card->host);
|
||||||
|
|
|
@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
|
||||||
|
|
||||||
cmd.opcode = opcode;
|
cmd.opcode = opcode;
|
||||||
cmd.arg = card->rca << 16 | 1;
|
cmd.arg = card->rca << 16 | 1;
|
||||||
cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
|
|
||||||
|
|
||||||
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
err = mmc_wait_for_cmd(card->host, &cmd, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
Loading…
Reference in a new issue