svn commit: r208423 - in projects/ppc64/sys/powerpc: include ofw
powermac
Nathan Whitehorn
nwhitehorn at FreeBSD.org
Sat May 22 21:51:18 UTC 2010
Author: nwhitehorn
Date: Sat May 22 21:51:17 2010
New Revision: 208423
URL: http://svn.freebsd.org/changeset/base/208423
Log:
Implement MSI support on the HT bus of CPC945-based machines. MSI on
the northbridge's PCI-E port will come later.
This will be merged to HEAD after required multiple-PIC changes.
Modified:
projects/ppc64/sys/powerpc/include/intr_machdep.h
projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c
projects/ppc64/sys/powerpc/powermac/cpcht.c
Modified: projects/ppc64/sys/powerpc/include/intr_machdep.h
==============================================================================
--- projects/ppc64/sys/powerpc/include/intr_machdep.h Sat May 22 21:38:57 2010 (r208422)
+++ projects/ppc64/sys/powerpc/include/intr_machdep.h Sat May 22 21:51:17 2010 (r208423)
@@ -35,7 +35,7 @@
#define INTR_INTLINE(irq) (irq & ((1 << IGN_SHIFT) - 1))
#define INTR_IGN(irq) (irq >> IGN_SHIFT)
-#define INTR_VEC(pic_id, irq) ((powerpc_ign_lookup(pic_id) << IGN_SHIFT) | irq)
+#define INTR_VEC(pic_id, irq) ((powerpc_ign_lookup(pic_id) << IGN_SHIFT) | (irq))
/*
* Default base address for MSI messages on PowerPC
Modified: projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c
==============================================================================
--- projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c Sat May 22 21:38:57 2010 (r208422)
+++ projects/ppc64/sys/powerpc/ofw/ofw_pcib_pci.c Sat May 22 21:51:17 2010 (r208423)
@@ -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: projects/ppc64/sys/powerpc/powermac/cpcht.c
==============================================================================
--- projects/ppc64/sys/powerpc/powermac/cpcht.c Sat May 22 21:38:57 2010 (r208422)
+++ projects/ppc64/sys/powerpc/powermac/cpcht.c Sat May 22 21:51:17 2010 (r208423)
@@ -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);
}
More information about the svn-src-projects
mailing list