scsi: ufs: correct ufshcd_shutdown flow
Subsystems (3)
PATCH v2 1/1 scsi: ufs: correct ufshcd_shutdown flow
From: Peter Wang <[email protected]>
Both ufshcd_shtdown and ufshcd_wl_shutdown could run concurrently. And it have race condition when ufshcd_wl_shutdown on-going and clock/power turn off by ufshcd_shutdown.
The normal case:ufshcd_wl_shutdown -> ufshcd_shtdownufshcd_shtdown should turn off clock/power.
The abnormal case:ufshcd_shtdown -> ufshcd_wl_shutdown
Wait ufshcd_wl_shutdown set device to power off and turn off clock/power. If timeout happen, means device still in active mode, cannot turn off clock/power directly. Skip and keep clock/power on in this case.
Also remove pm_runtime_get_sync because shutdown is focus on turn off clock/power. We don't need turn on(resume) and turn off. The second reason is ufshcd_wl_shutdown call ufshcd_rpm_get_sync already, if ufshcd_shtdown wait ufshcd_wl_shutdown finish, hba->dev is already resume and no need pm_runtime_get_sync.
--- drivers/ufs/core/ufshcd.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/ufs/core/ufshcd.c +11 -3
@@ -58,6 +58,9 @@/* Task management command timeout */ #define TM_CMD_TIMEOUT 100/* msecs */ +/* Shutdown wait devcie into power off timeout */ +#define UFS_SHUTDWON_TIMEOUT 500/* msecs */ +/* maximum number of retries for a general UIC command */ #define UFS_UIC_COMMAND_RETRIES 3
@@ -9461,10 +9464,15 @@ EXPORT_SYMBOL(ufshcd_runtime_resume);*/ int ufshcd_shutdown (struct ufs_hba *hba) { -if (ufshcd_is_ufs_dev_poweroff (hba) &&ufshcd_is_link_off (hba)) - goto out; +unsigned long timeout; -pm_runtime_get_sync (hba->dev); +/* Wait ufshcd_wl_shutdown clear ufs state */ + timeout = jiffies +msecs_to_jiffies (UFS_SHUTDWON_TIMEOUT ); +while (!ufshcd_is_ufs_dev_poweroff (hba) || !ufshcd_is_link_off (hba)) { +if (time_after (jiffies, timeout)) + goto out; +msleep (1 ); + }ufshcd_suspend (hba); out:
Signature · 1 line
2.18.0