| From 5995a22fa881bb1261492b0edbfd18121fa42c2c Mon Sep 17 00:00:00 2001 |
| From: Can Guo <cang@codeaurora.org> |
| Date: Mon, 25 Nov 2019 22:53:33 -0800 |
| Subject: [PATCH] scsi: ufs: Complete pending requests in host reset and |
| restore path |
| |
| commit 2df74b6985b51e77756e2e8faa16c45ca3ba53c5 upstream. |
| |
| In UFS host reset and restore path, before probe, we stop and start the |
| host controller once. After host controller is stopped, the pending |
| requests, if any, are cleared from the doorbell, but no completion IRQ |
| would be raised due to the hba is stopped. These pending requests shall be |
| completed along with the first NOP_OUT command (as it is the first command |
| which can raise a transfer completion IRQ) sent during probe. Since the |
| OCSs of these pending requests are not SUCCESS (because they are not yet |
| literally finished), their UPIUs shall be dumped. When there are multiple |
| pending requests, the UPIU dump can be overwhelming and may lead to |
| stability issues because it is in atomic context. Therefore, before probe, |
| complete these pending requests right after host controller is stopped and |
| silence the UPIU dump from them. |
| |
| Link: https://lore.kernel.org/r/1574751214-8321-5-git-send-email-cang@qti.qualcomm.com |
| Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com> |
| Reviewed-by: Bean Huo <beanhuo@micron.com> |
| Tested-by: Bean Huo <beanhuo@micron.com> |
| 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 8058bc848836..1d4afdc1d5c5 100644 |
| --- a/drivers/scsi/ufs/ufshcd.c |
| +++ b/drivers/scsi/ufs/ufshcd.c |
| @@ -4743,7 +4743,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) |
| break; |
| } /* end of switch */ |
| |
| - if (host_byte(result) != DID_OK) |
| + if ((host_byte(result) != DID_OK) && !hba->silence_err_logs) |
| ufshcd_print_trs(hba, 1 << lrbp->task_tag, true); |
| return result; |
| } |
| @@ -5275,8 +5275,8 @@ static void ufshcd_err_handler(struct work_struct *work) |
| |
| /* |
| * if host reset is required then skip clearing the pending |
| - * transfers forcefully because they will automatically get |
| - * cleared after link startup. |
| + * transfers forcefully because they will get cleared during |
| + * host reset and restore |
| */ |
| if (needs_reset) |
| goto skip_pending_xfer_clear; |
| @@ -6132,9 +6132,15 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) |
| int err; |
| unsigned long flags; |
| |
| - /* Reset the host controller */ |
| + /* |
| + * Stop the host controller and complete the requests |
| + * cleared by h/w |
| + */ |
| spin_lock_irqsave(hba->host->host_lock, flags); |
| ufshcd_hba_stop(hba, false); |
| + hba->silence_err_logs = true; |
| + ufshcd_complete_requests(hba); |
| + hba->silence_err_logs = false; |
| spin_unlock_irqrestore(hba->host->host_lock, flags); |
| |
| /* scale up clocks to max frequency before full reinitialization */ |
| @@ -6168,22 +6174,12 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba) |
| static int ufshcd_reset_and_restore(struct ufs_hba *hba) |
| { |
| int err = 0; |
| - unsigned long flags; |
| int retries = MAX_HOST_RESET_RETRIES; |
| |
| do { |
| err = ufshcd_host_reset_and_restore(hba); |
| } while (err && --retries); |
| |
| - /* |
| - * After reset the door-bell might be cleared, complete |
| - * outstanding requests in s/w here. |
| - */ |
| - spin_lock_irqsave(hba->host->host_lock, flags); |
| - ufshcd_transfer_req_compl(hba); |
| - ufshcd_tmc_handler(hba); |
| - spin_unlock_irqrestore(hba->host->host_lock, flags); |
| - |
| return err; |
| } |
| |
| diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h |
| index 3e815fe3af67..8f88242b0b5d 100644 |
| --- a/drivers/scsi/ufs/ufshcd.h |
| +++ b/drivers/scsi/ufs/ufshcd.h |
| @@ -489,6 +489,7 @@ struct ufs_stats { |
| * @uic_error: UFS interconnect layer error status |
| * @saved_err: sticky error mask |
| * @saved_uic_err: sticky UIC error mask |
| + * @silence_err_logs: flag to silence error logs |
| * @dev_cmd: ufs device management command information |
| * @last_dme_cmd_tstamp: time stamp of the last completed DME command |
| * @auto_bkops_enabled: to track whether bkops is enabled in device |
| @@ -646,6 +647,7 @@ struct ufs_hba { |
| u32 saved_err; |
| u32 saved_uic_err; |
| struct ufs_stats ufs_stats; |
| + bool silence_err_logs; |
| |
| /* Device management request data */ |
| struct ufs_dev_cmd dev_cmd; |
| -- |
| 2.7.4 |
| |