| From 286c68a327e1d31bcb02d80431d4d44a3eac1790 Mon Sep 17 00:00:00 2001 |
| From: Subhash Jadavani <subhashj@codeaurora.org> |
| Date: Thu, 14 Nov 2019 22:09:30 -0800 |
| Subject: [PATCH] scsi: ufs: Fix error handing during hibern8 enter |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit 6d303e4b19d694cdbebf76bcdb51ada664ee953d upstream. |
| |
| During clock gating (ufshcd_gate_work()), we first put the link hibern8 by |
| calling ufshcd_uic_hibern8_enter() and if ufshcd_uic_hibern8_enter() |
| returns success (0) then we gate all the clocks. Now let’s zoom in to what |
| ufshcd_uic_hibern8_enter() does internally: It calls |
| __ufshcd_uic_hibern8_enter() and if failure is encountered, link recovery |
| shall put the link back to the highest HS gear and returns success (0) to |
| ufshcd_uic_hibern8_enter() which is the issue as link is still in active |
| state due to recovery! Now ufshcd_uic_hibern8_enter() returns success to |
| ufshcd_gate_work() and hence it goes ahead with gating the UFS clock while |
| link is still in active state hence I believe controller would raise UIC |
| error interrupts. But when we service the interrupt, clocks might have |
| already been disabled! |
| |
| This change fixes for this by returning failure from |
| __ufshcd_uic_hibern8_enter() if recovery succeeds as link is still not in |
| hibern8, upon receiving the error ufshcd_hibern8_enter() would initiate |
| retry to put the link state back into hibern8. |
| |
| Link: https://lore.kernel.org/r/1573798172-20534-8-git-send-email-cang@codeaurora.org |
| Reviewed-by: Avri Altman <avri.altman@wdc.com> |
| Reviewed-by: Bean Huo <beanhuo@micron.com> |
| Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> |
| Signed-off-by: Can Guo <cang@codeaurora.org> |
| Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c |
| index 90225d6ec835..275b8271cdb9 100644 |
| --- a/drivers/scsi/ufs/ufshcd.c |
| +++ b/drivers/scsi/ufs/ufshcd.c |
| @@ -3848,15 +3848,24 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) |
| ktime_to_us(ktime_sub(ktime_get(), start)), ret); |
| |
| if (ret) { |
| + int err; |
| + |
| dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n", |
| __func__, ret); |
| |
| /* |
| - * If link recovery fails then return error so that caller |
| - * don't retry the hibern8 enter again. |
| + * If link recovery fails then return error code returned from |
| + * ufshcd_link_recovery(). |
| + * If link recovery succeeds then return -EAGAIN to attempt |
| + * hibern8 enter retry again. |
| */ |
| - if (ufshcd_link_recovery(hba)) |
| - ret = -ENOLINK; |
| + err = ufshcd_link_recovery(hba); |
| + if (err) { |
| + dev_err(hba->dev, "%s: link recovery failed", __func__); |
| + ret = err; |
| + } else { |
| + ret = -EAGAIN; |
| + } |
| } else |
| ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER, |
| POST_CHANGE); |
| @@ -3870,7 +3879,7 @@ static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) |
| |
| for (retries = UIC_HIBERN8_ENTER_RETRIES; retries > 0; retries--) { |
| ret = __ufshcd_uic_hibern8_enter(hba); |
| - if (!ret || ret == -ENOLINK) |
| + if (!ret) |
| goto out; |
| } |
| out: |
| -- |
| 2.7.4 |
| |