Date: Fri, 18 Jun 2010 17:39:56 +0000 (UTC) From: Nathan Whitehorn <nwhitehorn@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r209310 - in head/sys/powerpc: ofw powermac Message-ID: <201006181739.o5IHdu6x025919@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: nwhitehorn Date: Fri Jun 18 17:39:56 2010 New Revision: 209310 URL: http://svn.freebsd.org/changeset/base/209310 Log: Add MSI support for PCI devices attached to the CPC925 and CPC945 bridges found in Apple and IBM G5 systems. Modified: head/sys/powerpc/ofw/ofw_pcib_pci.c head/sys/powerpc/powermac/cpcht.c Modified: head/sys/powerpc/ofw/ofw_pcib_pci.c ============================================================================== --- head/sys/powerpc/ofw/ofw_pcib_pci.c Fri Jun 18 17:22:08 2010 (r209309) +++ head/sys/powerpc/ofw/ofw_pcib_pci.c Fri Jun 18 17:39:56 2010 (r209310) @@ -76,6 +76,11 @@ static device_method_t ofw_pcib_pci_meth DEVMETHOD(pcib_read_config, pcib_read_config), DEVMETHOD(pcib_write_config, pcib_write_config), DEVMETHOD(pcib_route_interrupt, ofw_pcib_pci_route_interrupt), + DEVMETHOD(pcib_alloc_msi, pcib_alloc_msi), + DEVMETHOD(pcib_release_msi, pcib_release_msi), + DEVMETHOD(pcib_alloc_msix, pcib_alloc_msix), + DEVMETHOD(pcib_release_msix, pcib_release_msix), + DEVMETHOD(pcib_map_msi, pcib_map_msi), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, ofw_pcib_pci_get_node), Modified: head/sys/powerpc/powermac/cpcht.c ============================================================================== --- head/sys/powerpc/powermac/cpcht.c Fri Jun 18 17:22:08 2010 (r209309) +++ head/sys/powerpc/powermac/cpcht.c Fri Jun 18 17:39:56 2010 (r209310) @@ -31,6 +31,8 @@ #include <sys/bus.h> #include <sys/conf.h> #include <sys/kernel.h> +#include <sys/pciio.h> +#include <sys/rman.h> #include <dev/ofw/openfirm.h> #include <dev/ofw/ofw_pci.h> @@ -45,8 +47,6 @@ #include <machine/pio.h> #include <machine/resource.h> -#include <sys/rman.h> - #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> @@ -89,6 +89,16 @@ static void cpcht_write_config(device_t u_int, u_int32_t, int); static int cpcht_route_interrupt(device_t bus, device_t dev, int pin); +static int cpcht_alloc_msi(device_t dev, device_t child, + int count, int maxcount, int *irqs); +static int cpcht_release_msi(device_t dev, device_t child, + int count, int *irqs); +static int cpcht_alloc_msix(device_t dev, device_t child, + int *irq); +static int cpcht_release_msix(device_t dev, device_t child, + int irq); +static int cpcht_map_msi(device_t dev, device_t child, + int irq, uint64_t *addr, uint32_t *data); /* * ofw_bus interface @@ -119,6 +129,11 @@ static device_method_t cpcht_methods[] = DEVMETHOD(pcib_read_config, cpcht_read_config), DEVMETHOD(pcib_write_config, cpcht_write_config), DEVMETHOD(pcib_route_interrupt, cpcht_route_interrupt), + DEVMETHOD(pcib_alloc_msi, cpcht_alloc_msi), + DEVMETHOD(pcib_release_msi, cpcht_release_msi), + DEVMETHOD(pcib_alloc_msix, cpcht_alloc_msix), + DEVMETHOD(pcib_release_msix, cpcht_release_msix), + DEVMETHOD(pcib_map_msi, cpcht_map_msi), /* ofw_bus interface */ DEVMETHOD(ofw_bus_get_node, cpcht_get_node), @@ -126,6 +141,10 @@ static device_method_t cpcht_methods[] = }; struct cpcht_irq { + enum { + IRQ_NONE, IRQ_HT, IRQ_MSI, IRQ_INTERNAL + } irq_type; + int ht_source; vm_offset_t ht_base; @@ -135,6 +154,7 @@ struct cpcht_irq { }; static struct cpcht_irq *cpcht_irqmap = NULL; +uint32_t cpcht_msipic = 0; struct cpcht_softc { device_t sc_dev; @@ -144,6 +164,7 @@ struct cpcht_softc { struct rman sc_mem_rman; struct cpcht_irq htirq_map[128]; + struct mtx htirq_mtx; }; static driver_t cpcht_driver = { @@ -199,7 +220,7 @@ cpcht_attach(device_t dev) struct cpcht_softc *sc; phandle_t node, child; u_int32_t reg[3]; - int error; + int i, error; node = ofw_bus_get_node(dev); sc = device_get_softc(dev); @@ -228,6 +249,9 @@ cpcht_attach(device_t dev) */ bzero(sc->htirq_map, sizeof(sc->htirq_map)); + mtx_init(&sc->htirq_mtx, "cpcht irq", NULL, MTX_DEF); + for (i = 0; i < 8; i++) + sc->htirq_map[i].irq_type = IRQ_INTERNAL; for (child = OF_child(node); child != 0; child = OF_peer(child)) cpcht_configure_htbridge(dev, child); @@ -336,6 +360,7 @@ cpcht_configure_htbridge(device_t dev, p irq | HTAPIC_MASK, 4); irq = (irq >> 16) & 0xff; + sc->htirq_map[irq].irq_type = IRQ_HT; sc->htirq_map[irq].ht_source = i; sc->htirq_map[irq].ht_base = sc->sc_data + (((((s & 0x1f) << 3) | (f & 0x07)) << 8) | (ptr)); @@ -584,6 +609,129 @@ cpcht_deactivate_resource(device_t bus, return (rman_deactivate_resource(res)); } +static int +cpcht_alloc_msi(device_t dev, device_t child, int count, int maxcount, + int *irqs) +{ + struct cpcht_softc *sc; + int i, j; + + sc = device_get_softc(dev); + j = 0; + + /* Bail if no MSI PIC yet */ + if (cpcht_msipic == 0) + return (ENXIO); + + mtx_lock(&sc->htirq_mtx); + for (i = 8; i < 124 - count; i++) { + for (j = 0; j < count; j++) { + if (sc->htirq_map[i+j].irq_type != IRQ_NONE) + break; + } + if (j == count) + break; + + i += j; /* We know there isn't a large enough run */ + } + + if (j != count) { + mtx_unlock(&sc->htirq_mtx); + return (ENXIO); + } + + for (j = 0; j < count; j++) { + irqs[j] = INTR_VEC(cpcht_msipic, i+j); + sc->htirq_map[i+j].irq_type = IRQ_MSI; + } + mtx_unlock(&sc->htirq_mtx); + + return (0); +} + +static int +cpcht_release_msi(device_t dev, device_t child, int count, int *irqs) +{ + struct cpcht_softc *sc; + int i; + + sc = device_get_softc(dev); + + mtx_lock(&sc->htirq_mtx); + for (i = 0; i < count; i++) + sc->htirq_map[irqs[i] & 0xff].irq_type = IRQ_NONE; + mtx_unlock(&sc->htirq_mtx); + + return (0); +} + +static int +cpcht_alloc_msix(device_t dev, device_t child, int *irq) +{ + struct cpcht_softc *sc; + int i; + + sc = device_get_softc(dev); + + /* Bail if no MSI PIC yet */ + if (cpcht_msipic == 0) + return (ENXIO); + + mtx_lock(&sc->htirq_mtx); + for (i = 8; i < 124; i++) { + if (sc->htirq_map[i].irq_type == IRQ_NONE) { + sc->htirq_map[i].irq_type = IRQ_MSI; + *irq = INTR_VEC(cpcht_msipic, i); + + mtx_unlock(&sc->htirq_mtx); + return (0); + } + } + mtx_unlock(&sc->htirq_mtx); + + return (ENXIO); +} + +static int +cpcht_release_msix(device_t dev, device_t child, int irq) +{ + struct cpcht_softc *sc; + + sc = device_get_softc(dev); + + mtx_lock(&sc->htirq_mtx); + sc->htirq_map[irq & 0xff].irq_type = IRQ_NONE; + mtx_unlock(&sc->htirq_mtx); + + return (0); +} + +static int +cpcht_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, + uint32_t *data) +{ + device_t pcib; + struct pci_devinfo *dinfo; + struct pcicfg_ht *ht = NULL; + + for (pcib = child; pcib != dev; pcib = + device_get_parent(device_get_parent(pcib))) { + dinfo = device_get_ivars(pcib); + ht = &dinfo->cfg.ht; + + if (ht == NULL) + continue; + } + + if (ht == NULL) + return (ENXIO); + + *addr = ht->ht_msiaddr; + *data = irq & 0xff; + + return (0); +} + /* * Driver for the integrated MPIC on U3/U4 (CPC925/CPC945) */ @@ -671,6 +819,15 @@ openpic_cpcht_attach(device_t dev) for (irq = 4; irq < 124; irq++) openpic_config(dev, irq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); + /* + * Use this PIC for MSI only if it is the root PIC. This may not + * be necessary, but Linux does it, and I cannot find any U3 machines + * with MSI devices to test. + */ + + if (dev == root_pic) + cpcht_msipic = PIC_ID(dev); + return (0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201006181739.o5IHdu6x025919>