Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F103979124
D22014.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D22014.diff
View Options
Index: sys/powerpc/include/openpicvar.h
===================================================================
--- sys/powerpc/include/openpicvar.h
+++ sys/powerpc/include/openpicvar.h
@@ -35,6 +35,7 @@
#define OPENPIC_IRQMAX 256 /* h/w allows more */
#define OPENPIC_QUIRK_SINGLE_BIND 1 /* Bind interrupts to only 1 CPU */
+#define OPENPIC_QUIRK_HIDDEN_IRQS 2 /* May have IRQs beyond FRR[NIRQ] */
/* Names match the macros in openpicreg.h. */
struct openpic_timer {
Index: sys/powerpc/mpc85xx/pci_mpc85xx.c
===================================================================
--- sys/powerpc/mpc85xx/pci_mpc85xx.c
+++ sys/powerpc/mpc85xx/pci_mpc85xx.c
@@ -51,8 +51,10 @@
#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/queue.h>
#include <sys/rman.h>
#include <sys/endian.h>
+#include <sys/vmem.h>
#include <vm/vm.h>
#include <vm/pmap.h>
@@ -67,6 +69,7 @@
#include "ofw_bus_if.h"
#include "pcib_if.h"
+#include "pic_if.h"
#include <machine/resource.h>
#include <machine/bus.h>
@@ -80,6 +83,12 @@
#define REG_CFG_DATA 0x0004
#define REG_INT_ACK 0x0008
+#define REG_PEX_IP_BLK_REV1 0x0bf8
+#define IP_MJ_M 0x0000ff00
+#define IP_MJ_S 8
+#define IP_MN_M 0x000000ff
+#define IP_MN_S 0
+
#define REG_POTAR(n) (0x0c00 + 0x20 * (n))
#define REG_POTEAR(n) (0x0c04 + 0x20 * (n))
#define REG_POWBAR(n) (0x0c08 + 0x20 * (n))
@@ -89,6 +98,12 @@
#define REG_PIWBAR(n) (0x0e08 - 0x20 * (n))
#define REG_PIWBEAR(n) (0x0e0c - 0x20 * (n))
#define REG_PIWAR(n) (0x0e10 - 0x20 * (n))
+#define PIWAR_EN 0x80000000
+#define PIWAR_PF 0x40000000
+#define PIWAR_TRGT_M 0x00f00000
+#define PIWAR_TRGT_S 20
+#define PIWAR_TRGT_CCSR 0xe
+#define PIWAR_TRGT_LOCAL 0xf
#define REG_PEX_MES_DR 0x0020
#define REG_PEX_MES_IER 0x0028
@@ -123,10 +138,14 @@
#define DEVFN(b, s, f) ((b << 16) | (s << 8) | f)
+#define FSL_NUM_MSIS 256 /* 8 registers of 32 bits (8 hardware IRQs) */
+
struct fsl_pcib_softc {
struct ofw_pci_softc pci_sc;
device_t sc_dev;
struct mtx sc_cfg_mtx;
+ int sc_ip_maj;
+ int sc_ip_min;
int sc_iomem_target;
bus_addr_t sc_iomem_start, sc_iomem_end;
@@ -151,6 +170,14 @@
uint32_t err_dr_mask;
};
+struct fsl_msi_map {
+ SLIST_ENTRY(fsl_msi_map) slist;
+ uint32_t irq_base;
+ bus_addr_t target;
+};
+
+SLIST_HEAD(msi_head, fsl_msi_map) fsl_msis = SLIST_HEAD_INITIALIZER(msi_head);
+
static const struct fsl_pcib_err_dr pci_err[] = {
{"ME", REG_PEX_ERR_DR_ME},
{"PCT", REG_PEX_ERR_DR_PCT},
@@ -195,6 +222,16 @@
static uint32_t fsl_pcib_read_config(device_t, u_int, u_int, u_int, u_int, int);
static void fsl_pcib_write_config(device_t, u_int, u_int, u_int, u_int,
uint32_t, int);
+static int fsl_pcib_alloc_msi(device_t dev, device_t child,
+ int count, int maxcount, int *irqs);
+static int fsl_pcib_release_msi(device_t dev, device_t child,
+ int count, int *irqs);
+static int fsl_pcib_alloc_msix(device_t dev, device_t child, int *irq);
+static int fsl_pcib_release_msix(device_t dev, device_t child, int irq);
+static int fsl_pcib_map_msi(device_t dev, device_t child,
+ int irq, uint64_t *addr, uint32_t *data);
+
+static vmem_t *msi_vmem; /* Global MSI vmem, holds all MSI ranges. */
/*
* Bus interface definitions.
@@ -209,6 +246,11 @@
DEVMETHOD(pcib_maxslots, fsl_pcib_maxslots),
DEVMETHOD(pcib_read_config, fsl_pcib_read_config),
DEVMETHOD(pcib_write_config, fsl_pcib_write_config),
+ DEVMETHOD(pcib_alloc_msi, fsl_pcib_alloc_msi),
+ DEVMETHOD(pcib_release_msi, fsl_pcib_release_msi),
+ DEVMETHOD(pcib_alloc_msix, fsl_pcib_alloc_msix),
+ DEVMETHOD(pcib_release_msix, fsl_pcib_release_msix),
+ DEVMETHOD(pcib_map_msi, fsl_pcib_map_msi),
DEVMETHOD_END
};
@@ -272,7 +314,7 @@
{
struct fsl_pcib_softc *sc;
phandle_t node;
- uint32_t cfgreg, brctl;
+ uint32_t cfgreg, brctl, ipreg;
int error, rid;
uint8_t ltssm, capptr;
@@ -290,6 +332,9 @@
sc->sc_bsh = rman_get_bushandle(sc->sc_res);
sc->sc_busnr = 0;
+ ipreg = bus_read_4(sc->sc_res, REG_PEX_IP_BLK_REV1);
+ sc->sc_ip_min = (ipreg & IP_MN_M) >> IP_MN_S;
+ sc->sc_ip_maj = (ipreg & IP_MJ_M) >> IP_MJ_S;
mtx_init(&sc->sc_cfg_mtx, "pcicfg", NULL, MTX_SPIN);
cfgreg = fsl_pcib_cfgread(sc, 0, 0, 0, PCIR_VENDOR, 2);
@@ -533,14 +578,16 @@
KASSERT(wnd > 0, ("%s: inbound window 0 is invalid", __func__));
+ attr = PIWAR_EN;
+
switch (tgt) {
- /* XXX OCP85XX_TGTIF_RAM2, OCP85XX_TGTIF_RAM_INTL should be handled */
- case OCP85XX_TGTIF_RAM1_85XX:
- case OCP85XX_TGTIF_RAM1_QORIQ:
- attr = 0xa0f55000 | (ffsl(size) - 2);
+ case -1:
+ attr &= ~PIWAR_EN;
break;
+ case PIWAR_TRGT_LOCAL:
+ attr |= (ffsl(size) - 2);
default:
- attr = 0;
+ attr |= (tgt << PIWAR_TRGT_S);
break;
}
tar = start >> 12;
@@ -702,8 +749,209 @@
fsl_pcib_inbound(sc, 1, -1, 0, 0, 0);
fsl_pcib_inbound(sc, 2, -1, 0, 0, 0);
- fsl_pcib_inbound(sc, 3, OCP85XX_TGTIF_RAM1, 0,
- 2U * 1024U * 1024U * 1024U, 0);
+ fsl_pcib_inbound(sc, 3, PIWAR_TRGT_LOCAL, 0,
+ ptoa(Maxmem), 0);
+
+ /* Direct-map the CCSR for MSIs. */
+ /* Freescale PCIe 2.x has a dedicated MSI window. */
+ /* inbound window 8 makes it hit 0xD00 offset, the MSI window. */
+ if (sc->sc_ip_maj >= 2)
+ fsl_pcib_inbound(sc, 8, PIWAR_TRGT_CCSR, ccsrbar_pa,
+ ccsrbar_size, ccsrbar_pa);
+ else
+ fsl_pcib_inbound(sc, 1, PIWAR_TRGT_CCSR, ccsrbar_pa,
+ ccsrbar_size, ccsrbar_pa);
+
+ return (0);
+}
+
+static int fsl_pcib_alloc_msi(device_t dev, device_t child,
+ int count, int maxcount, int *irqs)
+{
+ struct fsl_pcib_softc *sc;
+ vmem_addr_t start;
+ int err, i;
+
+ sc = device_get_softc(dev);
+ if (msi_vmem == NULL)
+ return (ENODEV);
+
+ err = vmem_xalloc(msi_vmem, count, powerof2(count), 0, 0,
+ VMEM_ADDR_MIN, VMEM_ADDR_MAX, M_BESTFIT | M_WAITOK, &start);
+
+ if (err)
+ return (err);
+
+ for (i = 0; i < count; i++)
+ irqs[i] = start + i;
+
+ return (0);
+}
+
+static int fsl_pcib_release_msi(device_t dev, device_t child,
+ int count, int *irqs)
+{
+ if (msi_vmem == NULL)
+ return (ENODEV);
+
+ vmem_xfree(msi_vmem, irqs[0], count);
+ return (0);
+}
+
+static int fsl_pcib_alloc_msix(device_t dev, device_t child, int *irq)
+{
+ return (fsl_pcib_alloc_msi(dev, child, 1, 1, irq));
+}
+
+static int fsl_pcib_release_msix(device_t dev, device_t child, int irq)
+{
+ return (fsl_pcib_release_msi(dev, child, 1, &irq));
+}
+
+static int fsl_pcib_map_msi(device_t dev, device_t child,
+ int irq, uint64_t *addr, uint32_t *data)
+{
+ struct fsl_msi_map *mp;
+
+ SLIST_FOREACH(mp, &fsl_msis, slist) {
+ if (irq >= mp->irq_base && irq < mp->irq_base + FSL_NUM_MSIS)
+ break;
+ }
+
+ if (mp == NULL)
+ return (ENODEV);
+
+ *data = (irq & 255);
+ *addr = ccsrbar_pa + mp->target;
+
+ return (0);
+}
+
+
+/*
+ * Linux device trees put the msi@<x> as children of the SoC, with ranges based
+ * on the CCSR. Since rman doesn't permit overlapping or sub-ranges between
+ * devices (bus_space_subregion(9) could do it, but let's not touch the PIC
+ * driver just to allocate a subregion for a sibling driver). This driver will
+ * use ccsr_write() and ccsr_read() instead.
+ */
+
+#define FSL_NUM_IRQS 8
+#define FSL_NUM_MSI_PER_IRQ 32
+#define FSL_MSI_TARGET 0x140
+
+struct fsl_msi_softc {
+ vm_offset_t sc_base;
+ vm_offset_t sc_target;
+ int sc_msi_base_irq;
+ struct fsl_msi_map sc_map;
+ struct fsl_msi_irq {
+ /* This struct gets passed as the filter private data. */
+ struct fsl_msi_softc *sc_ptr; /* Pointer back to softc. */
+ struct resource *res;
+ int irq;
+ void *cookie;
+ int vectors[FSL_NUM_MSI_PER_IRQ];
+ vm_offset_t reg;
+ } sc_msi_irq[FSL_NUM_IRQS];
+};
+
+static int
+fsl_msi_intr_filter(void *priv)
+{
+ struct fsl_msi_irq *data = priv;
+ uint32_t reg;
+ int i;
+
+ reg = ccsr_read4(ccsrbar_va + data->reg);
+ i = 0;
+ while (reg != 0) {
+ if (reg & 1)
+ powerpc_dispatch_intr(data->vectors[i], NULL);
+ reg >>= 1;
+ i++;
+ }
+
+ return (FILTER_HANDLED);
+}
+
+static int
+fsl_msi_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "fsl,mpic-msi"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Freescale MSI");
+
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+fsl_msi_attach(device_t dev)
+{
+ struct fsl_msi_softc *sc;
+ struct fsl_msi_irq *irq;
+ int i;
+
+ sc = device_get_softc(dev);
+
+ if (msi_vmem == NULL)
+ msi_vmem = vmem_create("MPIC MSI", 0, 0, 1, 1, M_BESTFIT | M_WAITOK);
+
+ /* Manually play with resource entries. */
+ sc->sc_base = bus_get_resource_start(dev, SYS_RES_MEMORY, 0);
+ sc->sc_map.target = bus_get_resource_start(dev, SYS_RES_MEMORY, 1);
+
+ if (sc->sc_map.target == 0)
+ sc->sc_map.target = sc->sc_base + FSL_MSI_TARGET;
+
+ for (i = 0; i < FSL_NUM_IRQS; i++) {
+ irq = &sc->sc_msi_irq[i];
+ irq->irq = i;
+ irq->reg = sc->sc_base + 16 * i;
+ irq->res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
+ &irq->irq, RF_ACTIVE);
+ bus_setup_intr(dev, irq->res, INTR_TYPE_MISC | INTR_MPSAFE,
+ fsl_msi_intr_filter, NULL, irq, &irq->cookie);
+ }
+ sc->sc_map.irq_base = powerpc_register_pic(dev, ofw_bus_get_node(dev),
+ FSL_NUM_MSIS, 0, 0);
+
+ /* Let vmem and the IRQ subsystem work their magic for allocations. */
+ vmem_add(msi_vmem, sc->sc_map.irq_base, FSL_NUM_MSIS, M_WAITOK);
+
+ SLIST_INSERT_HEAD(&fsl_msis, &sc->sc_map, slist);
return (0);
}
+
+static void
+fsl_msi_enable(device_t dev, u_int irq, u_int vector, void **priv)
+{
+ struct fsl_msi_softc *sc;
+ struct fsl_msi_irq *irqd;
+
+ sc = device_get_softc(dev);
+
+ irqd = &sc->sc_msi_irq[irq / FSL_NUM_MSI_PER_IRQ];
+ irqd->vectors[irq % FSL_NUM_MSI_PER_IRQ] = vector;
+}
+
+static device_method_t fsl_msi_methods[] = {
+ DEVMETHOD(device_probe, fsl_msi_probe),
+ DEVMETHOD(device_attach, fsl_msi_attach),
+
+ DEVMETHOD(pic_enable, fsl_msi_enable),
+ DEVMETHOD_END
+};
+
+static devclass_t fsl_msi_devclass;
+
+static driver_t fsl_msi_driver = {
+ "fsl_msi",
+ fsl_msi_methods,
+ sizeof(struct fsl_msi_softc)
+};
+
+EARLY_DRIVER_MODULE(fsl_msi, simplebus, fsl_msi_driver, fsl_msi_devclass, 0, 0,
+ BUS_PASS_INTERRUPT + 1);
Index: sys/powerpc/ofw/openpic_ofw.c
===================================================================
--- sys/powerpc/ofw/openpic_ofw.c
+++ sys/powerpc/ofw/openpic_ofw.c
@@ -139,8 +139,10 @@
OF_getencprop(node, "linux,phandle", &xref, sizeof(xref)) == -1)
xref = node;
- if (ofw_bus_is_compatible(dev, "fsl,mpic"))
+ if (ofw_bus_is_compatible(dev, "fsl,mpic")) {
sc->sc_quirks = OPENPIC_QUIRK_SINGLE_BIND;
+ sc->sc_quirks |= OPENPIC_QUIRK_HIDDEN_IRQS;
+ }
return (openpic_common_attach(dev, xref));
}
Index: sys/powerpc/powerpc/openpic.c
===================================================================
--- sys/powerpc/powerpc/openpic.c
+++ sys/powerpc/powerpc/openpic.c
@@ -52,6 +52,8 @@
#include "pic_if.h"
+#define OPENPIC_NIPIS 4
+
devclass_t openpic_devclass;
/*
@@ -182,6 +184,14 @@
"Version %s, supports %d CPUs and %d irqs\n",
sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
+ /*
+ * Allow more IRQs than what the PIC says it handles. Some Freescale PICs
+ * have MSIs that show up above the PIC's self-described 196 IRQs
+ * (P5020 starts MSI IRQs at 224).
+ */
+ if (sc->sc_quirks & OPENPIC_QUIRK_HIDDEN_IRQS)
+ sc->sc_nirq = OPENPIC_IRQMAX - OPENPIC_NIPIS;
+
for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 15);
@@ -196,7 +206,7 @@
}
/* Reset and disable all IPIs. */
- for (ipi = 0; ipi < 4; ipi++) {
+ for (ipi = 0; ipi < OPENPIC_NIPIS; ipi++) {
x = sc->sc_nirq + ipi;
x |= OPENPIC_IMASK;
x |= 15 << OPENPIC_PRIORITY_SHIFT;
@@ -221,7 +231,7 @@
for (cpu = 0; cpu < sc->sc_ncpu; cpu++)
openpic_write(sc, OPENPIC_PCPU_TPR(cpu), 0);
- powerpc_register_pic(dev, node, sc->sc_nirq, 4, FALSE);
+ powerpc_register_pic(dev, node, sc->sc_nirq, OPENPIC_NIPIS, FALSE);
/* If this is not a cascaded PIC, it must be the root PIC */
if (sc->sc_intr == NULL)
@@ -411,7 +421,7 @@
sc = device_get_softc(dev);
sc->sc_saved_config = bus_read_4(sc->sc_memr, OPENPIC_CONFIG);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < OPENPIC_NIPIS; i++) {
sc->sc_saved_ipis[i] = bus_read_4(sc->sc_memr, OPENPIC_IPI_VECTOR(i));
}
@@ -442,7 +452,7 @@
sc = device_get_softc(dev);
sc->sc_saved_config = bus_read_4(sc->sc_memr, OPENPIC_CONFIG);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < OPENPIC_NIPIS; i++) {
bus_write_4(sc->sc_memr, OPENPIC_IPI_VECTOR(i), sc->sc_saved_ipis[i]);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Dec 2, 11:49 PM (19 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14994943
Default Alt Text
D22014.diff (12 KB)
Attached To
Mode
D22014: powerpc/mpc85xx: Add MSI support for Freescale PowerPC SoCs
Attached
Detach File
Event Timeline
Log In to Comment