Page MenuHomeFreeBSD

D22014.diff
No OneTemporary

D22014.diff

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

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)

Event Timeline