summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubhash Jadavani <subhashj@codeaurora.org>2015-06-08 13:13:16 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-22 10:59:55 -0700
commit4d53145d9793da4f24c0923de350303b2f09d3fb (patch)
tree98d447d10ba7ecfa1ee0cca1be11e545025b4325
parent88abe3727bb5ed5c60e52f3c35fff9620d44ffbb (diff)
scsi: ufs: fix timeout waiting for doorbell clear
ufshcd_wait_for_doorbell_clr() function should wait for the doorbell to be cleared until the specified timeout period but current implementation really seems to be waiting until the doorbell is cleared (instead of timing out after timeout period), this change fixes this issue. Change-Id: I0dee77db7d319250b5fab5f77e51175ea7d1d664 Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
-rw-r--r--drivers/scsi/ufs/ufshcd.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c2318eaa7265..cc567cd7572e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3769,8 +3769,8 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us)
int ret = 0;
u32 tm_doorbell;
u32 tr_doorbell;
- bool timeout = false;
- ktime_t start = ktime_get();
+ bool timeout = false, do_last_check = false;
+ ktime_t start;
ufshcd_hold_all(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
@@ -3783,19 +3783,29 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us)
* Wait for all the outstanding tasks/transfer requests.
* Verify by checking the doorbell registers are clear.
*/
+ start = ktime_get();
do {
tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL);
tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL);
if (!tm_doorbell && !tr_doorbell) {
timeout = false;
break;
+ } else if (do_last_check) {
+ break;
}
spin_unlock_irqrestore(hba->host->host_lock, flags);
schedule();
if (ktime_to_us(ktime_sub(ktime_get(), start)) >
- wait_timeout_us)
+ wait_timeout_us) {
timeout = true;
+ /*
+ * We might have scheduled out for long time so make
+ * sure to check if doorbells are cleared by this time
+ * or not.
+ */
+ do_last_check = true;
+ }
spin_lock_irqsave(hba->host->host_lock, flags);
} while (tm_doorbell || tr_doorbell);