| From: Stanley Chu <stanley.chu@mediatek.com> |
| Date: Wed, 12 Jun 2019 23:19:05 +0800 |
| Subject: scsi: ufs: Avoid runtime suspend possibly being blocked forever |
| |
| commit 24e2e7a19f7e4b83d0d5189040d997bce3596473 upstream. |
| |
| UFS runtime suspend can be triggered after pm_runtime_enable() is invoked |
| in ufshcd_pltfrm_init(). However if the first runtime suspend is triggered |
| before binding ufs_hba structure to ufs device structure via |
| platform_set_drvdata(), then UFS runtime suspend will be no longer |
| triggered in the future because its dev->power.runtime_error was set in the |
| first triggering and does not have any chance to be cleared. |
| |
| To be more clear, dev->power.runtime_error is set if hba is NULL in |
| ufshcd_runtime_suspend() which returns -EINVAL to rpm_callback() where |
| dev->power.runtime_error is set as -EINVAL. In this case, any future |
| rpm_suspend() for UFS device fails because rpm_check_suspend_allowed() |
| fails due to non-zero |
| dev->power.runtime_error. |
| |
| To resolve this issue, make sure the first UFS runtime suspend get valid |
| "hba" in ufshcd_runtime_suspend(): Enable UFS runtime PM only after hba is |
| successfully bound to UFS device structure. |
| |
| Fixes: 62694735ca95 ([SCSI] ufs: Add runtime PM support for UFS host controller driver) |
| Signed-off-by: Stanley Chu <stanley.chu@mediatek.com> |
| Reviewed-by: Avri Altman <avri.altman@wdc.com> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| [bwh: Backported to 3.16: |
| - ufshcd_pltrfm_probe() doesn't allocate or free the host structure |
| - Adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| drivers/scsi/ufs/ufshcd-pltfrm.c | 11 ++++------- |
| 1 file changed, 4 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/scsi/ufs/ufshcd-pltfrm.c |
| +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c |
| @@ -150,22 +150,19 @@ static int ufshcd_pltfrm_probe(struct pl |
| goto out; |
| } |
| |
| - pm_runtime_set_active(&pdev->dev); |
| - pm_runtime_enable(&pdev->dev); |
| - |
| err = ufshcd_init(dev, &hba, mmio_base, irq); |
| if (err) { |
| dev_err(dev, "Intialization failed\n"); |
| - goto out_disable_rpm; |
| + goto out; |
| } |
| |
| platform_set_drvdata(pdev, hba); |
| |
| + pm_runtime_set_active(&pdev->dev); |
| + pm_runtime_enable(&pdev->dev); |
| + |
| return 0; |
| |
| -out_disable_rpm: |
| - pm_runtime_disable(&pdev->dev); |
| - pm_runtime_set_suspended(&pdev->dev); |
| out: |
| return err; |
| } |