summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVenkat Gopalakrishnan <venkatg@codeaurora.org>2020-04-21 13:40:03 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-04-24 07:59:08 +0200
commit5ebfa3b9b37c926b4625b106ce854a277d2a6cb7 (patch)
treeffa094609a6b2d6fd09f853194e9668912a0a2b2
parent6457ade9bc42c3ab7eea29e5045c985b0dfc2302 (diff)
scsi: ufs: make sure all interrupts are processed
[ Upstream commit 7f6ba4f12e6cbfdefbb95cfd8fc67ece6c15d799 ] As multiple requests are submitted to the ufs host controller in parallel there could be instances where the command completion interrupt arrives later for a request that is already processed earlier as the corresponding doorbell was cleared when handling the previous interrupt. Read the interrupt status in a loop after processing the received interrupt to catch such interrupts and handle it. Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org> Signed-off-by: Asutosh Das <asutoshd@codeaurora.org> Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/scsi/ufs/ufshcd.c27
1 files changed, 19 insertions, 8 deletions
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9bd26efcc1a1..50d15748084a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4397,19 +4397,30 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba)
u32 intr_status, enabled_intr_status;
irqreturn_t retval = IRQ_NONE;
struct ufs_hba *hba = __hba;
+ int retries = hba->nutrs;
spin_lock(hba->host->host_lock);
intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
- enabled_intr_status =
- intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
- if (intr_status)
- ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+ /*
+ * There could be max of hba->nutrs reqs in flight and in worst case
+ * if the reqs get finished 1 by 1 after the interrupt status is
+ * read, make sure we handle them by checking the interrupt status
+ * again in a loop until we process all of the reqs before returning.
+ */
+ do {
+ enabled_intr_status =
+ intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE);
+ if (intr_status)
+ ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS);
+ if (enabled_intr_status) {
+ ufshcd_sl_intr(hba, enabled_intr_status);
+ retval = IRQ_HANDLED;
+ }
+
+ intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS);
+ } while (intr_status && --retries);
- if (enabled_intr_status) {
- ufshcd_sl_intr(hba, enabled_intr_status);
- retval = IRQ_HANDLED;
- }
spin_unlock(hba->host->host_lock);
return retval;
}