Skip to content

Commit 3ebfefa

Browse files
paliLorenzo Pieralisi
authored andcommitted
PCI: aardvark: Add support for ERR interrupt on emulated bridge
ERR interrupt is triggered when corresponding bit is unmasked in both ISR0 and PCI_EXP_DEVCTL registers. Unmasking ERR bits in PCI_EXP_DEVCTL register is not enough. This means that currently the ERR interrupt is never triggered. Unmask ERR bits in ISR0 register at driver probe time. ERR interrupt is not triggered until ERR bits are unmasked also in PCI_EXP_DEVCTL register, which is done by AER driver. So it is safe to unconditionally unmask all ERR bits in aardvark probe. Aardvark HW sets PCI_ERR_ROOT_AER_IRQ to zero and when corresponding bits in ISR0 and PCI_EXP_DEVCTL are enabled, the HW triggers a generic interrupt on GIC. Chain this interrupt to PCIe interrupt 0 with generic_handle_domain_irq() to allow processing of ERR interrupts. Link: https://lore.kernel.org/r/20220110015018.26359-14-kabel@kernel.org Signed-off-by: Pali Rohár <pali@kernel.org> Signed-off-by: Marek Behún <kabel@kernel.org> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
1 parent 754e449 commit 3ebfefa

1 file changed

Lines changed: 34 additions & 1 deletion

File tree

drivers/pci/controller/pci-aardvark.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@
9898
#define PCIE_MSG_PM_PME_MASK BIT(7)
9999
#define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44)
100100
#define PCIE_ISR0_MSI_INT_PENDING BIT(24)
101+
#define PCIE_ISR0_CORR_ERR BIT(11)
102+
#define PCIE_ISR0_NFAT_ERR BIT(12)
103+
#define PCIE_ISR0_FAT_ERR BIT(13)
104+
#define PCIE_ISR0_ERR_MASK GENMASK(13, 11)
101105
#define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
102106
#define PCIE_ISR0_INTX_DEASSERT(val) BIT(20 + (val))
103107
#define PCIE_ISR0_ALL_MASK GENMASK(31, 0)
@@ -778,11 +782,15 @@ advk_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
778782
case PCI_INTERRUPT_LINE: {
779783
/*
780784
* From the whole 32bit register we support reading from HW only
781-
* one bit: PCI_BRIDGE_CTL_BUS_RESET.
785+
* two bits: PCI_BRIDGE_CTL_BUS_RESET and PCI_BRIDGE_CTL_SERR.
782786
* Other bits are retrieved only from emulated config buffer.
783787
*/
784788
__le32 *cfgspace = (__le32 *)&bridge->conf;
785789
u32 val = le32_to_cpu(cfgspace[PCI_INTERRUPT_LINE / 4]);
790+
if (advk_readl(pcie, PCIE_ISR0_MASK_REG) & PCIE_ISR0_ERR_MASK)
791+
val &= ~(PCI_BRIDGE_CTL_SERR << 16);
792+
else
793+
val |= PCI_BRIDGE_CTL_SERR << 16;
786794
if (advk_readl(pcie, PCIE_CORE_CTRL1_REG) & HOT_RESET_GEN)
787795
val |= PCI_BRIDGE_CTL_BUS_RESET << 16;
788796
else
@@ -808,6 +816,19 @@ advk_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
808816
break;
809817

810818
case PCI_INTERRUPT_LINE:
819+
/*
820+
* According to Figure 6-3: Pseudo Logic Diagram for Error
821+
* Message Controls in PCIe base specification, SERR# Enable bit
822+
* in Bridge Control register enable receiving of ERR_* messages
823+
*/
824+
if (mask & (PCI_BRIDGE_CTL_SERR << 16)) {
825+
u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
826+
if (new & (PCI_BRIDGE_CTL_SERR << 16))
827+
val &= ~PCIE_ISR0_ERR_MASK;
828+
else
829+
val |= PCIE_ISR0_ERR_MASK;
830+
advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
831+
}
811832
if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
812833
u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
813834
if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
@@ -1453,6 +1474,18 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
14531474
isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
14541475
isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
14551476

1477+
/* Process ERR interrupt */
1478+
if (isr0_status & PCIE_ISR0_ERR_MASK) {
1479+
advk_writel(pcie, PCIE_ISR0_ERR_MASK, PCIE_ISR0_REG);
1480+
1481+
/*
1482+
* Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
1483+
* PCIe interrupt 0
1484+
*/
1485+
if (generic_handle_domain_irq(pcie->irq_domain, 0) == -EINVAL)
1486+
dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
1487+
}
1488+
14561489
/* Process MSI interrupts */
14571490
if (isr0_status & PCIE_ISR0_MSI_INT_PENDING)
14581491
advk_pcie_handle_msi(pcie);

0 commit comments

Comments
 (0)