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

Commit 84864682 authored by Veerabhadrarao Badiganti's avatar Veerabhadrarao Badiganti
Browse files

scsi: ufs: Logic to check UIC command timeout errors genuineness



In few instances where UIC command timeout error is reported,
it turned-out to be interrupt starvation issue. That is,
ufs controller triggers the interrupt but ISR might get delayed
for different reasons which lead to ufs UIC command timeout issues.

To handle such a scenario, before retrying UIC command upon timeout,
the driver waits for little more time for completion, if it finds that
controller indeed triggered the interrupt.

Change-Id: I646e2e4b202cd7d114cef80ffee01dfbb46c5abd
Signed-off-by: default avatarVeerabhadrarao Badiganti <vbadigan@codeaurora.org>
parent 31be490b
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -3168,6 +3168,8 @@ ufshcd_dispatch_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
	/* Write UIC Cmd */
	ufshcd_writel(hba, uic_cmd->command & COMMAND_OPCODE_MASK,
		      REG_UIC_COMMAND);
	/* Make sure that UIC command is committed immediately */
	wmb();
}

/**
@@ -5110,6 +5112,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
	u8 status;
	int ret;
	bool reenable_intr = false;
	int wait_retries = 6; /* Allows 3secs max wait time */

	mutex_lock(&hba->uic_cmd_mutex);
	init_completion(&uic_async_done);
@@ -5136,11 +5139,42 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
		goto out;
	}

more_wait:
	if (!wait_for_completion_timeout(hba->uic_async_done,
					 msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
		u32 intr_status = 0;
		s64 ts_since_last_intr;

		dev_err(hba->dev,
			"pwr ctrl cmd 0x%x with mode 0x%x completion timeout\n",
			cmd->command, cmd->argument3);
		/*
		 * The controller must have triggered interrupt but ISR couldn't
		 * run due to interrupt starvation.
		 * Or ISR must have executed just after the timeout
		 * (which clears IS registers)
		 * If either of these two cases is true, then
		 * wait for little more time for completion.
		 */
		intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
		ts_since_last_intr = ktime_ms_delta(ktime_get(),
						hba->ufs_stats.last_intr_ts);

		if ((intr_status & UFSHCD_UIC_PWR_MASK) ||
		    ((hba->ufs_stats.last_intr_status & UFSHCD_UIC_PWR_MASK) &&
		     (ts_since_last_intr < (s64)UIC_CMD_TIMEOUT))) {
			dev_info(hba->dev, "IS:0x%08x last_intr_sts:0x%08x last_intr_ts:%lld, retry-cnt:%d\n",
				intr_status, hba->ufs_stats.last_intr_status,
				hba->ufs_stats.last_intr_ts, wait_retries);
			if (wait_retries--)
				goto more_wait;

			/*
			 * If same state continues event after more wait time,
			 * something must be hogging CPU.
			 */
			BUG_ON(hba->crash_on_err);
		}
		ret = -ETIMEDOUT;
		goto out;
	}