From a267ceca9785a89bc636e9dcefb8f99b197325af Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 29 Nov 2016 10:13:46 +0000 Subject: mvebu/clearfog updates Signed-off-by: Russell King --- drivers/pci/host/pci-mvebu.c | 109 ++++++++++++++++++++++++++++++++++++++-- drivers/pci/pcie/aspm.c | 2 + drivers/pci/pcie/portdrv_core.c | 2 + 3 files changed, 108 insertions(+), 5 deletions(-) diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index bd8e78327c59..54c3bd63c6b8 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) -- cgit