summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
authorgrehan <grehan@FreeBSD.org>2004-01-13 11:24:36 +0000
committergrehan <grehan@FreeBSD.org>2004-01-13 11:24:36 +0000
commitf31f435513a72bd9462d2c1602f1a1f023f17497 (patch)
tree90c414efa278baec94d53f3908b2cf1e9a36d216 /sys/powerpc
parent5e6c3e74a5c479c3a0a6cf5c9aea54650ece04f5 (diff)
downloadFreeBSD-src-f31f435513a72bd9462d2c1602f1a1f023f17497.zip
FreeBSD-src-f31f435513a72bd9462d2c1602f1a1f023f17497.tar.gz
Make the OpenPic driver bus-independent, with attachments for
the MacIO chip and PSIM's IOBus. Bus-specific drivers should use the identify method to attach themselves to nexus so interrupt can be allocated before the h/w is probed. The 'early attach' routine in openpic is used for this stage of boot. When h/w is probed, the openpic can be attached properly. It will enable interrupts allocated prior to this.
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/include/openpicvar.h30
-rw-r--r--sys/powerpc/powermac/openpic_macio.c231
-rw-r--r--sys/powerpc/powerpc/openpic.c241
-rw-r--r--sys/powerpc/psim/openpic_iobus.c219
4 files changed, 557 insertions, 164 deletions
diff --git a/sys/powerpc/include/openpicvar.h b/sys/powerpc/include/openpicvar.h
index 6f7cff6..5001b9b 100644
--- a/sys/powerpc/include/openpicvar.h
+++ b/sys/powerpc/include/openpicvar.h
@@ -28,13 +28,41 @@
#ifndef _POWERPC_OPENPICVAR_H_
#define _POWERPC_OPENPICVAR_H_
+#define OPENPIC_DEVSTR "OpenPIC Interrupt Controller"
+
+#define OPENPIC_IRQMAX 256 /* h/w allows more */
+
struct openpic_softc {
- vm_offset_t sc_base;
char *sc_version;
u_int sc_ncpu;
u_int sc_nirq;
int sc_psim;
struct rman sc_rman;
+ bus_space_tag_t sc_bt;
+ bus_space_handle_t sc_bh;
+ u_int sc_hwprobed;
+ u_int sc_early_done;
+ device_t sc_altdev;
+ u_char sc_irqrsv[OPENPIC_IRQMAX]; /* pre-h/w reservation */
};
+/*
+ * Bus-independent attach i/f
+ */
+int openpic_early_attach(device_t);
+int openpic_attach(device_t);
+
+/*
+ * PIC interface.
+ */
+struct resource *openpic_allocate_intr(device_t, device_t, int *,
+ u_long, u_int);
+int openpic_setup_intr(device_t, device_t,
+ struct resource *, int, driver_intr_t, void *,
+ void **);
+int openpic_teardown_intr(device_t, device_t,
+ struct resource *, void *);
+int openpic_release_intr(device_t dev, device_t, int,
+ struct resource *res);
+
#endif /* _POWERPC_OPENPICVAR_H_ */
diff --git a/sys/powerpc/powermac/openpic_macio.c b/sys/powerpc/powermac/openpic_macio.c
new file mode 100644
index 0000000..832a043
--- /dev/null
+++ b/sys/powerpc/powermac/openpic_macio.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2003 by Peter Grehan. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * The macio attachment for the OpenPIC interrupt controller.
+ * A nexus driver is defined so the number of interrupts can be
+ * determined early in the boot sequence before the hardware
+ * is accessed - the interrupt i/f is installed at this time,
+ * and when h/w is finally accessed, interrupt sources allocated
+ * prior to this are activated
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
+#include <machine/nexusvar.h>
+#include <machine/pio.h>
+#include <machine/resource.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <sys/rman.h>
+
+#include <machine/openpicvar.h>
+#include <powerpc/powermac/maciovar.h>
+
+#include "pic_if.h"
+
+struct openpic_ofw_softc {
+ struct openpic_softc osc;
+ struct resource *sc_memr; /* macio bus resource */
+ device_t sc_ndev; /* nexus device */
+};
+
+static struct openpic_ofw_softc *ofwpicsoftc;
+
+/*
+ * MacIO interface
+ */
+static void openpic_ofw_identify(driver_t *, device_t);
+static int openpic_ofw_probe(device_t);
+static int openpic_ofw_attach(device_t);
+static int openpic_macio_probe(device_t);
+static int openpic_macio_attach(device_t);
+
+/*
+ * Nexus attachment
+ */
+static device_method_t openpic_ofw_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, openpic_ofw_identify),
+ DEVMETHOD(device_probe, openpic_ofw_probe),
+ DEVMETHOD(device_attach, openpic_ofw_attach),
+
+ /* PIC interface */
+ DEVMETHOD(pic_allocate_intr, openpic_allocate_intr),
+ DEVMETHOD(pic_setup_intr, openpic_setup_intr),
+ DEVMETHOD(pic_teardown_intr, openpic_teardown_intr),
+ DEVMETHOD(pic_release_intr, openpic_release_intr),
+
+ { 0, 0 }
+};
+
+static driver_t openpic_ofw_driver = {
+ "openpic",
+ openpic_ofw_methods,
+ sizeof(struct openpic_ofw_softc)
+};
+
+static devclass_t openpic_ofw_devclass;
+
+DRIVER_MODULE(openpic_ofw, nexus, openpic_ofw_driver, openpic_ofw_devclass,
+ 0, 0);
+
+static void
+openpic_ofw_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+ phandle_t chosen, pic;
+ char type[40];
+
+ chosen = OF_finddevice("/chosen");
+ if (chosen == -1)
+ return;
+
+ if (OF_getprop(chosen, "interrupt-controller", &pic, 4) != 4)
+ return;
+
+ OF_getprop(pic, "device_type", type, sizeof(type));
+
+ if (strcmp(type, "open-pic") != 0)
+ return;
+
+ child = BUS_ADD_CHILD(parent, 0, "openpic", 0);
+ if (child != NULL)
+ nexus_set_device_type(child, "macio");
+}
+
+static int
+openpic_ofw_probe(device_t dev)
+{
+ char *name;
+ char *type;
+
+ name = nexus_get_name(dev);
+ type = nexus_get_device_type(dev);
+
+ if (strcmp(name, "openpic") != 0 ||
+ strcmp(type, "macio") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, OPENPIC_DEVSTR);
+ return (0);
+}
+
+static int
+openpic_ofw_attach(device_t dev)
+{
+ KASSERT(ofwpicsoftc == NULL, ("ofw openpic: already probed"));
+ ofwpicsoftc = device_get_softc(dev);
+ ofwpicsoftc->sc_ndev = dev;
+
+ nexus_install_intcntlr(dev);
+ openpic_early_attach(dev);
+ return (0);
+}
+
+/*
+ * MacIO attachment
+ */
+static device_method_t openpic_macio_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, openpic_macio_probe),
+ DEVMETHOD(device_attach, openpic_macio_attach),
+
+ { 0, 0 },
+};
+
+static driver_t openpic_macio_driver = {
+ "openpicmacio",
+ openpic_macio_methods,
+ 0
+};
+
+static devclass_t openpic_macio_devclass;
+
+DRIVER_MODULE(openpicmacio, macio, openpic_macio_driver,
+ openpic_macio_devclass, 0, 0);
+
+static int
+openpic_macio_probe(device_t dev)
+{
+ char *type = macio_get_devtype(dev);
+
+ if (strcmp(type, "open-pic") != 0)
+ return (ENXIO);
+
+ /*
+ * The description was already printed out in the nexus
+ * probe, so don't do it again here
+ */
+ device_set_desc(dev, "OpenPIC MacIO interrupt cell");
+ if (!bootverbose)
+ device_quiet(dev);
+ return (0);
+}
+
+static int
+openpic_macio_attach(device_t dev)
+{
+ struct openpic_ofw_softc *sc;
+ int rid;
+
+ sc = ofwpicsoftc;
+ KASSERT(sc != NULL, ("pic not nexus-probed\n"));
+
+ rid = 0;
+ sc->sc_memr = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+
+ if (sc->sc_memr == NULL) {
+ device_printf(dev, "Could not alloc mem resource!\n");
+ return (ENXIO);
+ }
+
+ sc->osc.sc_bt = rman_get_bustag(sc->sc_memr);
+ sc->osc.sc_bh = rman_get_bushandle(sc->sc_memr);
+ sc->osc.sc_altdev = dev;
+
+ return (openpic_attach(sc->sc_ndev));
+}
+
+
diff --git a/sys/powerpc/powerpc/openpic.c b/sys/powerpc/powerpc/openpic.c
index 864fae4..cd44cff 100644
--- a/sys/powerpc/powerpc/openpic.c
+++ b/sys/powerpc/powerpc/openpic.c
@@ -31,17 +31,10 @@
#include <sys/conf.h>
#include <sys/kernel.h>
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_pci.h>
-
-#include <dev/pci/pcivar.h>
-#include <dev/pci/pcireg.h>
-
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/intr_machdep.h>
#include <machine/md_var.h>
-#include <machine/nexusvar.h>
#include <machine/pio.h>
#include <machine/resource.h>
@@ -56,25 +49,6 @@
#include "pic_if.h"
/*
- * Device interface.
- */
-static int openpic_probe(device_t);
-static int openpic_attach(device_t);
-
-/*
- * PIC interface.
- */
-static struct resource *openpic_allocate_intr(device_t, device_t, int *,
- u_long, u_int);
-static int openpic_setup_intr(device_t, device_t,
- struct resource *, int, driver_intr_t, void *,
- void **);
-static int openpic_teardown_intr(device_t, device_t,
- struct resource *, void *);
-static int openpic_release_intr(device_t dev, device_t, int,
- struct resource *res);
-
-/*
* Local routines
*/
static u_int openpic_read(struct openpic_softc *, int);
@@ -85,89 +59,56 @@ static void openpic_enable_irq(struct openpic_softc *, int, int);
static void openpic_disable_irq(struct openpic_softc *, int);
static void openpic_set_priority(struct openpic_softc *, int, int);
static void openpic_intr(void);
-static void irq_enable(uintptr_t);
-static void irq_disable(uintptr_t);
+static void openpic_ext_enable_irq(uintptr_t);
+static void openpic_ext_disable_irq(uintptr_t);
+
+/* XXX This limits us to one openpic */
+static struct openpic_softc *openpic_softc;
/*
- * Driver methods.
+ * Called at nexus-probe time to allow interrupts to be enabled by
+ * devices that are probed before the OpenPIC h/w is probed.
*/
-static device_method_t openpic_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, openpic_probe),
- DEVMETHOD(device_attach, openpic_attach),
-
- /* PIC interface */
- DEVMETHOD(pic_allocate_intr, openpic_allocate_intr),
- DEVMETHOD(pic_setup_intr, openpic_setup_intr),
- DEVMETHOD(pic_teardown_intr, openpic_teardown_intr),
- DEVMETHOD(pic_release_intr, openpic_release_intr),
+int
+openpic_early_attach(device_t dev)
+{
+ struct openpic_softc *sc;
- { 0, 0 }
-};
+ sc = device_get_softc(dev);
+ openpic_softc = sc;
-static driver_t openpic_driver = {
- "openpic",
- openpic_methods,
- sizeof(struct openpic_softc)
-};
+ sc->sc_rman.rm_type = RMAN_ARRAY;
+ sc->sc_rman.rm_descr = device_get_nameunit(dev);
-static devclass_t openpic_devclass;
+ if (rman_init(&sc->sc_rman) != 0 ||
+ rman_manage_region(&sc->sc_rman, 0, OPENPIC_IRQMAX-1) != 0) {
+ device_printf(dev, "could not set up resource management");
+ return (ENXIO);
+ }
-DRIVER_MODULE(openpic, nexus, openpic_driver, openpic_devclass, 0, 0);
+ intr_init(openpic_intr, OPENPIC_IRQMAX, openpic_ext_enable_irq,
+ openpic_ext_disable_irq);
-static struct openpic_softc *softc; /* XXX This limits us to one openpic */
+ sc->sc_early_done = 1;
-/*
- * Device interface
- */
+ return (0);
+}
-static int
-openpic_probe(device_t dev)
+int
+openpic_attach(device_t dev)
{
- struct openpic_softc *sc;
- phandle_t node, parent;
- char *type;
- char *compat;
- u_int32_t reg[5], val;
- vm_offset_t macio_base;
- vm_offset_t opic_base;
-
- sc = device_get_softc(dev);
- node = nexus_get_node(dev);
- type = nexus_get_device_type(dev);
- compat = nexus_get_compatible(dev);
-
- if (type == NULL)
- return (ENXIO);
-
- if (strcmp(type, "open-pic") != 0)
- return (ENXIO);
+ struct openpic_softc *sc;
+ u_int irq;
+ u_int32_t x;
- if (strcmp(compat, "psim,open-pic") == 0) {
- sc->sc_psim = 1;
-
- if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
- return (ENXIO);
-
- opic_base = reg[1];
- } else {
- parent = OF_parent(node);
- if (OF_getprop(parent, "assigned-addresses",
- reg, sizeof(reg)) < 20)
- return (ENXIO);
-
- macio_base = (vm_offset_t)reg[2];
-
- if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8)
- return (ENXIO);
-
- opic_base = macio_base + reg[0];
- }
+ sc = device_get_softc(dev);
+ sc->sc_hwprobed = 1;
- sc->sc_base = (vm_offset_t)pmap_mapdev(opic_base, OPENPIC_SIZE);
+ if (!sc->sc_early_done)
+ openpic_early_attach(dev);
- val = openpic_read(sc, OPENPIC_FEATURE);
- switch (val & OPENPIC_FEATURE_VERSION_MASK) {
+ x = openpic_read(sc, OPENPIC_FEATURE);
+ switch (x & OPENPIC_FEATURE_VERSION_MASK) {
case 1:
sc->sc_version = "1.0";
break;
@@ -182,9 +123,9 @@ openpic_probe(device_t dev)
break;
}
- sc->sc_ncpu = ((val & OPENPIC_FEATURE_LAST_CPU_MASK) >>
+ sc->sc_ncpu = ((x & OPENPIC_FEATURE_LAST_CPU_MASK) >>
OPENPIC_FEATURE_LAST_CPU_SHIFT) + 1;
- sc->sc_nirq = ((val & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
+ sc->sc_nirq = ((x & OPENPIC_FEATURE_LAST_IRQ_MASK) >>
OPENPIC_FEATURE_LAST_IRQ_SHIFT) + 1;
/*
@@ -193,31 +134,10 @@ openpic_probe(device_t dev)
if (sc->sc_psim)
sc->sc_nirq--;
- device_set_desc(dev, "OpenPIC interrupt controller");
- return (0);
-}
-
-static int
-openpic_attach(device_t dev)
-{
- struct openpic_softc *sc;
- u_int32_t irq, x;
-
- sc = device_get_softc(dev);
- softc = sc;
-
- device_printf(dev,
- "Version %s, supports %d CPUs and %d irqs\n",
- sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
-
- sc->sc_rman.rm_type = RMAN_ARRAY;
- sc->sc_rman.rm_descr = device_get_nameunit(dev);
-
- if (rman_init(&sc->sc_rman) != 0 ||
- rman_manage_region(&sc->sc_rman, 0, sc->sc_nirq - 1) != 0) {
- device_printf(dev, "could not set up resource management");
- return (ENXIO);
- }
+ if (bootverbose)
+ device_printf(dev,
+ "Version %s, supports %d CPUs and %d irqs\n",
+ sc->sc_version, sc->sc_ncpu, sc->sc_nirq);
/* disable all interrupts */
for (irq = 0; irq < sc->sc_nirq; irq++)
@@ -254,10 +174,12 @@ openpic_attach(device_t dev)
openpic_eoi(sc, 0);
}
+ /* enable pre-h/w reserved irqs, disable all others */
for (irq = 0; irq < sc->sc_nirq; irq++)
- openpic_disable_irq(sc, irq);
-
- intr_init(openpic_intr, sc->sc_nirq, irq_enable, irq_disable);
+ if (sc->sc_irqrsv[irq])
+ openpic_enable_irq(sc, irq, IST_LEVEL);
+ else
+ openpic_disable_irq(sc, irq);
return (0);
}
@@ -266,7 +188,7 @@ openpic_attach(device_t dev)
* PIC interface
*/
-static struct resource *
+struct resource *
openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
u_int flags)
{
@@ -278,6 +200,12 @@ openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
needactivate = flags & RF_ACTIVE;
flags &= ~RF_ACTIVE;
+ if (sc->sc_hwprobed && (intr > sc->sc_nirq)) {
+ device_printf(dev, "interrupt reservation %ld out of range\n",
+ intr);
+ return (NULL);
+ }
+
rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
if (rv == NULL) {
device_printf(dev, "interrupt reservation failed for %s\n",
@@ -298,7 +226,7 @@ openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
return (rv);
}
-static int
+int
openpic_setup_intr(device_t dev, device_t child, struct resource *res,
int flags, driver_intr_t *intr, void *arg, void **cookiep)
{
@@ -325,12 +253,16 @@ openpic_setup_intr(device_t dev, device_t child, struct resource *res,
error = inthand_add(device_get_nameunit(child), res->r_start, intr,
arg, flags, cookiep);
- openpic_enable_irq(sc, res->r_start, IST_LEVEL);
+
+ if (sc->sc_hwprobed)
+ openpic_enable_irq(sc, res->r_start, IST_LEVEL);
+ else
+ sc->sc_irqrsv[res->r_start] = 1;
return (error);
}
-static int
+int
openpic_teardown_intr(device_t dev, device_t child, struct resource *res,
void *ih)
{
@@ -345,7 +277,7 @@ openpic_teardown_intr(device_t dev, device_t child, struct resource *res,
return (error);
}
-static int
+int
openpic_release_intr(device_t dev, device_t child, int rid,
struct resource *res)
{
@@ -367,29 +299,13 @@ openpic_release_intr(device_t dev, device_t child, int rid,
static u_int
openpic_read(struct openpic_softc *sc, int reg)
{
- volatile unsigned char *addr;
-
- addr = (unsigned char *)sc->sc_base + reg;
-#if 0
- printf("openpic: reading from %p (0x%08x + 0x%08x)\n", addr,
- sc->sc_base, reg);
-#endif
-
- return in32rb(addr);
+ return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
}
static void
openpic_write(struct openpic_softc *sc, int reg, u_int val)
{
- volatile unsigned char *addr;
-
- addr = (unsigned char *)sc->sc_base + reg;
-#if 0
- printf("openpic: writing to %p (0x%08x + 0x%08x)\n", addr, sc->sc_base,
- reg);
-#endif
-
- out32rb(addr, val);
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
}
static int
@@ -402,13 +318,6 @@ static void
openpic_eoi(struct openpic_softc *sc, int cpu)
{
openpic_write(sc, OPENPIC_EOI(cpu), 0);
- if (!sc->sc_psim) {
- /*
- * Probably not needed, since appropriate eieio/sync
- * is done in out32rb. See Darwin src.
- */
- openpic_read(sc, OPENPIC_EOI(cpu));
- }
}
static void
@@ -449,18 +358,20 @@ openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
static void
openpic_intr(void)
{
+ struct openpic_softc *sc;
int irq;
u_int32_t msr;
+ sc = openpic_softc;
msr = mfmsr();
- irq = openpic_read_irq(softc, 0);
+ irq = openpic_read_irq(sc, 0);
if (irq == 255) {
return;
}
start:
- openpic_disable_irq(softc, irq);
+ openpic_disable_irq(sc, irq);
/*mtmsr(msr | PSL_EE);*/
/* do the interrupt thang */
@@ -468,23 +379,27 @@ start:
mtmsr(msr);
- openpic_eoi(softc, 0);
+ openpic_eoi(sc, 0);
- irq = openpic_read_irq(softc, 0);
+ irq = openpic_read_irq(sc, 0);
if (irq != 255)
goto start;
}
static void
-irq_enable(uintptr_t irq)
+openpic_ext_enable_irq(uintptr_t irq)
{
+ if (!openpic_softc->sc_hwprobed)
+ return;
- openpic_enable_irq(softc, irq, IST_LEVEL);
+ openpic_enable_irq(openpic_softc, irq, IST_LEVEL);
}
static void
-irq_disable(uintptr_t irq)
+openpic_ext_disable_irq(uintptr_t irq)
{
+ if (!openpic_softc->sc_hwprobed)
+ return;
- openpic_disable_irq(softc, irq);
+ openpic_disable_irq(openpic_softc, irq);
}
diff --git a/sys/powerpc/psim/openpic_iobus.c b/sys/powerpc/psim/openpic_iobus.c
new file mode 100644
index 0000000..5bbeb14
--- /dev/null
+++ b/sys/powerpc/psim/openpic_iobus.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2003 by Peter Grehan. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * The psim iobus attachment for the OpenPIC interrupt controller.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+
+#include <dev/ofw/openfirm.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
+#include <machine/nexusvar.h>
+#include <machine/pio.h>
+#include <machine/resource.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <sys/rman.h>
+
+#include <machine/openpicvar.h>
+#include <powerpc/psim/iobusvar.h>
+
+#include "pic_if.h"
+
+struct openpic_iobus_softc {
+ struct openpic_softc osc;
+ struct resource *sc_memr; /* iobus mem resource */
+ device_t sc_ndev; /* nexus device */
+};
+
+static struct openpic_iobus_softc *ppicsoftc;
+
+/*
+ * MacIO interface
+ */
+static void openpic_psim_identify(driver_t *, device_t);
+static int openpic_psim_probe(device_t);
+static int openpic_psim_attach(device_t);
+static int openpic_iobus_probe(device_t);
+static int openpic_iobus_attach(device_t);
+
+/*
+ * Nexus attachment
+ */
+static device_method_t openpic_psim_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, openpic_psim_identify),
+ DEVMETHOD(device_probe, openpic_psim_probe),
+ DEVMETHOD(device_attach, openpic_psim_attach),
+
+ /* PIC interface */
+ DEVMETHOD(pic_allocate_intr, openpic_allocate_intr),
+ DEVMETHOD(pic_setup_intr, openpic_setup_intr),
+ DEVMETHOD(pic_teardown_intr, openpic_teardown_intr),
+ DEVMETHOD(pic_release_intr, openpic_release_intr),
+
+ { 0, 0 }
+};
+
+static driver_t openpic_psim_driver = {
+ "openpic",
+ openpic_psim_methods,
+ sizeof(struct openpic_iobus_softc)
+};
+
+static devclass_t openpic_psim_devclass;
+
+DRIVER_MODULE(openpic_psim, nexus, openpic_psim_driver, openpic_psim_devclass,
+ 0, 0);
+
+static void
+openpic_psim_identify(driver_t *driver, device_t parent)
+{
+ device_t child;
+ phandle_t pic;
+
+ pic = OF_finddevice("/iobus/opic");
+ if (pic == -1)
+ return;
+
+ child = BUS_ADD_CHILD(parent, 0, "openpic", 0);
+ if (child != NULL)
+ nexus_set_device_type(child, "psim");
+}
+
+static int
+openpic_psim_probe(device_t dev)
+{
+ char *name;
+ char *type;
+
+ name = nexus_get_name(dev);
+ type = nexus_get_device_type(dev);
+
+ if (strcmp(name, "openpic") != 0 ||
+ strcmp(type, "psim") != 0)
+ return (ENXIO);
+
+ device_set_desc(dev, OPENPIC_DEVSTR);
+ return (0);
+}
+
+static int
+openpic_psim_attach(device_t dev)
+{
+ KASSERT(ppicsoftc == NULL, ("iobus openpic: already probed"));
+ ppicsoftc = device_get_softc(dev);
+ ppicsoftc->sc_ndev = dev;
+
+ nexus_install_intcntlr(dev);
+ openpic_early_attach(dev);
+ return (0);
+}
+
+/*
+ * PSIM IOBus attachment
+ */
+static device_method_t openpic_iobus_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, openpic_iobus_probe),
+ DEVMETHOD(device_attach, openpic_iobus_attach),
+
+ { 0, 0 },
+};
+
+static driver_t openpic_iobus_driver = {
+ "openpiciobus",
+ openpic_iobus_methods,
+ 0
+};
+
+static devclass_t openpic_iobus_devclass;
+
+DRIVER_MODULE(openpiciobus, iobus, openpic_iobus_driver,
+ openpic_iobus_devclass, 0, 0);
+
+static int
+openpic_iobus_probe(device_t dev)
+{
+ char *name;
+
+ name = iobus_get_name(dev);
+ if (strcmp(name, "interrupt-controller") != 0)
+ return (ENXIO);
+
+ /*
+ * The description was already printed out in the nexus
+ * probe, so don't do it again here
+ */
+ device_set_desc(dev, "OpenPIC IOBus interrupt cell");
+ if (!bootverbose)
+ device_quiet(dev);
+ return (0);
+}
+
+static int
+openpic_iobus_attach(device_t dev)
+{
+ struct openpic_iobus_softc *sc;
+ int rid;
+
+ sc = ppicsoftc;
+ KASSERT(sc != NULL, ("pic not nexus-probed\n"));
+
+ rid = 0;
+ sc->sc_memr = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1,
+ RF_ACTIVE);
+
+ if (sc->sc_memr == NULL) {
+ device_printf(dev, "Could not alloc mem resource!\n");
+ return (ENXIO);
+ }
+
+ sc->osc.sc_psim = 1;
+ sc->osc.sc_bt = rman_get_bustag(sc->sc_memr);
+ sc->osc.sc_bh = rman_get_bushandle(sc->sc_memr);
+ sc->osc.sc_altdev = dev;
+
+ return (openpic_attach(sc->sc_ndev));
+}
+
+
OpenPOWER on IntegriCloud