Commit 2b6ee04c authored by Pali Rohár's avatar Pali Rohár Committed by Lorenzo Pieralisi
Browse files

PCI: mvebu: Add support for Advanced Error Reporting registers on emulated bridge

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: default avatarPali Rohár <pali@kernel.org>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
parent e3e13c91
Loading
Loading
Loading
Loading
+66 −1
Original line number Diff line number Diff line
@@ -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,
};

/*