Skip to content

Commit

Permalink
scsi: ufs: Try to save power mode change and UIC cmd completion timeout
Browse files Browse the repository at this point in the history
Use the uic_cmd->cmd_active as a flag to track the lifecycle of an UIC cmd.
The flag is set before sending the UIC cmd and cleared in IRQ handler. When
a PMC or UIC cmd completion timeout happens, if the flag is not set,
instead of returning timeout error, we still treat it as a successful
operation.  This is to deal with the scenario in which completion has been
raised but the one waiting for the completion cannot be awaken in time due
to kernel scheduling problem.

Link: https://lore.kernel.org/r/1604384682-15837-3-git-send-email-cang@codeaurora.org
Reviewed-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Can Guo <cang@codeaurora.org>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Can Guo authored and Martin K. Petersen committed Nov 5, 2020
1 parent da3fecb commit 0f52fcb
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
26 changes: 24 additions & 2 deletions drivers/scsi/ufs/ufshcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2115,10 +2115,20 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
unsigned long flags;

if (wait_for_completion_timeout(&uic_cmd->done,
msecs_to_jiffies(UIC_CMD_TIMEOUT)))
msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
else
} else {
ret = -ETIMEDOUT;
dev_err(hba->dev,
"uic cmd 0x%x with arg3 0x%x completion timeout\n",
uic_cmd->command, uic_cmd->argument3);

if (!uic_cmd->cmd_active) {
dev_err(hba->dev, "%s: UIC cmd has been completed, return the result\n",
__func__);
ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
}
}

spin_lock_irqsave(hba->host->host_lock, flags);
hba->active_uic_cmd = NULL;
Expand Down Expand Up @@ -2150,6 +2160,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd,
if (completion)
init_completion(&uic_cmd->done);

uic_cmd->cmd_active = 1;
ufshcd_dispatch_uic_cmd(hba, uic_cmd);

return 0;
Expand Down Expand Up @@ -3807,10 +3818,18 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
dev_err(hba->dev,
"pwr ctrl cmd 0x%x with mode 0x%x completion timeout\n",
cmd->command, cmd->argument3);

if (!cmd->cmd_active) {
dev_err(hba->dev, "%s: Power Mode Change operation has been completed, go check UPMCRS\n",
__func__);
goto check_upmcrs;
}

ret = -ETIMEDOUT;
goto out;
}

check_upmcrs:
status = ufshcd_get_upmcrs(hba);
if (status != PWR_LOCAL) {
dev_err(hba->dev,
Expand Down Expand Up @@ -4902,11 +4921,14 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
ufshcd_get_uic_cmd_result(hba);
hba->active_uic_cmd->argument3 =
ufshcd_get_dme_attr_val(hba);
if (!hba->uic_async_done)
hba->active_uic_cmd->cmd_active = 0;
complete(&hba->active_uic_cmd->done);
retval = IRQ_HANDLED;
}

if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) {
hba->active_uic_cmd->cmd_active = 0;
complete(hba->uic_async_done);
retval = IRQ_HANDLED;
}
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/ufs/ufshcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@ enum dev_cmd_type {
* @argument1: UIC command argument 1
* @argument2: UIC command argument 2
* @argument3: UIC command argument 3
* @cmd_active: Indicate if UIC command is outstanding
* @done: UIC command completion
*/
struct uic_command {
u32 command;
u32 argument1;
u32 argument2;
u32 argument3;
int cmd_active;
struct completion done;
};

Expand Down

0 comments on commit 0f52fcb

Please sign in to comment.