We need to ensure that there are no pending MSI IRQ vector set (i.e
PCIE_MSI_INTR0_STATUS reads 0 at least once) before exiting
dra7xx_pcie_msi_irq_handler(). Else, the dra7xx PCIe wrapper will not
register new MSI IRQs even though PCIE_MSI_INTR0_STATUS shows IRQs are
pending. Therefore, keep calling dra7xx_pcie_msi_irq_handler() until it
returns IRQ_NONE, which suggests that PCIE_MSI_INTR0_STATUS is 0.

This fixes a bug, where PCIe wifi cards with 4 DMA queues like Intel
8260 used to throw following error and stall during ping/iperf3 tests.

[   97.776310] iwlwifi 0000:01:00.0: Queue 9 stuck for 2500 ms.

Signed-off-by: Vignesh R <vigne...@ti.com>
---
 drivers/pci/dwc/pci-dra7xx.c | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/dwc/pci-dra7xx.c b/drivers/pci/dwc/pci-dra7xx.c
index ed8558d638e5..3420cbf7b60a 100644
--- a/drivers/pci/dwc/pci-dra7xx.c
+++ b/drivers/pci/dwc/pci-dra7xx.c
@@ -254,14 +254,31 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, 
void *arg)
        struct dra7xx_pcie *dra7xx = arg;
        struct dw_pcie *pci = dra7xx->pci;
        struct pcie_port *pp = &pci->pp;
+       int count = 0;
        unsigned long reg;
        u32 virq, bit;
 
        reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI);
+       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg);
 
        switch (reg) {
        case MSI:
-               dw_handle_msi_irq(pp);
+               /*
+                * Need to make sure no MSI IRQs are pending before
+                * exiting handler, else the wrapper will not catch new
+                * IRQs. So loop around till dw_handle_msi_irq() returns
+                * IRQ_NONE
+                */
+               while (dw_handle_msi_irq(pp) != IRQ_NONE && count < 1000)
+                       count++;
+
+               if (count == 1000) {
+                       dev_err(pci->dev, "too much work in msi irq\n");
+                       dra7xx_pcie_writel(dra7xx,
+                                          PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI,
+                                          reg);
+                       return IRQ_HANDLED;
+               }
                break;
        case INTA:
        case INTB:
@@ -275,8 +292,6 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, 
void *arg)
                break;
        }
 
-       dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI, reg);
-
        return IRQ_HANDLED;
 }
 
-- 
2.16.1

Reply via email to