9b15b7917e7b748daed363bf346042cc21eece33
[openwrt/staging/aparcar.git] /
1 From 7f3e55a3890fa26d15e2e4e90213962d1a7f6df9 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
3 Date: Fri, 12 Feb 2021 20:32:55 +0100
4 Subject: [PATCH] PCI: aardvark: Add support for ERR interrupt on emulated
5 bridge
6 MIME-Version: 1.0
7 Content-Type: text/plain; charset=UTF-8
8 Content-Transfer-Encoding: 8bit
9
10 ERR interrupt is triggered when corresponding bit is unmasked in both ISR0
11 and PCI_EXP_DEVCTL registers. Unmasking ERR bits in PCI_EXP_DEVCTL register
12 is not enough. This means that currently the ERR interrupt is never
13 triggered.
14
15 Unmask ERR bits in ISR0 register at driver probe time. ERR interrupt is not
16 triggered until ERR bits are unmasked also in PCI_EXP_DEVCTL register,
17 which is done by AER driver. So it is safe to unconditionally unmask all
18 ERR bits in aardvark probe.
19
20 Aardvark HW sets PCI_ERR_ROOT_AER_IRQ to zero and when corresponding bits
21 in ISR0 and PCI_EXP_DEVCTL are enabled, the HW triggers a generic interrupt
22 on GIC. Chain this interrupt to PCIe interrupt 0 with
23 generic_handle_domain_irq() to allow processing of ERR interrupts.
24
25 Signed-off-by: Pali Rohár <pali@kernel.org>
26 Signed-off-by: Marek Behún <kabel@kernel.org>
27 ---
28 drivers/pci/controller/pci-aardvark.c | 36 ++++++++++++++++++++++++++-
29 1 file changed, 35 insertions(+), 1 deletion(-)
30
31 diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c
32 index e6cfee3b41a2..7956b103d3c7 100644
33 --- a/drivers/pci/controller/pci-aardvark.c
34 +++ b/drivers/pci/controller/pci-aardvark.c
35 @@ -97,6 +97,10 @@
36 #define PCIE_MSG_PM_PME_MASK BIT(7)
37 #define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44)
38 #define PCIE_ISR0_MSI_INT_PENDING BIT(24)
39 +#define PCIE_ISR0_CORR_ERR BIT(11)
40 +#define PCIE_ISR0_NFAT_ERR BIT(12)
41 +#define PCIE_ISR0_FAT_ERR BIT(13)
42 +#define PCIE_ISR0_ERR_MASK GENMASK(13, 11)
43 #define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
44 #define PCIE_ISR0_INTX_DEASSERT(val) BIT(20 + (val))
45 #define PCIE_ISR0_ALL_MASK GENMASK(31, 0)
46 @@ -785,11 +789,15 @@ advk_pci_bridge_emul_base_conf_read(struct pci_bridge_emul *bridge,
47 case PCI_INTERRUPT_LINE: {
48 /*
49 * From the whole 32bit register we support reading from HW only
50 - * one bit: PCI_BRIDGE_CTL_BUS_RESET.
51 + * two bits: PCI_BRIDGE_CTL_BUS_RESET and PCI_BRIDGE_CTL_SERR.
52 * Other bits are retrieved only from emulated config buffer.
53 */
54 __le32 *cfgspace = (__le32 *)&bridge->conf;
55 u32 val = le32_to_cpu(cfgspace[PCI_INTERRUPT_LINE / 4]);
56 + if (advk_readl(pcie, PCIE_ISR0_MASK_REG) & PCIE_ISR0_ERR_MASK)
57 + val &= ~(PCI_BRIDGE_CTL_SERR << 16);
58 + else
59 + val |= PCI_BRIDGE_CTL_SERR << 16;
60 if (advk_readl(pcie, PCIE_CORE_CTRL1_REG) & HOT_RESET_GEN)
61 val |= PCI_BRIDGE_CTL_BUS_RESET << 16;
62 else
63 @@ -815,6 +823,19 @@ advk_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
64 break;
65
66 case PCI_INTERRUPT_LINE:
67 + /*
68 + * According to Figure 6-3: Pseudo Logic Diagram for Error
69 + * Message Controls in PCIe base specification, SERR# Enable bit
70 + * in Bridge Control register enable receiving of ERR_* messages
71 + */
72 + if (mask & (PCI_BRIDGE_CTL_SERR << 16)) {
73 + u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
74 + if (new & (PCI_BRIDGE_CTL_SERR << 16))
75 + val &= ~PCIE_ISR0_ERR_MASK;
76 + else
77 + val |= PCIE_ISR0_ERR_MASK;
78 + advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
79 + }
80 if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
81 u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
82 if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
83 @@ -1464,6 +1485,19 @@ static void advk_pcie_handle_int(struct advk_pcie *pcie)
84 isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
85 isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
86
87 + /* Process ERR interrupt */
88 + if (isr0_status & PCIE_ISR0_ERR_MASK) {
89 + advk_writel(pcie, PCIE_ISR0_ERR_MASK, PCIE_ISR0_REG);
90 +
91 + /*
92 + * Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
93 + * PCIe interrupt 0
94 + */
95 + virq = irq_find_mapping(pcie->irq_domain, 0);
96 + if (generic_handle_irq(virq) == -EINVAL)
97 + dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
98 + }
99 +
100 /* Process MSI interrupts */
101 if (isr0_status & PCIE_ISR0_MSI_INT_PENDING)
102 advk_pcie_handle_msi(pcie);
103 --
104 2.34.1
105