2021-11-04 20:52:43 +00:00
|
|
|
From 7f3e55a3890fa26d15e2e4e90213962d1a7f6df9 Mon Sep 17 00:00:00 2001
|
|
|
|
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
|
|
|
Date: Fri, 12 Feb 2021 20:32:55 +0100
|
|
|
|
Subject: [PATCH] PCI: aardvark: Add support for ERR interrupt on emulated
|
|
|
|
bridge
|
|
|
|
MIME-Version: 1.0
|
|
|
|
Content-Type: text/plain; charset=UTF-8
|
|
|
|
Content-Transfer-Encoding: 8bit
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
Signed-off-by: Pali Rohár <pali@kernel.org>
|
|
|
|
Signed-off-by: Marek Behún <kabel@kernel.org>
|
|
|
|
---
|
|
|
|
drivers/pci/controller/pci-aardvark.c | 36 ++++++++++++++++++++++++++-
|
|
|
|
1 file changed, 35 insertions(+), 1 deletion(-)
|
|
|
|
|
|
|
|
--- a/drivers/pci/controller/pci-aardvark.c
|
|
|
|
+++ b/drivers/pci/controller/pci-aardvark.c
|
2022-03-21 14:22:20 +00:00
|
|
|
@@ -98,6 +98,10 @@
|
2021-11-04 20:52:43 +00:00
|
|
|
#define PCIE_MSG_PM_PME_MASK BIT(7)
|
|
|
|
#define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44)
|
|
|
|
#define PCIE_ISR0_MSI_INT_PENDING BIT(24)
|
|
|
|
+#define PCIE_ISR0_CORR_ERR BIT(11)
|
|
|
|
+#define PCIE_ISR0_NFAT_ERR BIT(12)
|
|
|
|
+#define PCIE_ISR0_FAT_ERR BIT(13)
|
|
|
|
+#define PCIE_ISR0_ERR_MASK GENMASK(13, 11)
|
|
|
|
#define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
|
|
|
|
#define PCIE_ISR0_INTX_DEASSERT(val) BIT(20 + (val))
|
|
|
|
#define PCIE_ISR0_ALL_MASK GENMASK(31, 0)
|
2022-03-21 14:22:20 +00:00
|
|
|
@@ -778,11 +782,15 @@ advk_pci_bridge_emul_base_conf_read(stru
|
2021-11-04 20:52:43 +00:00
|
|
|
case PCI_INTERRUPT_LINE: {
|
|
|
|
/*
|
|
|
|
* From the whole 32bit register we support reading from HW only
|
|
|
|
- * one bit: PCI_BRIDGE_CTL_BUS_RESET.
|
|
|
|
+ * two bits: PCI_BRIDGE_CTL_BUS_RESET and PCI_BRIDGE_CTL_SERR.
|
|
|
|
* Other bits are retrieved only from emulated config buffer.
|
|
|
|
*/
|
|
|
|
__le32 *cfgspace = (__le32 *)&bridge->conf;
|
|
|
|
u32 val = le32_to_cpu(cfgspace[PCI_INTERRUPT_LINE / 4]);
|
|
|
|
+ if (advk_readl(pcie, PCIE_ISR0_MASK_REG) & PCIE_ISR0_ERR_MASK)
|
|
|
|
+ val &= ~(PCI_BRIDGE_CTL_SERR << 16);
|
|
|
|
+ else
|
|
|
|
+ val |= PCI_BRIDGE_CTL_SERR << 16;
|
|
|
|
if (advk_readl(pcie, PCIE_CORE_CTRL1_REG) & HOT_RESET_GEN)
|
|
|
|
val |= PCI_BRIDGE_CTL_BUS_RESET << 16;
|
|
|
|
else
|
2022-03-21 14:22:20 +00:00
|
|
|
@@ -808,6 +816,19 @@ advk_pci_bridge_emul_base_conf_write(str
|
2021-11-04 20:52:43 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PCI_INTERRUPT_LINE:
|
|
|
|
+ /*
|
|
|
|
+ * According to Figure 6-3: Pseudo Logic Diagram for Error
|
|
|
|
+ * Message Controls in PCIe base specification, SERR# Enable bit
|
|
|
|
+ * in Bridge Control register enable receiving of ERR_* messages
|
|
|
|
+ */
|
|
|
|
+ if (mask & (PCI_BRIDGE_CTL_SERR << 16)) {
|
|
|
|
+ u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
|
|
|
+ if (new & (PCI_BRIDGE_CTL_SERR << 16))
|
|
|
|
+ val &= ~PCIE_ISR0_ERR_MASK;
|
|
|
|
+ else
|
|
|
|
+ val |= PCIE_ISR0_ERR_MASK;
|
|
|
|
+ advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
|
|
|
|
+ }
|
|
|
|
if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
|
|
|
|
u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
|
|
|
|
if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
|
2022-03-30 14:14:03 +00:00
|
|
|
@@ -1459,6 +1480,18 @@ static void advk_pcie_handle_int(struct
|
2021-11-04 20:52:43 +00:00
|
|
|
isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
|
|
|
|
isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
|
|
|
|
|
|
|
|
+ /* Process ERR interrupt */
|
|
|
|
+ if (isr0_status & PCIE_ISR0_ERR_MASK) {
|
|
|
|
+ advk_writel(pcie, PCIE_ISR0_ERR_MASK, PCIE_ISR0_REG);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
|
|
|
|
+ * PCIe interrupt 0
|
|
|
|
+ */
|
2022-03-30 14:14:03 +00:00
|
|
|
+ if (generic_handle_domain_irq(pcie->irq_domain, 0) == -EINVAL)
|
2021-11-04 20:52:43 +00:00
|
|
|
+ dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
/* Process MSI interrupts */
|
|
|
|
if (isr0_status & PCIE_ISR0_MSI_INT_PENDING)
|
|
|
|
advk_pcie_handle_msi(pcie);
|