summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2016-11-29 10:13:46 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2017-07-07 16:12:29 +0100
commit721032736bd1e4b3ac6a139d96f69dc4f74e60e8 (patch)
tree4495f7418c15fd0442450deeb1611529206cf23a
parent84272504a19c5421f2e8a4ca0032c605c842b2bf (diff)
mvebu/clearfog pcie updates
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/pci/host/pci-mvebu.c109
-rw-r--r--drivers/pci/pcie/aspm.c2
-rw-r--r--drivers/pci/pcie/portdrv_core.c2
3 files changed, 108 insertions, 5 deletions
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index e0300c67abf6..f73aa5a89f10 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -53,7 +53,14 @@
PCIE_CONF_ADDR_EN)
#define PCIE_CONF_DATA_OFF 0x18fc
#define PCIE_MASK_OFF 0x1910
+#define PCIE_MASK_PM_PME BIT(28)
#define PCIE_MASK_ENABLE_INTS 0x0f000000
+#define PCIE_MASK_ERR_COR BIT(18)
+#define PCIE_MASK_ERR_NONFATAL BIT(17)
+#define PCIE_MASK_ERR_FATAL BIT(16)
+#define PCIE_MASK_FERR_DET BIT(10)
+#define PCIE_MASK_NFERR_DET BIT(9)
+#define PCIE_MASK_CORERR_DET BIT(8)
#define PCIE_CTRL_OFF 0x1a00
#define PCIE_CTRL_X1_MODE 0x0001
#define PCIE_STAT_OFF 0x1a04
@@ -476,6 +483,54 @@ static void mvebu_pcie_handle_membase_change(struct mvebu_pcie_port *port)
&port->memwin);
}
+static void mvebu_pcie_handle_irq_change(struct mvebu_pcie_port *port)
+{
+ u32 reg, old;
+ u16 devctl, rtctl;
+
+ /*
+ * Errors from downstream devices:
+ * bridge control register SERR: enables reception of errors
+ * Errors from this device, or received errors:
+ * command SERR: enables ERR_NONFATAL and ERR_FATAL messages
+ * => when enabled, these conditions also flag SERR in status register
+ * devctl CERE: enables ERR_CORR messages
+ * devctl NFERE: enables ERR_NONFATAL messages
+ * devctl FERE: enables ERR_FATAL messages
+ * Enabled messages then have three paths:
+ * 1. rtctl: enables system error indication
+ * 2. root error status register updated
+ * 3. root error command register: forwarding via MSI
+ */
+ old = mvebu_readl(port, PCIE_MASK_OFF);
+ reg = old & ~(PCIE_MASK_PM_PME | PCIE_MASK_FERR_DET |
+ PCIE_MASK_NFERR_DET | PCIE_MASK_CORERR_DET |
+ PCIE_MASK_ERR_COR | PCIE_MASK_ERR_NONFATAL |
+ PCIE_MASK_ERR_FATAL);
+
+ devctl = port->bridge.pcie_devctl;
+ if (devctl & PCI_EXP_DEVCTL_FERE)
+ reg |= PCIE_MASK_FERR_DET | PCIE_MASK_ERR_FATAL;
+ if (devctl & PCI_EXP_DEVCTL_NFERE)
+ reg |= PCIE_MASK_NFERR_DET | PCIE_MASK_ERR_NONFATAL;
+ if (devctl & PCI_EXP_DEVCTL_CERE)
+ reg |= PCIE_MASK_CORERR_DET | PCIE_MASK_ERR_COR;
+ if (port->bridge.command & PCI_COMMAND_SERR)
+ reg |= PCIE_MASK_FERR_DET | PCIE_MASK_NFERR_DET |
+ PCIE_MASK_ERR_FATAL | PCIE_MASK_ERR_NONFATAL;
+
+ if (!(port->bridge.bridgectrl & PCI_BRIDGE_CTL_SERR))
+ reg &= ~(PCIE_MASK_ERR_COR | PCIE_MASK_ERR_NONFATAL |
+ PCIE_MASK_ERR_FATAL);
+
+ rtctl = port->bridge.pcie_rtctl;
+ if (rtctl & PCI_EXP_RTCTL_PMEIE)
+ reg |= PCIE_MASK_PM_PME;
+
+ if (old != reg)
+ mvebu_writel(port, reg, PCIE_MASK_OFF);
+}
+
/*
* Initialize the configuration space of the PCI-to-PCI bridge
* associated with the given PCIe interface.
@@ -499,6 +554,7 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port)
/* Add capabilities */
bridge->status = PCI_STATUS_CAP_LIST;
+ bridge->bridgectrl = PCI_BRIDGE_CTL_SERR;
}
/*
@@ -571,7 +627,7 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
case PCI_INTERRUPT_LINE:
/* LINE PIN MIN_GNT MAX_LAT */
- *value = 0;
+ *value = bridge->bridgectrl << 16;
break;
case PCISWCAP_EXP_LIST_ID:
@@ -620,6 +676,16 @@ static int mvebu_sw_pci_bridge_read(struct mvebu_pcie_port *port,
*value = mvebu_readl(port, PCIE_RC_RTSTA);
break;
+ case 0x100 ... 0x128:
+ *value = mvebu_readl(port, where & ~3);
+ break;
+
+ case 0x100 + PCI_ERR_ROOT_COMMAND:
+ case 0x100 + PCI_ERR_ROOT_STATUS:
+ case 0x100 + PCI_ERR_ROOT_ERR_SRC:
+ *value = 0;
+ break;
+
/* PCIe requires the v2 fields to be hard-wired to zero */
case PCISWCAP_EXP_DEVCAP2:
case PCISWCAP_EXP_DEVCTL2:
@@ -650,7 +716,7 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
unsigned int where, int size, u32 value)
{
struct mvebu_sw_pci_bridge *bridge = &port->bridge;
- u32 mask, reg;
+ u32 mask, reg, old;
int err;
if (size == 4)
@@ -670,8 +736,7 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
switch (where & ~3) {
case PCI_COMMAND:
- {
- u32 old = bridge->command;
+ old = bridge->command;
if (!mvebu_has_ioport(port))
value &= ~PCI_COMMAND_IO;
@@ -681,8 +746,9 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
mvebu_pcie_handle_iobase_change(port);
if ((old ^ bridge->command) & PCI_COMMAND_MEMORY)
mvebu_pcie_handle_membase_change(port);
+ if ((old ^ bridge->command) & PCI_COMMAND_SERR)
+ mvebu_pcie_handle_irq_change(port);
break;
- }
case PCI_BASE_ADDRESS_0 ... PCI_BASE_ADDRESS_1:
bridge->bar[((where & ~3) - PCI_BASE_ADDRESS_0) / 4] = value;
@@ -711,6 +777,17 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
mvebu_pcie_handle_iobase_change(port);
break;
+ case PCI_INTERRUPT_LINE:
+ value >>= 16;
+ old = bridge->bridgectrl;
+ /* PCIe only has three bits here */
+ bridge->bridgectrl = value & (PCI_BRIDGE_CTL_BUS_RESET |
+ PCI_BRIDGE_CTL_SERR |
+ PCI_BRIDGE_CTL_PARITY);
+ if ((old ^ bridge->bridgectrl) & PCI_BRIDGE_CTL_SERR)
+ mvebu_pcie_handle_irq_change(port);
+ break;
+
case PCI_PRIMARY_BUS:
bridge->primary_bus = value & 0xff;
bridge->secondary_bus = (value >> 8) & 0xff;
@@ -720,6 +797,14 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
break;
case PCISWCAP_EXP_DEVCTL:
+ old = bridge->pcie_devctl;
+ bridge->pcie_devctl = value & (PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_URRE);
+ if (bridge->pcie_devctl ^ old)
+ mvebu_pcie_handle_irq_change(port);
+
/*
* Armada370 data says these bits must always
* be zero when in root complex mode.
@@ -761,10 +846,24 @@ static int mvebu_sw_pci_bridge_write(struct mvebu_pcie_port *port,
mvebu_writel(port, value, PCIE_CAP_PCIEXP + PCI_EXP_LNKCTL);
break;
+ case PCISWCAP_EXP_RTCTL:
+ old = bridge->pcie_rtctl;
+ bridge->pcie_rtctl = value & (PCI_EXP_RTCTL_SECEE |
+ PCI_EXP_RTCTL_SENFEE |
+ PCI_EXP_RTCTL_SEFEE |
+ PCI_EXP_RTCTL_PMEIE);
+ if (bridge->pcie_rtctl ^ old)
+ mvebu_pcie_handle_irq_change(port);
+ break;
+
case PCISWCAP_EXP_RTSTA:
mvebu_writel(port, value, PCIE_RC_RTSTA);
break;
+ case 0x100 ... 0x128:
+ mvebu_writel(port, value, where & ~3);
+ break;
+
default:
break;
}
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 1dfa10cc566b..f4eb7481d74e 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -509,6 +509,8 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist)
*/
pcie_get_aspm_reg(parent, &upreg);
pcie_get_aspm_reg(child, &dwreg);
+dev_info(&parent->dev, "up support %x enabled %x\n", upreg.support, upreg.enabled);
+dev_info(&parent->dev, "dn support %x enabled %x\n", dwreg.support, dwreg.enabled);
/*
* Setup L0s state
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index cea504f6f478..d8feef6e77bb 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -302,6 +302,7 @@ int pcie_port_device_register(struct pci_dev *dev)
/* Get and check PCI Express port services */
capabilities = get_port_device_capability(dev);
+dev_info(&dev->dev, "PCIe capabilities: 0x%x\n", capabilities);
if (!capabilities)
return 0;
@@ -314,6 +315,7 @@ int pcie_port_device_register(struct pci_dev *dev)
* if that is to be used.
*/
status = pcie_init_service_irqs(dev, irqs, capabilities);
+dev_info(&dev->dev, "init_service_irqs: %d\n", status);
if (status) {
capabilities &= PCIE_PORT_SERVICE_VC | PCIE_PORT_SERVICE_HP;
if (!capabilities)