Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6af9e96e authored by Venkatraman S's avatar Venkatraman S Committed by Chris Ball
Browse files

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: default avatarAlex Lemberg <Alex.Lemberg@sandisk.com>
Signed-off-by: default avatarVenkatraman S <svenkatr@ti.com>
Reviewed-by: default avatarNamjae Jeon <linkinjeon@gmail.com>
Reviewed-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
Acked-by: default avatarJaehoon Chung <jh80.chung@samsung.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent fd0ea65d
Loading
Loading
Loading
Loading
+32 −23
Original line number Diff line number Diff line
@@ -404,6 +404,7 @@ int mmc_interrupt_hpi(struct mmc_card *card)
{
	int err;
	u32 status;
	unsigned long prg_wait;

	BUG_ON(!card);

@@ -419,30 +420,38 @@ int mmc_interrupt_hpi(struct mmc_card *card)
		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.
	 */
	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.
		 * In idle states, HPI is not needed and the caller
		 * can issue the next intended command immediately
		 */
		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);
	if (err)
				pr_debug("%s: abort HPI (%d error)\n",
					 mmc_hostname(card->host), err);
		goto out;

	prg_wait = jiffies + msecs_to_jiffies(card->ext_csd.out_of_int_time);
	do {
		err = mmc_send_status(card, &status);
			if (err)

		if (!err && R1_CURRENT_STATE(status) == R1_STATE_TRAN)
			break;
		} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
	} else
		pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
		if (time_after(jiffies, prg_wait))
			err = -ETIMEDOUT;
	} while (!err);

out:
	mmc_release_host(card->host);
+0 −1
Original line number Diff line number Diff line
@@ -569,7 +569,6 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)

	cmd.opcode = opcode;
	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);
	if (err) {