mirror of
https://github.com/Fishwaldo/build.git
synced 2025-04-25 23:41:30 +00:00
199 lines
6.3 KiB
Diff
199 lines
6.3 KiB
Diff
diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c
|
|
index c7588caf0..d82069511 100644
|
|
--- a/drivers/pci/controller/pci-mvebu.c
|
|
+++ b/drivers/pci/controller/pci-mvebu.c
|
|
@@ -53,13 +53,26 @@
|
|
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
|
|
#define PCIE_STAT_BUS 0xff00
|
|
#define PCIE_STAT_DEV 0x1f0000
|
|
#define PCIE_STAT_LINK_DOWN BIT(0)
|
|
+#define PCIE_SSPL 0x1a0c
|
|
+#define PCIE_SSPL_MSGEN BIT(14)
|
|
+#define PCIE_SSPL_SPLS(x) (((x) & 3) << 8)
|
|
+#define PCIE_SSPL_SPLS_VAL(x) (((x) >> 8) & 3)
|
|
+#define PCIE_SSPL_SPLV(x) ((x) & 0xff)
|
|
+#define PCIE_SSPL_SPLV_VAL(x) ((x) & 0xff)
|
|
#define PCIE_RC_RTSTA 0x1a14
|
|
#define PCIE_DEBUG_CTRL 0x1a60
|
|
#define PCIE_DEBUG_SOFT_RESET BIT(20)
|
|
@@ -424,6 +437,60 @@ 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;
|
|
+
|
|
+ struct pci_bridge_emul_conf *conf = &port->bridge.conf;
|
|
+ struct pci_bridge_emul_pcie_conf *pcie_conf = &port->bridge.pcie_conf;
|
|
+
|
|
+ /*
|
|
+ * 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 = pcie_conf->devctl;//port->bridge.pcie_conf;
|
|
+ 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 (conf->command & PCI_COMMAND_SERR)
|
|
+ reg |= PCIE_MASK_FERR_DET | PCIE_MASK_NFERR_DET |
|
|
+ PCIE_MASK_ERR_FATAL | PCIE_MASK_ERR_NONFATAL;
|
|
+
|
|
+ if (!(conf->bridgectrl & PCI_BRIDGE_CTL_SERR))
|
|
+ reg &= ~(PCIE_MASK_ERR_COR | PCIE_MASK_ERR_NONFATAL |
|
|
+ PCIE_MASK_ERR_FATAL);
|
|
+
|
|
+ rtctl = pcie_conf->rootctl;//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);
|
|
+}
|
|
+
|
|
static pci_bridge_emul_read_status_t
|
|
mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
|
|
int reg, u32 *value)
|
|
@@ -462,6 +529,29 @@ mvebu_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
|
|
*value = mvebu_readl(port, PCIE_RC_RTSTA);
|
|
break;
|
|
|
|
+ case 0x100 ... 0x128:
|
|
+ *value = mvebu_readl(port, reg);
|
|
+ break;
|
|
+
|
|
+ case 0x100 + PCI_ERR_ROOT_COMMAND:
|
|
+ case 0x100 + PCI_ERR_ROOT_STATUS:
|
|
+ case 0x100 + PCI_ERR_ROOT_ERR_SRC:
|
|
+ *value = 0;
|
|
+ break;
|
|
+
|
|
+ case PCI_EXP_SLTCAP:
|
|
+ {
|
|
+ u32 tmp = mvebu_readl(port, PCIE_SSPL);
|
|
+ *value = PCIE_SSPL_SPLS_VAL(tmp) << 15 |
|
|
+ PCIE_SSPL_SPLV_VAL(tmp) << 7;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case PCI_INTERRUPT_LINE:
|
|
+ /* LINE PIN MIN_GNT MAX_LAT */
|
|
+ *value = bridge->conf.bridgectrl << 16;
|
|
+ break;
|
|
+
|
|
default:
|
|
return PCI_BRIDGE_EMUL_NOT_HANDLED;
|
|
}
|
|
@@ -486,7 +576,8 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
|
|
mvebu_pcie_handle_iobase_change(port);
|
|
if ((old ^ new) & PCI_COMMAND_MEMORY)
|
|
mvebu_pcie_handle_membase_change(port);
|
|
-
|
|
+ if ((old ^ new) & PCI_COMMAND_SERR)
|
|
+ mvebu_pcie_handle_irq_change(port);
|
|
break;
|
|
}
|
|
|
|
@@ -509,6 +600,16 @@ mvebu_pci_bridge_emul_base_conf_write(struct pci_bridge_emul *bridge,
|
|
mvebu_pcie_handle_iobase_change(port);
|
|
break;
|
|
|
|
+ case PCI_INTERRUPT_LINE:
|
|
+ new >>= 16;
|
|
+ /* PCIe only has three bits here */
|
|
+ conf->bridgectrl = new & (PCI_BRIDGE_CTL_BUS_RESET |
|
|
+ PCI_BRIDGE_CTL_SERR |
|
|
+ PCI_BRIDGE_CTL_PARITY);
|
|
+ if ((old ^ conf->bridgectrl) & PCI_BRIDGE_CTL_SERR)
|
|
+ mvebu_pcie_handle_irq_change(port);
|
|
+ break;
|
|
+
|
|
case PCI_PRIMARY_BUS:
|
|
mvebu_pcie_set_local_bus_nr(port, conf->secondary_bus);
|
|
break;
|
|
@@ -526,6 +627,13 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
|
|
|
|
switch (reg) {
|
|
case PCI_EXP_DEVCTL:
|
|
+ bridge->pcie_conf.devctl = new & (PCI_EXP_DEVCTL_FERE |
|
|
+ PCI_EXP_DEVCTL_NFERE |
|
|
+ PCI_EXP_DEVCTL_CERE |
|
|
+ PCI_EXP_DEVCTL_URRE);
|
|
+ if (bridge->pcie_conf.devctl ^ old)
|
|
+ mvebu_pcie_handle_irq_change(port);
|
|
+
|
|
/*
|
|
* Armada370 data says these bits must always
|
|
* be zero when in root complex mode.
|
|
@@ -551,6 +659,27 @@ mvebu_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
|
|
case PCI_EXP_RTSTA:
|
|
mvebu_writel(port, new, PCIE_RC_RTSTA);
|
|
break;
|
|
+
|
|
+ case PCI_EXP_SLTCAP:
|
|
+ {
|
|
+ u32 sspl = PCIE_SSPL_SPLV((new & PCI_EXP_SLTCAP_SPLV) >> 7) |
|
|
+ PCIE_SSPL_SPLS((new & PCI_EXP_SLTCAP_SPLS) >> 15) |
|
|
+ PCIE_SSPL_MSGEN;
|
|
+ mvebu_writel(port, sspl, PCIE_SSPL);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ case PCI_EXP_RTCTL:
|
|
+ bridge->pcie_conf.rootctl = new & (PCI_EXP_RTCTL_SECEE |
|
|
+ PCI_EXP_RTCTL_SENFEE |
|
|
+ PCI_EXP_RTCTL_SEFEE |
|
|
+ PCI_EXP_RTCTL_PMEIE);
|
|
+ if (bridge->pcie_conf.rootctl ^ old)
|
|
+ mvebu_pcie_handle_irq_change(port);
|
|
+ break;
|
|
+ case 0x100 ... 0x128:
|
|
+ mvebu_writel(port, new, reg);
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
@@ -579,6 +708,7 @@ static void mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port)
|
|
bridge->conf.iolimit = PCI_IO_RANGE_TYPE_32;
|
|
}
|
|
|
|
+ bridge->conf.bridgectrl = PCI_BRIDGE_CTL_SERR;
|
|
bridge->has_pcie = true;
|
|
bridge->data = port;
|
|
bridge->ops = &mvebu_pci_bridge_emul_ops;
|