From: Peter Wang <peter.wang@xxxxxxxxxxxx> If error happened in rpm flow, get rpm will stuck because rpm is suspending or resuming. And it cause IO hang. This patch bypass get rpm when err handling with pm_op_in_progress. Signed-off-by: Peter Wang <peter.wang@xxxxxxxxxxxx> --- drivers/ufs/core/ufshcd.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index a202d7d5240d..cc58fb585df2 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -6086,9 +6086,13 @@ static void ufshcd_clk_scaling_suspend(struct ufs_hba *hba, bool suspend) } } -static void ufshcd_err_handling_prepare(struct ufs_hba *hba) +static void ufshcd_err_handling_prepare(struct ufs_hba *hba, bool *rpm_put) { - ufshcd_rpm_get_sync(hba); + if (!hba->pm_op_in_progress) { + ufshcd_rpm_get_sync(hba); + *rpm_put = true; + } + if (pm_runtime_status_suspended(&hba->ufs_device_wlun->sdev_gendev) || hba->is_sys_suspended) { enum ufs_pm_op pm_op; @@ -6122,13 +6126,14 @@ static void ufshcd_err_handling_prepare(struct ufs_hba *hba) cancel_work_sync(&hba->eeh_work); } -static void ufshcd_err_handling_unprepare(struct ufs_hba *hba) +static void ufshcd_err_handling_unprepare(struct ufs_hba *hba, bool rpm_put) { ufshcd_scsi_unblock_requests(hba); ufshcd_release(hba); if (ufshcd_is_clkscaling_supported(hba)) ufshcd_clk_scaling_suspend(hba, false); - ufshcd_rpm_put(hba); + if (rpm_put) + ufshcd_rpm_put(hba); } static inline bool ufshcd_err_handling_should_stop(struct ufs_hba *hba) @@ -6210,6 +6215,7 @@ static void ufshcd_err_handler(struct work_struct *work) bool err_tm; int pmc_err; int tag; + bool rpm_put = false; hba = container_of(work, struct ufs_hba, eh_work); @@ -6231,7 +6237,7 @@ static void ufshcd_err_handler(struct work_struct *work) } ufshcd_set_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); - ufshcd_err_handling_prepare(hba); + ufshcd_err_handling_prepare(hba, &rpm_put); /* Complete requests that have door-bell cleared by h/w */ ufshcd_complete_requests(hba); spin_lock_irqsave(hba->host->host_lock, flags); @@ -6394,7 +6400,7 @@ static void ufshcd_err_handler(struct work_struct *work) } ufshcd_clear_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); - ufshcd_err_handling_unprepare(hba); + ufshcd_err_handling_unprepare(hba, rpm_put); up(&hba->host_sem); dev_info(hba->dev, "%s finished; HBA state %s\n", __func__, -- 2.18.0