Skip to content

Commit 0f52fcb

Browse files
Can Guomartinkpetersen
authored andcommitted
scsi: ufs: Try to save power mode change and UIC cmd completion timeout
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/[email protected] Reviewed-by: Stanley Chu <[email protected]> Signed-off-by: Can Guo <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent da3fecb commit 0f52fcb

File tree

2 files changed

+26
-2
lines changed

2 files changed

+26
-2
lines changed

drivers/scsi/ufs/ufshcd.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2115,10 +2115,20 @@ ufshcd_wait_for_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
21152115
unsigned long flags;
21162116

21172117
if (wait_for_completion_timeout(&uic_cmd->done,
2118-
msecs_to_jiffies(UIC_CMD_TIMEOUT)))
2118+
msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
21192119
ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
2120-
else
2120+
} else {
21212121
ret = -ETIMEDOUT;
2122+
dev_err(hba->dev,
2123+
"uic cmd 0x%x with arg3 0x%x completion timeout\n",
2124+
uic_cmd->command, uic_cmd->argument3);
2125+
2126+
if (!uic_cmd->cmd_active) {
2127+
dev_err(hba->dev, "%s: UIC cmd has been completed, return the result\n",
2128+
__func__);
2129+
ret = uic_cmd->argument2 & MASK_UIC_COMMAND_RESULT;
2130+
}
2131+
}
21222132

21232133
spin_lock_irqsave(hba->host->host_lock, flags);
21242134
hba->active_uic_cmd = NULL;
@@ -2150,6 +2160,7 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd,
21502160
if (completion)
21512161
init_completion(&uic_cmd->done);
21522162

2163+
uic_cmd->cmd_active = 1;
21532164
ufshcd_dispatch_uic_cmd(hba, uic_cmd);
21542165

21552166
return 0;
@@ -3807,10 +3818,18 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd)
38073818
dev_err(hba->dev,
38083819
"pwr ctrl cmd 0x%x with mode 0x%x completion timeout\n",
38093820
cmd->command, cmd->argument3);
3821+
3822+
if (!cmd->cmd_active) {
3823+
dev_err(hba->dev, "%s: Power Mode Change operation has been completed, go check UPMCRS\n",
3824+
__func__);
3825+
goto check_upmcrs;
3826+
}
3827+
38103828
ret = -ETIMEDOUT;
38113829
goto out;
38123830
}
38133831

3832+
check_upmcrs:
38143833
status = ufshcd_get_upmcrs(hba);
38153834
if (status != PWR_LOCAL) {
38163835
dev_err(hba->dev,
@@ -4902,11 +4921,14 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
49024921
ufshcd_get_uic_cmd_result(hba);
49034922
hba->active_uic_cmd->argument3 =
49044923
ufshcd_get_dme_attr_val(hba);
4924+
if (!hba->uic_async_done)
4925+
hba->active_uic_cmd->cmd_active = 0;
49054926
complete(&hba->active_uic_cmd->done);
49064927
retval = IRQ_HANDLED;
49074928
}
49084929

49094930
if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) {
4931+
hba->active_uic_cmd->cmd_active = 0;
49104932
complete(hba->uic_async_done);
49114933
retval = IRQ_HANDLED;
49124934
}

drivers/scsi/ufs/ufshcd.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,15 @@ enum dev_cmd_type {
6464
* @argument1: UIC command argument 1
6565
* @argument2: UIC command argument 2
6666
* @argument3: UIC command argument 3
67+
* @cmd_active: Indicate if UIC command is outstanding
6768
* @done: UIC command completion
6869
*/
6970
struct uic_command {
7071
u32 command;
7172
u32 argument1;
7273
u32 argument2;
7374
u32 argument3;
75+
int cmd_active;
7476
struct completion done;
7577
};
7678

0 commit comments

Comments
 (0)