PCI: tegra194: Fix Root Port interrupt handling
authorVidya Sagar <vidyas@nvidia.com>
Thu, 21 Jul 2022 14:20:46 +0000 (19:50 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Aug 2022 12:23:57 +0000 (14:23 +0200)
[ Upstream commit 6646e99bcec627e866bc84365af37942c72b4b76 ]

As part of Root Port interrupt handling, level-0 register is read first and
based on the bits set in that, corresponding level-1 registers are read for
further interrupt processing. Since both these values are currently read
into the same 'val' variable, checking level-0 bits the second time around
is happening on the 'val' variable value of level-1 register contents
instead of freshly reading the level-0 value again.

Fix by using different variables to store level-0 and level-1 registers
contents.

Link: https://lore.kernel.org/r/20220721142052.25971-11-vidyas@nvidia.com
Fixes: 56e15a238d92 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/pci/controller/dwc/pcie-tegra194.c

index 98da257..ba9f29d 100644 (file)
@@ -352,15 +352,14 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
        struct tegra_pcie_dw *pcie = arg;
        struct dw_pcie *pci = &pcie->pci;
        struct pcie_port *pp = &pci->pp;
-       u32 val, tmp;
+       u32 val, status_l0, status_l1;
        u16 val_w;
 
-       val = appl_readl(pcie, APPL_INTR_STATUS_L0);
-       if (val & APPL_INTR_STATUS_L0_LINK_STATE_INT) {
-               val = appl_readl(pcie, APPL_INTR_STATUS_L1_0_0);
-               if (val & APPL_INTR_STATUS_L1_0_0_LINK_REQ_RST_NOT_CHGED) {
-                       appl_writel(pcie, val, APPL_INTR_STATUS_L1_0_0);
-
+       status_l0 = appl_readl(pcie, APPL_INTR_STATUS_L0);
+       if (status_l0 & APPL_INTR_STATUS_L0_LINK_STATE_INT) {
+               status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_0_0);
+               appl_writel(pcie, status_l1, APPL_INTR_STATUS_L1_0_0);
+               if (status_l1 & APPL_INTR_STATUS_L1_0_0_LINK_REQ_RST_NOT_CHGED) {
                        /* SBR & Surprise Link Down WAR */
                        val = appl_readl(pcie, APPL_CAR_RESET_OVRD);
                        val &= ~APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
@@ -376,15 +375,15 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
                }
        }
 
-       if (val & APPL_INTR_STATUS_L0_INT_INT) {
-               val = appl_readl(pcie, APPL_INTR_STATUS_L1_8_0);
-               if (val & APPL_INTR_STATUS_L1_8_0_AUTO_BW_INT_STS) {
+       if (status_l0 & APPL_INTR_STATUS_L0_INT_INT) {
+               status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_8_0);
+               if (status_l1 & APPL_INTR_STATUS_L1_8_0_AUTO_BW_INT_STS) {
                        appl_writel(pcie,
                                    APPL_INTR_STATUS_L1_8_0_AUTO_BW_INT_STS,
                                    APPL_INTR_STATUS_L1_8_0);
                        apply_bad_link_workaround(pp);
                }
-               if (val & APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS) {
+               if (status_l1 & APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS) {
                        appl_writel(pcie,
                                    APPL_INTR_STATUS_L1_8_0_BW_MGT_INT_STS,
                                    APPL_INTR_STATUS_L1_8_0);
@@ -396,25 +395,24 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
                }
        }
 
-       val = appl_readl(pcie, APPL_INTR_STATUS_L0);
-       if (val & APPL_INTR_STATUS_L0_CDM_REG_CHK_INT) {
-               val = appl_readl(pcie, APPL_INTR_STATUS_L1_18);
-               tmp = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
-               if (val & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT) {
+       if (status_l0 & APPL_INTR_STATUS_L0_CDM_REG_CHK_INT) {
+               status_l1 = appl_readl(pcie, APPL_INTR_STATUS_L1_18);
+               val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
+               if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMPLT) {
                        dev_info(pci->dev, "CDM check complete\n");
-                       tmp |= PCIE_PL_CHK_REG_CHK_REG_COMPLETE;
+                       val |= PCIE_PL_CHK_REG_CHK_REG_COMPLETE;
                }
-               if (val & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMP_ERR) {
+               if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_CMP_ERR) {
                        dev_err(pci->dev, "CDM comparison mismatch\n");
-                       tmp |= PCIE_PL_CHK_REG_CHK_REG_COMPARISON_ERROR;
+                       val |= PCIE_PL_CHK_REG_CHK_REG_COMPARISON_ERROR;
                }
-               if (val & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_LOGIC_ERR) {
+               if (status_l1 & APPL_INTR_STATUS_L1_18_CDM_REG_CHK_LOGIC_ERR) {
                        dev_err(pci->dev, "CDM Logic error\n");
-                       tmp |= PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR;
+                       val |= PCIE_PL_CHK_REG_CHK_REG_LOGIC_ERROR;
                }
-               dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, tmp);
-               tmp = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_ERR_ADDR);
-               dev_err(pci->dev, "CDM Error Address Offset = 0x%08X\n", tmp);
+               dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
+               val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_ERR_ADDR);
+               dev_err(pci->dev, "CDM Error Address Offset = 0x%08X\n", val);
        }
 
        return IRQ_HANDLED;