OSDN Git Service

PCI: mvebu: Add support for Advanced Error Reporting registers on emulated bridge
authorPali Rohár <pali@kernel.org>
Tue, 22 Feb 2022 15:50:25 +0000 (16:50 +0100)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Tue, 22 Feb 2022 16:04:20 +0000 (16:04 +0000)
AER registers start at mvebu offset 0x0100. Registers PCI_ERR_ROOT_COMMAND,
PCI_ERR_ROOT_STATUS and PCI_ERR_ROOT_ERR_SRC are not supported on pre-XP
hardware and returns zeros.

Note that AER interrupt is not supported yet as mvebu emulated bridge does
not implement interrupts support at all yet.

Also remove custom macro PCIE_HEADER_LOG_4_OFF as it is unused and
correctly this register should be referenced via standard macros with
offset, e.g. as: PCIE_CAP_PCIERR_OFF + PCI_ERR_HEADER_LOG + 4.

Link: https://lore.kernel.org/r/20220222155030.988-8-pali@kernel.org
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
drivers/pci/controller/pci-mvebu.c

index 566d838..1cf5c02 100644 (file)
@@ -34,7 +34,7 @@
 #define PCIE_BAR_HI_OFF(n)     (0x0014 + ((n) << 3))
 #define PCIE_SSDEV_ID_OFF      0x002c
 #define PCIE_CAP_PCIEXP                0x0060
-#define PCIE_HEADER_LOG_4_OFF  0x0128
+#define PCIE_CAP_PCIERR_OFF    0x0100
 #define PCIE_BAR_CTRL_OFF(n)   (0x1804 + (((n) - 1) * 4))
 #define PCIE_WIN04_CTRL_OFF(n) (0x1820 + ((n) << 4))
 #define PCIE_WIN04_BASE_OFF(n) (0x1824 + ((n) << 4))
@@ -603,6 +603,37 @@ mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
        return PCI_BRIDGE_EMUL_HANDLED;
 }
 
+static pci_bridge_emul_read_status_t
+mvebu_pci_bridge_emul_ext_conf_read(struct pci_bridge_emul *bridge,
+                                   int reg, u32 *value)
+{
+       struct mvebu_pcie_port *port = bridge->data;
+
+       switch (reg) {
+       case 0:
+       case PCI_ERR_UNCOR_STATUS:
+       case PCI_ERR_UNCOR_MASK:
+       case PCI_ERR_UNCOR_SEVER:
+       case PCI_ERR_COR_STATUS:
+       case PCI_ERR_COR_MASK:
+       case PCI_ERR_CAP:
+       case PCI_ERR_HEADER_LOG+0:
+       case PCI_ERR_HEADER_LOG+4:
+       case PCI_ERR_HEADER_LOG+8:
+       case PCI_ERR_HEADER_LOG+12:
+       case PCI_ERR_ROOT_COMMAND:
+       case PCI_ERR_ROOT_STATUS:
+       case PCI_ERR_ROOT_ERR_SRC:
+               *value = mvebu_readl(port, PCIE_CAP_PCIERR_OFF + reg);
+               break;
+
+       default:
+               return PCI_BRIDGE_EMUL_NOT_HANDLED;
+       }
+
+       return PCI_BRIDGE_EMUL_HANDLED;
+}
+
 static void
 mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
                                      int reg, u32 old, u32 new, u32 mask)
@@ -715,11 +746,45 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
        }
 }
 
+static void
+mvebu_pci_bridge_emul_ext_conf_write(struct pci_bridge_emul *bridge,
+                                    int reg, u32 old, u32 new, u32 mask)
+{
+       struct mvebu_pcie_port *port = bridge->data;
+
+       switch (reg) {
+       /* These are W1C registers, so clear other bits */
+       case PCI_ERR_UNCOR_STATUS:
+       case PCI_ERR_COR_STATUS:
+       case PCI_ERR_ROOT_STATUS:
+               new &= mask;
+               fallthrough;
+
+       case PCI_ERR_UNCOR_MASK:
+       case PCI_ERR_UNCOR_SEVER:
+       case PCI_ERR_COR_MASK:
+       case PCI_ERR_CAP:
+       case PCI_ERR_HEADER_LOG+0:
+       case PCI_ERR_HEADER_LOG+4:
+       case PCI_ERR_HEADER_LOG+8:
+       case PCI_ERR_HEADER_LOG+12:
+       case PCI_ERR_ROOT_COMMAND:
+       case PCI_ERR_ROOT_ERR_SRC:
+               mvebu_writel(port, new, PCIE_CAP_PCIERR_OFF + reg);
+               break;
+
+       default:
+               break;
+       }
+}
+
 static const struct pci_bridge_emul_ops mvebu_pci_bridge_emul_ops = {
        .read_base = mvebu_pci_bridge_emul_base_conf_read,
        .write_base = mvebu_pci_bridge_emul_base_conf_write,
        .read_pcie = mvebu_pci_bridge_emul_pcie_conf_read,
        .write_pcie = mvebu_pci_bridge_emul_pcie_conf_write,
+       .read_ext = mvebu_pci_bridge_emul_ext_conf_read,
+       .write_ext = mvebu_pci_bridge_emul_ext_conf_write,
 };
 
 /*