Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f916f6e0 authored by Vidya Sagar's avatar Vidya Sagar Committed by Greg Kroah-Hartman
Browse files

PCI: tegra194: Fix Root Port interrupt handling

[ 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: 56e15a23 ("PCI: tegra: Add Tegra194 PCIe support")
Signed-off-by: default avatarVidya Sagar <vidyas@nvidia.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent ed44d9ce
Loading
Loading
Loading
Loading
+22 −24
Original line number Diff line number Diff line
@@ -345,15 +345,14 @@ static irqreturn_t tegra_pcie_rp_irq_handler(struct tegra_pcie_dw *pcie)
{
	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;
@@ -369,15 +368,15 @@ static irqreturn_t tegra_pcie_rp_irq_handler(struct tegra_pcie_dw *pcie)
		}
	}

	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);
@@ -389,25 +388,24 @@ static irqreturn_t tegra_pcie_rp_irq_handler(struct tegra_pcie_dw *pcie)
		}
	}

	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;