summaryrefslogtreecommitdiffstats
path: root/sys/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'sys/powerpc')
-rw-r--r--sys/powerpc/aim/interrupt.c19
-rw-r--r--sys/powerpc/aim/nexus.c95
-rw-r--r--sys/powerpc/include/intr_machdep.h29
-rw-r--r--sys/powerpc/include/md_var.h9
-rw-r--r--sys/powerpc/include/openpicvar.h33
-rw-r--r--sys/powerpc/powermac/hrowpic.c436
-rw-r--r--sys/powerpc/powermac/hrowpicvar.h12
-rw-r--r--sys/powerpc/powermac/openpic_macio.c156
-rw-r--r--sys/powerpc/powerpc/autoconf.c9
-rw-r--r--sys/powerpc/powerpc/interrupt.c19
-rw-r--r--sys/powerpc/powerpc/intr_machdep.c187
-rw-r--r--sys/powerpc/powerpc/nexus.c95
-rw-r--r--sys/powerpc/powerpc/openpic.c316
-rw-r--r--sys/powerpc/powerpc/pic_if.m36
-rw-r--r--sys/powerpc/psim/openpic_iobus.c142
15 files changed, 495 insertions, 1098 deletions
diff --git a/sys/powerpc/aim/interrupt.c b/sys/powerpc/aim/interrupt.c
index bb27675..ff77fc8 100644
--- a/sys/powerpc/aim/interrupt.c
+++ b/sys/powerpc/aim/interrupt.c
@@ -49,30 +49,19 @@
#include <sys/vmmeter.h>
#include <machine/cpu.h>
+#include <machine/clock.h>
#include <machine/db_machdep.h>
#include <machine/fpu.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/spr.h>
#include <machine/sr.h>
-void powerpc_interrupt(struct trapframe *);
-
-/*
- * External interrupt install routines
- */
-static void (*powerpc_extintr_handler)(void);
-
-void
-ext_intr_install(void (*new_extint)(void))
-{
- powerpc_extintr_handler = new_extint;
-}
-
-extern void decr_intr(struct trapframe *);
+#include "pic_if.h"
/*
* A very short dispatch, to try and maximise assembler code use
@@ -90,7 +79,7 @@ powerpc_interrupt(struct trapframe *framep)
switch (framep->exc) {
case EXC_EXI:
atomic_add_int(&td->td_intr_nesting_level, 1);
- (*powerpc_extintr_handler)();
+ PIC_DISPATCH(pic, framep);
atomic_subtract_int(&td->td_intr_nesting_level, 1);
break;
diff --git a/sys/powerpc/aim/nexus.c b/sys/powerpc/aim/nexus.c
index c2b754a..e31ef61 100644
--- a/sys/powerpc/aim/nexus.c
+++ b/sys/powerpc/aim/nexus.c
@@ -97,7 +97,7 @@ struct nexus_devinfo {
};
struct nexus_softc {
- device_t sc_pic;
+ struct rman sc_rman;
};
/*
@@ -182,12 +182,24 @@ nexus_probe(device_t dev)
phandle_t root;
phandle_t child;
struct nexus_softc *sc;
+ u_long start, end;
if ((root = OF_peer(0)) == -1)
panic("nexus_probe: OF_peer failed.");
sc = device_get_softc(dev);
+ start = 0;
+ end = INTR_VECTORS - 1;
+
+ sc->sc_rman.rm_start = start;
+ sc->sc_rman.rm_end = end;
+ sc->sc_rman.rm_type = RMAN_ARRAY;
+ sc->sc_rman.rm_descr = "Interrupt request lines";
+ if (rman_init(&sc->sc_rman) ||
+ rman_manage_region(&sc->sc_rman, start, end))
+ panic("nexus_probe IRQ rman");
+
/*
* Allow devices to identify
*/
@@ -302,31 +314,40 @@ nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
static int
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
- driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep)
+ driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep)
{
- struct nexus_softc *sc;
+ driver_t *driver;
+ int error;
- sc = device_get_softc(dev);
+ /* somebody tried to setup an irq that failed to allocate! */
+ if (res == NULL)
+ panic("nexus_setup_intr: NULL irq resource!");
+
+ *cookiep = 0;
+ if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
+ flags |= INTR_EXCL;
+
+ driver = device_get_driver(child);
+
+ /*
+ * We depend here on rman_activate_resource() being idempotent.
+ */
+ error = rman_activate_resource(res);
+ if (error)
+ return (error);
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_setup_intr: no pic attached\n");
+ error = powerpc_setup_intr(device_get_nameunit(child),
+ rman_get_start(res), filter, ihand, arg, flags, cookiep);
- return (PIC_SETUP_INTR(sc->sc_pic, child, res, flags, filter, intr,
- arg, cookiep));
+ return (error);
}
static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
- void *ih)
+ void *cookie)
{
- struct nexus_softc *sc;
- sc = device_get_softc(dev);
-
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_teardown_intr: no pic attached\n");
-
- return (PIC_TEARDOWN_INTR(sc->sc_pic, child, res, ih));
+ return (powerpc_teardown_intr(cookie));
}
/*
@@ -337,10 +358,8 @@ static struct resource *
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
- struct nexus_softc *sc;
- struct resource *rv;
-
- sc = device_get_softc(bus);
+ struct nexus_softc *sc;
+ struct resource *rv;
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@@ -348,10 +367,21 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (NULL);
}
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_alloc_resource: no pic attached\n");
+ if (count == 0 || start + count - 1 != end) {
+ device_printf(bus, "invalid IRQ allocation from %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
- rv = PIC_ALLOCATE_INTR(sc->sc_pic, child, rid, start, flags);
+ sc = device_get_softc(bus);
+
+ rv = rman_reserve_resource(&sc->sc_rman, start, end, count,
+ flags, child);
+ if (rv == NULL) {
+ device_printf(bus, "IRQ allocation failed for %s\n",
+ device_get_nameunit(child));
+ } else
+ rman_set_rid(rv, *rid);
return (rv);
}
@@ -378,9 +408,6 @@ static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)
{
- struct nexus_softc *sc;
-
- sc = device_get_softc(bus);
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@@ -388,10 +415,7 @@ nexus_release_resource(device_t bus, device_t child, int type, int rid,
return (EINVAL);
}
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_release_resource: no pic attached\n");
-
- return (PIC_RELEASE_INTR(sc->sc_pic, child, rid, res));
+ return (rman_release_resource(res));
}
static device_t
@@ -418,17 +442,6 @@ nexus_device_from_node(device_t parent, phandle_t node)
return (cdev);
}
-int
-nexus_install_intcntlr(device_t dev)
-{
- struct nexus_softc *sc;
-
- sc = device_get_softc(device_get_parent(dev));
- sc->sc_pic = dev;
-
- return (0);
-}
-
static const char *
nexus_ofw_get_name(device_t bus, device_t dev)
{
diff --git a/sys/powerpc/include/intr_machdep.h b/sys/powerpc/include/intr_machdep.h
index 9914965..25f47f0 100644
--- a/sys/powerpc/include/intr_machdep.h
+++ b/sys/powerpc/include/intr_machdep.h
@@ -28,29 +28,18 @@
#ifndef _MACHINE_INTR_MACHDEP_H_
#define _MACHINE_INTR_MACHDEP_H_
-typedef void ih_func_t(void *);
+#define INTR_VECTORS 256
-struct intr_event;
+extern device_t pic;
-struct ppc_intr_handler {
- ih_func_t *ih_func;
- void *ih_arg;
- struct intr_event *ih_event;
- u_int ih_irq;
- u_int ih_flags;
- u_int ih_index;
- u_long *ih_count;
- u_long *ih_straycount;
-};
+struct trapframe;
-/* XXX temporary. */
-void ext_intr_install(void (*new_extint)(void));
+void powerpc_register_pic(device_t);
-void intr_init(void (*)(void), int, void (*)(uintptr_t), void (*)(uintptr_t));
-void intr_setup(u_int, ih_func_t *, void *, u_int);
-int inthand_add(const char *, u_int, driver_filter_t *filter,
- void (*)(void *), void *, int, void **);
-int inthand_remove(u_int, void *);
-void intr_handle(u_int);
+void powerpc_dispatch_intr(u_int, struct trapframe *);
+int powerpc_enable_intr(void);
+int powerpc_setup_intr(const char *, u_int, driver_filter_t,
+ driver_intr_t, void *, enum intr_type, void **);
+int powerpc_teardown_intr(void *);
#endif /* _MACHINE_INTR_MACHDEP_H_ */
diff --git a/sys/powerpc/include/md_var.h b/sys/powerpc/include/md_var.h
index 7248e4b..73249ad 100644
--- a/sys/powerpc/include/md_var.h
+++ b/sys/powerpc/include/md_var.h
@@ -44,12 +44,6 @@ extern vm_offset_t kstack0_phys;
extern u_long ns_per_tick;
-struct fpreg;
-struct proc;
-struct reg;
-struct cam_sim;
-struct pcicfg;
-
#if defined(_KERNEL) || defined(_STANDALONE)
#define CACHELINESIZE 32
#endif
@@ -64,4 +58,7 @@ void decr_init(void);
void cpu_setup(u_int);
+struct trapframe;
+void powerpc_interrupt(struct trapframe *);
+
#endif /* !_MACHINE_MD_VAR_H_ */
diff --git a/sys/powerpc/include/openpicvar.h b/sys/powerpc/include/openpicvar.h
index 5095036..081cf7a 100644
--- a/sys/powerpc/include/openpicvar.h
+++ b/sys/powerpc/include/openpicvar.h
@@ -33,36 +33,31 @@
#define OPENPIC_IRQMAX 256 /* h/w allows more */
struct openpic_softc {
+ device_t sc_dev;
+ struct resource *sc_memr;
+ bus_space_tag_t sc_bt;
+ bus_space_handle_t sc_bh;
char *sc_version;
+ int sc_rid;
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 */
+ int sc_psim;
};
+extern devclass_t openpic_devclass;
+
/*
* Bus-independent attach i/f
*/
-int openpic_early_attach(device_t);
-int openpic_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_filter_t,
- 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);
+void openpic_dispatch(device_t, struct trapframe *);
+void openpic_enable(device_t, u_int, u_int);
+void openpic_eoi(device_t, u_int);
+void openpic_mask(device_t, u_int);
+void openpic_unmask(device_t, u_int);
#endif /* _POWERPC_OPENPICVAR_H_ */
diff --git a/sys/powerpc/powermac/hrowpic.c b/sys/powerpc/powermac/hrowpic.c
index d6e5e25..cf8a462 100644
--- a/sys/powerpc/powermac/hrowpic.c
+++ b/sys/powerpc/powermac/hrowpic.c
@@ -28,15 +28,9 @@
*/
/*
- * A driver for the PIC found in the Heathrow/Paddington MacIO chips.
+ * A driver for the PIC found in the Heathrow/Paddington MacIO chips.
* This was superseded by an OpenPIC in the Keylargo and beyond
* MacIO versions.
- *
- * The device is initially located in the Open Firmware device tree
- * in the earliest stage of the nexus probe. However, no device registers
- * are touched until the actual h/w is probed later on during the
- * MacIO probe. At that point, any interrupt sources that were allocated
- * prior to this are activated.
*/
#include <sys/param.h>
@@ -45,6 +39,7 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/rman.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/openfirm.h>
@@ -60,67 +55,35 @@
#include <vm/vm.h>
#include <vm/pmap.h>
-#include <sys/rman.h>
-
#include <powerpc/powermac/hrowpicvar.h>
#include "pic_if.h"
/*
- * Device interface.
- */
-static void hrowpic_identify(driver_t *, device_t);
-static int hrowpic_probe(device_t);
-static int hrowpic_attach(device_t);
-
-/*
- * PIC interface.
- */
-static struct resource *hrowpic_allocate_intr(device_t, device_t, int *,
- u_long, u_int);
-static int hrowpic_setup_intr(device_t, device_t,
- struct resource *, int, driver_filter_t,
- driver_intr_t, void *, void **);
-static int hrowpic_teardown_intr(device_t, device_t,
- struct resource *, void *);
-static int hrowpic_release_intr(device_t dev, device_t, int,
- struct resource *res);
-
-/*
* MacIO interface
*/
-static int hrowpic_macio_probe(device_t);
-static int hrowpic_macio_attach(device_t);
-
-/*
- * Local routines
- */
-static void hrowpic_intr(void);
-static void hrowpic_ext_enable_irq(uintptr_t);
-static void hrowpic_ext_disable_irq(uintptr_t);
-static void hrowpic_toggle_irq(struct hrowpic_softc *sc, int, int);
+static int hrowpic_probe(device_t);
+static int hrowpic_attach(device_t);
-/*
- * Interrupt controller softc. There should only be one.
- */
-static struct hrowpic_softc *hpicsoftc;
+static void hrowpic_dispatch(device_t, struct trapframe *);
+static void hrowpic_enable(device_t, u_int, u_int);
+static void hrowpic_eoi(device_t, u_int);
+static void hrowpic_mask(device_t, u_int);
+static void hrowpic_unmask(device_t, u_int);
-/*
- * Driver methods.
- */
static device_method_t hrowpic_methods[] = {
/* Device interface */
- DEVMETHOD(device_identify, hrowpic_identify),
DEVMETHOD(device_probe, hrowpic_probe),
DEVMETHOD(device_attach, hrowpic_attach),
/* PIC interface */
- DEVMETHOD(pic_allocate_intr, hrowpic_allocate_intr),
- DEVMETHOD(pic_setup_intr, hrowpic_setup_intr),
- DEVMETHOD(pic_teardown_intr, hrowpic_teardown_intr),
- DEVMETHOD(pic_release_intr, hrowpic_release_intr),
+ DEVMETHOD(pic_dispatch, hrowpic_dispatch),
+ DEVMETHOD(pic_enable, hrowpic_enable),
+ DEVMETHOD(pic_eoi, hrowpic_eoi),
+ DEVMETHOD(pic_mask, hrowpic_mask),
+ DEVMETHOD(pic_unmask, hrowpic_unmask),
- { 0, 0 }
+ { 0, 0 },
};
static driver_t hrowpic_driver = {
@@ -131,39 +94,48 @@ static driver_t hrowpic_driver = {
static devclass_t hrowpic_devclass;
-DRIVER_MODULE(hrowpic, nexus, hrowpic_driver, hrowpic_devclass, 0, 0);
+DRIVER_MODULE(hrowpic, macio, hrowpic_driver, hrowpic_devclass, 0, 0);
-static void
-hrowpic_identify(driver_t *driver, device_t parent)
+static uint32_t
+hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank)
{
- phandle_t chosen, pic;
- char type[40];
+ if (bank == HPIC_PRIMARY)
+ reg += HPIC_1ST_OFFSET;
- chosen = OF_finddevice("/chosen");
- if (chosen == -1)
- return;
+ return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
+}
- if (OF_getprop(chosen, "interrupt-controller", &pic, 4) != 4)
- return;
+static void
+hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank,
+ uint32_t val)
+{
- OF_getprop(pic, "compatible", type, sizeof(type));
- if (strcmp(type, "heathrow"))
- return;
+ if (bank == HPIC_PRIMARY)
+ reg += HPIC_1ST_OFFSET;
+
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
- BUS_ADD_CHILD(parent, 0, "hrowpic", 0);
+ /* XXX Issue a read to force the write to complete. */
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, reg);
}
static int
hrowpic_probe(device_t dev)
{
- char *name;
-
- name = nexus_get_name(dev);
+ const char *type = ofw_bus_get_type(dev);
- if (strcmp(name, "hrowpic"))
+ /*
+ * OpenPIC cells have a type of "open-pic", so this
+ * is sufficient to identify a Heathrow cell
+ */
+ if (strcmp(type, "interrupt-controller") != 0)
return (ENXIO);
-
- device_set_desc(dev, "Heathrow interrupt controller");
+
+ /*
+ * The description was already printed out in the nexus
+ * probe, so don't do it again here
+ */
+ device_set_desc(dev, "Heathrow MacIO interrupt controller");
return (0);
}
@@ -173,159 +145,36 @@ hrowpic_attach(device_t dev)
struct hrowpic_softc *sc;
sc = device_get_softc(dev);
+ sc->sc_dev = dev;
- sc->sc_rman.rm_type = RMAN_ARRAY;
- sc->sc_rman.rm_descr = device_get_nameunit(dev);
+ sc->sc_rrid = 0;
+ sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rrid,
+ RF_ACTIVE);
- if (rman_init(&sc->sc_rman) != 0 ||
- rman_manage_region(&sc->sc_rman, 0, HROWPIC_IRQMAX-1) != 0) {
- device_printf(dev, "could not set up resource management");
+ if (sc->sc_rres == NULL) {
+ device_printf(dev, "Could not alloc mem resource!\n");
return (ENXIO);
- }
-
- nexus_install_intcntlr(dev);
- intr_init(hrowpic_intr, HROWPIC_IRQMAX, hrowpic_ext_enable_irq,
- hrowpic_ext_disable_irq);
-
- KASSERT(hpicsoftc == NULL, ("hrowpic: h/w already probed"));
- hpicsoftc = sc;
-
- return (0);
-}
-
-/*
- * PIC interface
- */
-static struct resource *
-hrowpic_allocate_intr(device_t picdev, device_t child, int *rid, u_long intr,
- u_int flags)
-{
- struct hrowpic_softc *sc;
- struct resource *rv;
- int needactivate;
-
- sc = device_get_softc(picdev);
- needactivate = flags & RF_ACTIVE;
- flags &= ~RF_ACTIVE;
-
- rv = rman_reserve_resource(&sc->sc_rman, intr, intr, 1, flags, child);
- if (rv == NULL) {
- device_printf(picdev, "interrupt reservation failed for %s\n",
- device_get_nameunit(child));
- return (NULL);
}
- rman_set_rid(rv, *rid);
-
- return (rv);
-}
-static int
-hrowpic_setup_intr(device_t picdev, device_t child, struct resource *res,
- int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
- void **cookiep)
-{
- struct hrowpic_softc *sc;
- u_long start;
- int error;
-
- sc = device_get_softc(picdev);
- start = rman_get_start(res);
-
- if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
- flags |= INTR_EXCL;
+ sc->sc_bt = rman_get_bustag(sc->sc_rres);
+ sc->sc_bh = rman_get_bushandle(sc->sc_rres);
/*
- * We depend here on rman_activate_resource() being idempotent.
- */
- error = rman_activate_resource(res);
- if (error)
- return (error);
-
- error = inthand_add(device_get_nameunit(child), start, filt, intr, arg,
- flags, cookiep);
-
- if (!error) {
- /*
- * Record irq request, and enable if h/w has been probed
- */
- sc->sc_irq[start] = 1;
- if (sc->sc_memr) {
- hrowpic_toggle_irq(sc, start, 1);
- }
- }
-
- return (error);
-}
-
-static int
-hrowpic_teardown_intr(device_t picdev, device_t child, struct resource *res,
- void *ih)
-{
- int error;
-
- error = rman_deactivate_resource(res);
- if (error)
- return (error);
-
- error = inthand_remove(rman_get_start(res), ih);
-
- return (error);
-}
-
-static int
-hrowpic_release_intr(device_t picdev, device_t child, int rid,
- struct resource *res)
-{
- int error;
-
- if (rman_get_flags(res) & RF_ACTIVE) {
- error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
- if (error)
- return (error);
- }
-
- return (rman_release_resource(res));
-}
-
-/*
- * Interrupt interface
- */
-static void
-hrowpic_write_reg(struct hrowpic_softc *sc, u_int reg, u_int bank,
- u_int32_t val)
-{
- if (bank == HPIC_PRIMARY)
- reg += HPIC_1ST_OFFSET;
-
- bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
-
- /*
- * XXX Issue a read to force the write to complete
- */
- bus_space_read_4(sc->sc_bt, sc->sc_bh, reg);
-}
-
-static u_int32_t
-hrowpic_read_reg(struct hrowpic_softc *sc, u_int reg, u_int bank)
-{
- if (bank == HPIC_PRIMARY)
- reg += HPIC_1ST_OFFSET;
-
- return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
-}
-
-static void
-hrowpic_clear_all(struct hrowpic_softc *sc)
-{
- /*
* Disable all interrupt sources and clear outstanding interrupts
*/
hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_PRIMARY, 0);
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY, 0xffffffff);
hrowpic_write_reg(sc, HPIC_ENABLE, HPIC_SECONDARY, 0);
hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY, 0xffffffff);
+
+ powerpc_register_pic(dev);
+ return (0);
}
+/*
+ * Local routines
+ */
+
static void
hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable)
{
@@ -349,143 +198,74 @@ hrowpic_toggle_irq(struct hrowpic_softc *sc, int irq, int enable)
hrowpic_write_reg(sc, HPIC_ENABLE, roffset, sc->sc_softreg[roffset]);
}
+/*
+ * PIC I/F methods.
+ */
+
static void
-hrowpic_intr(void)
+hrowpic_dispatch(device_t dev, struct trapframe *tf)
{
- int irq_lo, irq_hi;
- int i;
struct hrowpic_softc *sc;
+ uint64_t mask;
+ uint32_t reg;
+ u_int irq;
- sc = hpicsoftc;
-
- /*
- * Loop through both interrupt sources until they are empty.
- * XXX simplistic code, far from optimal.
- */
- do {
- irq_lo = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY);
- if (irq_lo) {
- hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_PRIMARY,
- irq_lo);
- for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) {
- if (irq_lo & (1 << i)) {
- /*
- * Disable IRQ and call handler
- */
- hrowpic_toggle_irq(sc, i, 0);
- intr_handle(i);
- }
- }
-
- }
-
- irq_hi = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY);
- if (irq_hi) {
- hrowpic_write_reg(sc, HPIC_CLEAR, HPIC_SECONDARY,
- irq_hi);
- for (i = 0; i < HROWPIC_IRQ_REGNUM; i++) {
- if (irq_hi & (1 << i)) {
- /*
- * Disable IRQ and call handler
- */
- hrowpic_toggle_irq(sc,
- i + HROWPIC_IRQ_REGNUM, 0);
- intr_handle(i + HROWPIC_IRQ_REGNUM);
- }
- }
+ sc = device_get_softc(dev);
+ while (1) {
+ mask = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_SECONDARY);
+ reg = hrowpic_read_reg(sc, HPIC_STATUS, HPIC_PRIMARY);
+ mask = (mask << 32) | reg;
+ if (mask == 0)
+ break;
+
+ irq = 0;
+ while (irq < HROWPIC_IRQMAX) {
+ if (mask & 1)
+ powerpc_dispatch_intr(sc->sc_vector[irq], tf);
+ mask >>= 1;
+ irq++;
}
- } while (irq_lo && irq_hi);
+ }
}
static void
-hrowpic_ext_enable_irq(uintptr_t irq)
+hrowpic_enable(device_t dev, u_int irq, u_int vector)
{
- hrowpic_toggle_irq(hpicsoftc, irq, 1);
+ struct hrowpic_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_vector[irq] = vector;
+ hrowpic_toggle_irq(sc, irq, 1);
}
static void
-hrowpic_ext_disable_irq(uintptr_t irq)
+hrowpic_eoi(device_t dev __unused, u_int irq __unused)
{
- hrowpic_toggle_irq(hpicsoftc, irq, 0);
-}
-
-
-/*
- * MacIO interface
- */
-
-static device_method_t hrowpic_macio_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, hrowpic_macio_probe),
- DEVMETHOD(device_attach, hrowpic_macio_attach),
-
- { 0, 0 },
-};
-
-static driver_t hrowpic_macio_driver = {
- "hrowpicmacio",
- hrowpic_macio_methods,
- 0
-};
-
-static devclass_t hrowpic_macio_devclass;
+ struct hrowpic_softc *sc;
+ int bank;
-DRIVER_MODULE(hrowpicmacio, macio, hrowpic_macio_driver,
- hrowpic_macio_devclass, 0, 0);
+ sc = device_get_softc(dev);
+ bank = (irq >= 32) ? HPIC_SECONDARY : HPIC_PRIMARY ;
+ hrowpic_write_reg(sc, HPIC_CLEAR, bank, 1U << (irq & 0x1f));
+}
-static int
-hrowpic_macio_probe(device_t dev)
+static void
+hrowpic_mask(device_t dev, u_int irq)
{
- const char *type = ofw_bus_get_type(dev);
-
- /*
- * OpenPIC cells have a type of "open-pic", so this
- * is sufficient to identify a Heathrow cell
- */
- if (strcmp(type, "interrupt-controller") != 0)
- return (ENXIO);
+ struct hrowpic_softc *sc;
+ int bank;
- /*
- * The description was already printed out in the nexus
- * probe, so don't do it again here
- */
- device_set_desc(dev, "Heathrow MacIO interrupt cell");
- device_quiet(dev);
- return (0);
+ sc = device_get_softc(dev);
+ hrowpic_toggle_irq(sc, irq, 0);
+ bank = (irq >= 32) ? HPIC_SECONDARY : HPIC_PRIMARY ;
+ hrowpic_write_reg(sc, HPIC_CLEAR, bank, 1U << (irq & 0x1f));
}
-static int
-hrowpic_macio_attach(device_t dev)
+static void
+hrowpic_unmask(device_t dev, u_int irq)
{
- struct hrowpic_softc *sc = hpicsoftc;
- int rid;
- int i;
-
- KASSERT(sc != NULL, ("pic not nexus-probed\n"));
- sc->sc_maciodev = dev;
-
- rid = 0;
- sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
- RF_ACTIVE);
-
- if (sc->sc_memr == NULL) {
- device_printf(dev, "Could not alloc mem resource!\n");
- return (ENXIO);
- }
-
- sc->sc_bt = rman_get_bustag(sc->sc_memr);
- sc->sc_bh = rman_get_bushandle(sc->sc_memr);
-
- hrowpic_clear_all(sc);
-
- /*
- * Enable all IRQs that were requested before the h/w
- * was probed
- */
- for (i = 0; i < HROWPIC_IRQMAX; i++)
- if (sc->sc_irq[i]) {
- hrowpic_toggle_irq(sc, i, 1);
- }
+ struct hrowpic_softc *sc;
- return (0);
+ sc = device_get_softc(dev);
+ hrowpic_toggle_irq(sc, irq, 1);
}
diff --git a/sys/powerpc/powermac/hrowpicvar.h b/sys/powerpc/powermac/hrowpicvar.h
index 6a536cc..ac643f5 100644
--- a/sys/powerpc/powermac/hrowpicvar.h
+++ b/sys/powerpc/powermac/hrowpicvar.h
@@ -62,16 +62,14 @@
#define HPIC_1ST_OFFSET 0x10 /* offset to primary reg bank */
-
struct hrowpic_softc {
- struct rman sc_rman; /* resource mgr for IRQs */
- u_int32_t sc_irq[HROWPIC_IRQMAX]; /* allocated IRQ flags */
- u_int32_t sc_softreg[2]; /* ENABLE reg copy */
- device_t sc_maciodev; /* macio device */
- struct resource *sc_memr; /* macio bus resource */
+ device_t sc_dev; /* macio device */
+ struct resource *sc_rres; /* macio bus resource */
bus_space_tag_t sc_bt; /* macio bus tag/handle */
bus_space_handle_t sc_bh;
+ int sc_rrid;
+ uint32_t sc_softreg[2]; /* ENABLE reg copy */
+ u_int sc_vector[HROWPIC_IRQMAX];
};
-
#endif /* _POWERPC_POWERMAC_HROWPICVAR_H_ */
diff --git a/sys/powerpc/powermac/openpic_macio.c b/sys/powerpc/powermac/openpic_macio.c
index c04c373..822804e 100644
--- a/sys/powerpc/powermac/openpic_macio.c
+++ b/sys/powerpc/powermac/openpic_macio.c
@@ -26,15 +26,6 @@
*
*/
-/*
- * 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$");
@@ -65,123 +56,33 @@ __FBSDID("$FreeBSD$");
#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 pic;
- char type[40];
-
- pic = OF_finddevice("mpic");
- if (pic == -1)
- 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),
+ DEVMETHOD(device_attach, openpic_attach),
+
+ /* PIC interface */
+ DEVMETHOD(pic_dispatch, openpic_dispatch),
+ DEVMETHOD(pic_enable, openpic_enable),
+ DEVMETHOD(pic_eoi, openpic_eoi),
+ DEVMETHOD(pic_mask, openpic_mask),
+ DEVMETHOD(pic_unmask, openpic_unmask),
{ 0, 0 },
};
static driver_t openpic_macio_driver = {
- "openpicmacio",
+ "openpic",
openpic_macio_methods,
- 0
+ sizeof(struct openpic_softc),
};
-static devclass_t openpic_macio_devclass;
-
-DRIVER_MODULE(openpicmacio, macio, openpic_macio_driver,
- openpic_macio_devclass, 0, 0);
+DRIVER_MODULE(openpic, macio, openpic_macio_driver, openpic_devclass, 0, 0);
static int
openpic_macio_probe(device_t dev)
@@ -191,39 +92,6 @@ openpic_macio_probe(device_t 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);
+ device_set_desc(dev, OPENPIC_DEVSTR);
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_any(dev, SYS_RES_MEMORY, &rid,
- 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/autoconf.c b/sys/powerpc/powerpc/autoconf.c
index aa21ddc..6449323 100644
--- a/sys/powerpc/powerpc/autoconf.c
+++ b/sys/powerpc/powerpc/autoconf.c
@@ -33,6 +33,8 @@ __FBSDID("$FreeBSD$");
#include <sys/cons.h>
#include <sys/kernel.h>
+#include <machine/intr_machdep.h>
+
static device_t nexusdev;
static void configure_first(void *);
@@ -65,9 +67,14 @@ configure(void *dummy)
static void
configure_final(void *dummy)
{
+
/*
- * Enable device interrupts
+ * Now that we're guaranteed to have a PIC driver (or we'll never
+ * have one), program it with all the previously setup interrupts.
*/
+ powerpc_enable_intr();
+
+ /* Enable external interrupts. */
mtmsr(mfmsr() | PSL_EE | PSL_RI);
cninit_finish();
diff --git a/sys/powerpc/powerpc/interrupt.c b/sys/powerpc/powerpc/interrupt.c
index bb27675..ff77fc8 100644
--- a/sys/powerpc/powerpc/interrupt.c
+++ b/sys/powerpc/powerpc/interrupt.c
@@ -49,30 +49,19 @@
#include <sys/vmmeter.h>
#include <machine/cpu.h>
+#include <machine/clock.h>
#include <machine/db_machdep.h>
#include <machine/fpu.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/psl.h>
#include <machine/trap.h>
#include <machine/spr.h>
#include <machine/sr.h>
-void powerpc_interrupt(struct trapframe *);
-
-/*
- * External interrupt install routines
- */
-static void (*powerpc_extintr_handler)(void);
-
-void
-ext_intr_install(void (*new_extint)(void))
-{
- powerpc_extintr_handler = new_extint;
-}
-
-extern void decr_intr(struct trapframe *);
+#include "pic_if.h"
/*
* A very short dispatch, to try and maximise assembler code use
@@ -90,7 +79,7 @@ powerpc_interrupt(struct trapframe *framep)
switch (framep->exc) {
case EXC_EXI:
atomic_add_int(&td->td_intr_nesting_level, 1);
- (*powerpc_extintr_handler)();
+ PIC_DISPATCH(pic, framep);
atomic_subtract_int(&td->td_intr_nesting_level, 1);
break;
diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c
index 1b0ff94..7daaf23 100644
--- a/sys/powerpc/powerpc/intr_machdep.c
+++ b/sys/powerpc/powerpc/intr_machdep.c
@@ -71,30 +71,32 @@
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
+#include <sys/syslog.h>
#include <sys/vmmeter.h>
#include <sys/proc.h>
#include <machine/frame.h>
#include <machine/intr_machdep.h>
+#include <machine/md_var.h>
#include <machine/trap.h>
+#include "pic_if.h"
+
#define MAX_STRAY_LOG 5
MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data");
-struct ppc_intr {
+struct powerpc_intr {
struct intr_event *event;
long *cntp;
- int cntidx;
+ u_int irq;
};
-static struct mtx ppc_intrs_lock;
-static struct ppc_intr **ppc_intrs;
-static u_int ppc_nintrs;
-
-static int intrcnt_index;
+static struct powerpc_intr *powerpc_intrs[INTR_VECTORS];
+static u_int nvectors; /* Allocated vectors */
+static u_int stray_count;
-static void (*irq_enable)(uintptr_t);
+device_t pic;
static void
intrcnt_setname(const char *name, int index)
@@ -103,111 +105,154 @@ intrcnt_setname(const char *name, int index)
MAXCOMLEN, name);
}
-void
-intr_init(void (*handler)(void), int nirq, void (*irq_e)(uintptr_t),
- void (*irq_d)(uintptr_t))
+#ifdef INTR_FILTER
+static void
+powerpc_intr_eoi(void *arg)
+{
+ u_int irq = (uintptr_t)arg;
+
+ PIC_EOI(pic, irq);
+}
+
+static void
+powerpc_intr_mask(void *arg)
+{
+ u_int irq = (uintptr_t)arg;
+
+ PIC_MASK(pic, irq);
+}
+#endif
+
+static void
+powerpc_intr_unmask(void *arg)
{
- uint32_t msr;
+ u_int irq = (uintptr_t)arg;
+
+ PIC_UNMASK(pic, irq);
+}
- if (ppc_intrs != NULL)
- panic("intr_init: interrupts initialized twice\n");
+void
+powerpc_register_pic(device_t dev)
+{
- ppc_nintrs = nirq;
- ppc_intrs = malloc(nirq * sizeof(struct ppc_intr *), M_INTR,
- M_NOWAIT|M_ZERO);
- if (ppc_intrs == NULL)
- panic("intr_init: unable to allocate interrupt handler array");
+ pic = dev;
+}
- mtx_init(&ppc_intrs_lock, "intr table", NULL, MTX_SPIN);
+int
+powerpc_enable_intr(void)
+{
+ struct powerpc_intr *i;
+ int vector;
- irq_enable = irq_e;
+ for (vector = 0; vector < nvectors; vector++) {
+ i = powerpc_intrs[vector];
+ if (i == NULL)
+ continue;
- intrcnt_setname("???", 0);
- intrcnt_index = 1;
+ PIC_ENABLE(pic, i->irq, vector);
+ }
- msr = mfmsr();
- mtmsr(msr & ~PSL_EE);
- ext_intr_install(handler);
- mtmsr(msr);
+ return (0);
}
int
-inthand_add(const char *name, u_int irq, driver_filter_t *filter,
- void (*handler)(void *), void *arg, int flags, void **cookiep)
+powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter,
+ driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep)
{
- struct ppc_intr *i, *orphan;
- u_int idx;
+ struct powerpc_intr *i;
+ u_int vector;
int error;
- /*
- * Work around a race where more than one CPU may be registering
- * handlers on the same IRQ at the same time.
- */
- mtx_lock_spin(&ppc_intrs_lock);
- i = ppc_intrs[irq];
- mtx_unlock_spin(&ppc_intrs_lock);
+ /* XXX lock */
+
+ i = NULL;
+ for (vector = 0; vector < nvectors; vector++) {
+ i = powerpc_intrs[vector];
+ if (i == NULL)
+ continue;
+ if (i->irq == irq)
+ break;
+ i = NULL;
+ }
if (i == NULL) {
+ if (nvectors >= INTR_VECTORS) {
+ /* XXX unlock */
+ return (ENOENT);
+ }
+
i = malloc(sizeof(*i), M_INTR, M_NOWAIT);
- if (i == NULL)
+ if (i == NULL) {
+ /* XXX unlock */
return (ENOMEM);
+ }
error = intr_event_create(&i->event, (void *)irq, 0,
- (void (*)(void *))irq_enable, "irq%d:", irq);
+ powerpc_intr_unmask,
+#ifdef INTR_FILTER
+ powerpc_intr_eoi, powerpc_intr_mask,
+#endif
+ "irq%u:", irq);
if (error) {
+ /* XXX unlock */
free(i, M_INTR);
return (error);
}
- mtx_lock_spin(&ppc_intrs_lock);
- if (ppc_intrs[irq] != NULL) {
- orphan = i;
- i = ppc_intrs[irq];
- mtx_unlock_spin(&ppc_intrs_lock);
-
- intr_event_destroy(orphan->event);
- free(orphan, M_INTR);
- } else {
- ppc_intrs[irq] = i;
- idx = intrcnt_index++;
- mtx_unlock_spin(&ppc_intrs_lock);
-
- i->cntidx = idx;
- i->cntp = &intrcnt[idx];
- intrcnt_setname(i->event->ie_fullname, idx);
- }
+ vector = nvectors++;
+ powerpc_intrs[vector] = i;
+
+ i->irq = irq;
+
+ /* XXX unlock */
+
+ i->cntp = &intrcnt[vector];
+ intrcnt_setname(i->event->ie_fullname, vector);
+
+ if (!cold)
+ PIC_ENABLE(pic, i->irq, vector);
+ } else {
+ /* XXX unlock */
}
error = intr_event_add_handler(i->event, name, filter, handler, arg,
intr_priority(flags), flags, cookiep);
if (!error)
- intrcnt_setname(i->event->ie_fullname, i->cntidx);
+ intrcnt_setname(i->event->ie_fullname, vector);
return (error);
}
int
-inthand_remove(u_int irq, void *cookie)
+powerpc_teardown_intr(void *cookie)
{
return (intr_event_remove_handler(cookie));
}
void
-intr_handle(u_int irq)
+powerpc_dispatch_intr(u_int vector, struct trapframe *tf)
{
- struct ppc_intr *i;
+ struct powerpc_intr *i;
struct intr_event *ie;
+#ifndef INTR_FILTER
struct intr_handler *ih;
int error, sched, ret;
+#endif
- i = ppc_intrs[irq];
+ i = powerpc_intrs[vector];
if (i == NULL)
goto stray;
- atomic_add_long(i->cntp, 1);
+ (*i->cntp)++;
ie = i->event;
KASSERT(ie != NULL, ("%s: interrupt without an event", __func__));
+#ifdef INTR_FILTER
+ if (intr_event_handle(ie, tf) != 0) {
+ PIC_MASK(pic, i->irq);
+ log(LOG_ERR, "stray irq%u\n", i->irq);
+ }
+#else
if (TAILQ_EMPTY(&ie->ie_handlers))
goto stray;
@@ -238,20 +283,24 @@ intr_handle(u_int irq)
critical_exit();
if (sched) {
+ PIC_MASK(pic, i->irq);
error = intr_event_schedule_thread(ie);
KASSERT(error == 0, ("%s: impossible stray interrupt",
__func__));
} else
- irq_enable(irq);
+ PIC_EOI(pic, i->irq);
+#endif
return;
stray:
- atomic_add_long(&intrcnt[0], 1);
- if (intrcnt[0] <= MAX_STRAY_LOG) {
- printf("stray irq %d\n", irq);
- if (intrcnt[0] >= MAX_STRAY_LOG) {
+ stray_count++;
+ if (stray_count <= MAX_STRAY_LOG) {
+ printf("stray irq %d\n", i->irq);
+ if (stray_count >= MAX_STRAY_LOG) {
printf("got %d stray interrupts, not logging anymore\n",
- MAX_STRAY_LOG);
+ MAX_STRAY_LOG);
}
}
+ if (i != NULL)
+ PIC_MASK(pic, i->irq);
}
diff --git a/sys/powerpc/powerpc/nexus.c b/sys/powerpc/powerpc/nexus.c
index c2b754a..e31ef61 100644
--- a/sys/powerpc/powerpc/nexus.c
+++ b/sys/powerpc/powerpc/nexus.c
@@ -97,7 +97,7 @@ struct nexus_devinfo {
};
struct nexus_softc {
- device_t sc_pic;
+ struct rman sc_rman;
};
/*
@@ -182,12 +182,24 @@ nexus_probe(device_t dev)
phandle_t root;
phandle_t child;
struct nexus_softc *sc;
+ u_long start, end;
if ((root = OF_peer(0)) == -1)
panic("nexus_probe: OF_peer failed.");
sc = device_get_softc(dev);
+ start = 0;
+ end = INTR_VECTORS - 1;
+
+ sc->sc_rman.rm_start = start;
+ sc->sc_rman.rm_end = end;
+ sc->sc_rman.rm_type = RMAN_ARRAY;
+ sc->sc_rman.rm_descr = "Interrupt request lines";
+ if (rman_init(&sc->sc_rman) ||
+ rman_manage_region(&sc->sc_rman, start, end))
+ panic("nexus_probe IRQ rman");
+
/*
* Allow devices to identify
*/
@@ -302,31 +314,40 @@ nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
static int
nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
- driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep)
+ driver_filter_t *filter, driver_intr_t *ihand, void *arg, void **cookiep)
{
- struct nexus_softc *sc;
+ driver_t *driver;
+ int error;
- sc = device_get_softc(dev);
+ /* somebody tried to setup an irq that failed to allocate! */
+ if (res == NULL)
+ panic("nexus_setup_intr: NULL irq resource!");
+
+ *cookiep = 0;
+ if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
+ flags |= INTR_EXCL;
+
+ driver = device_get_driver(child);
+
+ /*
+ * We depend here on rman_activate_resource() being idempotent.
+ */
+ error = rman_activate_resource(res);
+ if (error)
+ return (error);
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_setup_intr: no pic attached\n");
+ error = powerpc_setup_intr(device_get_nameunit(child),
+ rman_get_start(res), filter, ihand, arg, flags, cookiep);
- return (PIC_SETUP_INTR(sc->sc_pic, child, res, flags, filter, intr,
- arg, cookiep));
+ return (error);
}
static int
nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
- void *ih)
+ void *cookie)
{
- struct nexus_softc *sc;
- sc = device_get_softc(dev);
-
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_teardown_intr: no pic attached\n");
-
- return (PIC_TEARDOWN_INTR(sc->sc_pic, child, res, ih));
+ return (powerpc_teardown_intr(cookie));
}
/*
@@ -337,10 +358,8 @@ static struct resource *
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
u_long start, u_long end, u_long count, u_int flags)
{
- struct nexus_softc *sc;
- struct resource *rv;
-
- sc = device_get_softc(bus);
+ struct nexus_softc *sc;
+ struct resource *rv;
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@@ -348,10 +367,21 @@ nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
return (NULL);
}
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_alloc_resource: no pic attached\n");
+ if (count == 0 || start + count - 1 != end) {
+ device_printf(bus, "invalid IRQ allocation from %s\n",
+ device_get_nameunit(child));
+ return (NULL);
+ }
- rv = PIC_ALLOCATE_INTR(sc->sc_pic, child, rid, start, flags);
+ sc = device_get_softc(bus);
+
+ rv = rman_reserve_resource(&sc->sc_rman, start, end, count,
+ flags, child);
+ if (rv == NULL) {
+ device_printf(bus, "IRQ allocation failed for %s\n",
+ device_get_nameunit(child));
+ } else
+ rman_set_rid(rv, *rid);
return (rv);
}
@@ -378,9 +408,6 @@ static int
nexus_release_resource(device_t bus, device_t child, int type, int rid,
struct resource *res)
{
- struct nexus_softc *sc;
-
- sc = device_get_softc(bus);
if (type != SYS_RES_IRQ) {
device_printf(bus, "unknown resource request from %s\n",
@@ -388,10 +415,7 @@ nexus_release_resource(device_t bus, device_t child, int type, int rid,
return (EINVAL);
}
- if (device_get_state(sc->sc_pic) != DS_ATTACHED)
- panic("nexus_release_resource: no pic attached\n");
-
- return (PIC_RELEASE_INTR(sc->sc_pic, child, rid, res));
+ return (rman_release_resource(res));
}
static device_t
@@ -418,17 +442,6 @@ nexus_device_from_node(device_t parent, phandle_t node)
return (cdev);
}
-int
-nexus_install_intcntlr(device_t dev)
-{
- struct nexus_softc *sc;
-
- sc = device_get_softc(device_get_parent(dev));
- sc->sc_pic = dev;
-
- return (0);
-}
-
static const char *
nexus_ofw_get_name(device_t bus, device_t dev)
{
diff --git a/sys/powerpc/powerpc/openpic.c b/sys/powerpc/powerpc/openpic.c
index 3afc5b9..c6a0863 100644
--- a/sys/powerpc/powerpc/openpic.c
+++ b/sys/powerpc/powerpc/openpic.c
@@ -30,6 +30,7 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/kernel.h>
+#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -41,57 +42,38 @@
#include <vm/vm.h>
#include <vm/pmap.h>
-#include <sys/rman.h>
-
#include <machine/openpicreg.h>
#include <machine/openpicvar.h>
#include "pic_if.h"
+devclass_t openpic_devclass;
+
/*
* Local routines
*/
-static u_int openpic_read(struct openpic_softc *, int);
-static void openpic_write(struct openpic_softc *, int, u_int);
-static int openpic_read_irq(struct openpic_softc *, int);
-static void openpic_eoi(struct openpic_softc *, int);
-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 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;
-/*
- * Called at nexus-probe time to allow interrupts to be enabled by
- * devices that are probed before the OpenPIC h/w is probed.
- */
-int
-openpic_early_attach(device_t dev)
+static __inline uint32_t
+openpic_read(struct openpic_softc *sc, u_int reg)
{
- struct openpic_softc *sc;
-
- sc = device_get_softc(dev);
- openpic_softc = sc;
-
- 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, OPENPIC_IRQMAX-1) != 0) {
- device_printf(dev, "could not set up resource management");
- return (ENXIO);
- }
+ return (bus_space_read_4(sc->sc_bt, sc->sc_bh, reg));
+}
- intr_init(openpic_intr, OPENPIC_IRQMAX, openpic_ext_enable_irq,
- openpic_ext_disable_irq);
+static __inline void
+openpic_write(struct openpic_softc *sc, u_int reg, uint32_t val)
+{
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
+}
- sc->sc_early_done = 1;
+static __inline void
+openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
+{
+ uint32_t x;
- return (0);
+ x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu));
+ x &= ~OPENPIC_CPU_PRIORITY_MASK;
+ x |= pri;
+ openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x);
}
int
@@ -102,10 +84,19 @@ openpic_attach(device_t dev)
u_int32_t x;
sc = device_get_softc(dev);
- sc->sc_hwprobed = 1;
+ sc->sc_dev = dev;
- if (!sc->sc_early_done)
- openpic_early_attach(dev);
+ sc->sc_rid = 0;
+ sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
+ RF_ACTIVE);
+
+ if (sc->sc_memr == NULL) {
+ device_printf(dev, "Could not alloc mem resource!\n");
+ return (ENXIO);
+ }
+
+ sc->sc_bt = rman_get_bustag(sc->sc_memr);
+ sc->sc_bh = rman_get_bushandle(sc->sc_memr);
x = openpic_read(sc, OPENPIC_FEATURE);
switch (x & OPENPIC_FEATURE_VERSION_MASK) {
@@ -155,7 +146,7 @@ openpic_attach(device_t dev)
openpic_write(sc, OPENPIC_IDEST(irq), 1 << 0);
for (irq = 0; irq < sc->sc_nirq; irq++) {
- x = irq;
+ x = irq; /* irq == vector. */
x |= OPENPIC_IMASK;
x |= OPENPIC_POLARITY_POSITIVE;
x |= OPENPIC_SENSE_LEVEL;
@@ -170,239 +161,78 @@ openpic_attach(device_t dev)
/* clear all pending interrupts */
for (irq = 0; irq < sc->sc_nirq; irq++) {
- openpic_read_irq(sc, 0);
- openpic_eoi(sc, 0);
+ (void)openpic_read(sc, OPENPIC_IACK(0));
+ openpic_write(sc, OPENPIC_EOI(0), 0);
}
- /* enable pre-h/w reserved irqs, disable all others */
- for (irq = 0; irq < sc->sc_nirq; irq++)
- if (sc->sc_irqrsv[irq])
- openpic_enable_irq(sc, irq, IST_LEVEL);
- else
- openpic_disable_irq(sc, irq);
+ powerpc_register_pic(dev);
return (0);
}
/*
- * PIC interface
+ * PIC I/F methods
*/
-struct resource *
-openpic_allocate_intr(device_t dev, device_t child, int *rid, u_long intr,
- u_int flags)
+void
+openpic_dispatch(device_t dev, struct trapframe *tf)
{
- struct openpic_softc *sc;
- struct resource *rv;
- int needactivate;
+ struct openpic_softc *sc;
+ u_int vector;
sc = device_get_softc(dev);
- 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",
- device_get_nameunit(child));
- return (NULL);
+ while (1) {
+ vector = openpic_read(sc, OPENPIC_IACK(0));
+ vector &= OPENPIC_VECTOR_MASK;
+ if (vector == 255)
+ break;
+ powerpc_dispatch_intr(vector, tf);
}
- rman_set_rid(rv, *rid);
- if (needactivate) {
- if (bus_activate_resource(child, SYS_RES_IRQ, *rid, rv) != 0) {
- device_printf(dev,
- "resource activation failed for %s\n",
- device_get_nameunit(child));
- rman_release_resource(rv);
- return (NULL);
- }
- }
-
- return (rv);
}
-int
-openpic_setup_intr(device_t dev, device_t child, struct resource *res,
- int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
- void **cookiep)
+void
+openpic_enable(device_t dev, u_int irq, u_int vector)
{
- struct openpic_softc *sc;
- u_long start;
- int error;
+ struct openpic_softc *sc;
+ uint32_t x;
sc = device_get_softc(dev);
- start = rman_get_start(res);
-
- if (res == NULL) {
- device_printf(dev, "null interrupt resource from %s\n",
- device_get_nameunit(child));
- return (EINVAL);
- }
-
- if ((rman_get_flags(res) & RF_SHAREABLE) == 0)
- flags |= INTR_EXCL;
-
- /*
- * We depend here on rman_activate_resource() being idempotent.
- */
- error = rman_activate_resource(res);
- if (error)
- return (error);
-
- error = inthand_add(device_get_nameunit(child), start, filt, intr, arg,
- flags, cookiep);
-
- if (sc->sc_hwprobed)
- openpic_enable_irq(sc, start, IST_LEVEL);
- else
- sc->sc_irqrsv[start] = 1;
-
- return (error);
-}
-
-int
-openpic_teardown_intr(device_t dev, device_t child, struct resource *res,
- void *ih)
-{
- int error;
-
- error = rman_deactivate_resource(res);
- if (error)
- return (error);
-
- error = inthand_remove(rman_get_start(res), ih);
-
- return (error);
-}
-
-int
-openpic_release_intr(device_t dev, device_t child, int rid,
- struct resource *res)
-{
- int error;
-
- if (rman_get_flags(res) & RF_ACTIVE) {
- error = bus_deactivate_resource(child, SYS_RES_IRQ, rid, res);
- if (error)
- return (error);
- }
-
- return (rman_release_resource(res));
-}
-
-/*
- * Local routines
- */
-
-static u_int
-openpic_read(struct openpic_softc *sc, int reg)
-{
- 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)
-{
- bus_space_write_4(sc->sc_bt, sc->sc_bh, reg, val);
-}
-
-static int
-openpic_read_irq(struct openpic_softc *sc, int cpu)
-{
- return openpic_read(sc, OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
-}
-
-static void
-openpic_eoi(struct openpic_softc *sc, int cpu)
-{
- openpic_write(sc, OPENPIC_EOI(cpu), 0);
+ x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
+ x &= ~(OPENPIC_IMASK | OPENPIC_VECTOR_MASK);
+ x |= vector;
+ openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
}
-static void
-openpic_enable_irq(struct openpic_softc *sc, int irq, int type)
+void
+openpic_eoi(device_t dev, u_int irq __unused)
{
- u_int x;
+ struct openpic_softc *sc;
- x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
- x &= ~(OPENPIC_IMASK | OPENPIC_SENSE_LEVEL | OPENPIC_SENSE_EDGE);
- if (type == IST_LEVEL)
- x |= OPENPIC_SENSE_LEVEL;
- else
- x |= OPENPIC_SENSE_EDGE;
- openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
+ sc = device_get_softc(dev);
+ openpic_write(sc, OPENPIC_EOI(0), 0);
}
-static void
-openpic_disable_irq(struct openpic_softc *sc, int irq)
+void
+openpic_mask(device_t dev, u_int irq)
{
- u_int x;
+ struct openpic_softc *sc;
+ uint32_t x;
+ sc = device_get_softc(dev);
x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
x |= OPENPIC_IMASK;
openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
+ openpic_write(sc, OPENPIC_EOI(0), 0);
}
-static void
-openpic_set_priority(struct openpic_softc *sc, int cpu, int pri)
-{
- u_int x;
-
- x = openpic_read(sc, OPENPIC_CPU_PRIORITY(cpu));
- x &= ~OPENPIC_CPU_PRIORITY_MASK;
- x |= pri;
- openpic_write(sc, OPENPIC_CPU_PRIORITY(cpu), x);
-}
-
-static void
-openpic_intr(void)
+void
+openpic_unmask(device_t dev, u_int irq)
{
struct openpic_softc *sc;
- int irq;
- u_int32_t msr;
-
- sc = openpic_softc;
- msr = mfmsr();
-
- irq = openpic_read_irq(sc, 0);
- if (irq == 255) {
- return;
- }
-
-start:
- openpic_disable_irq(sc, irq);
- /*mtmsr(msr | PSL_EE);*/
+ uint32_t x;
- /* do the interrupt thang */
- intr_handle(irq);
-
- mtmsr(msr);
-
- openpic_eoi(sc, 0);
-
- irq = openpic_read_irq(sc, 0);
- if (irq != 255)
- goto start;
-}
-
-static void
-openpic_ext_enable_irq(uintptr_t irq)
-{
- if (!openpic_softc->sc_hwprobed)
- return;
-
- openpic_enable_irq(openpic_softc, irq, IST_LEVEL);
-}
-
-static void
-openpic_ext_disable_irq(uintptr_t irq)
-{
- if (!openpic_softc->sc_hwprobed)
- return;
-
- openpic_disable_irq(openpic_softc, irq);
+ sc = device_get_softc(dev);
+ x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq));
+ x &= ~OPENPIC_IMASK;
+ openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x);
}
diff --git a/sys/powerpc/powerpc/pic_if.m b/sys/powerpc/powerpc/pic_if.m
index 2b22b0f..9db9c16 100644
--- a/sys/powerpc/powerpc/pic_if.m
+++ b/sys/powerpc/powerpc/pic_if.m
@@ -28,38 +28,32 @@
#
#include <sys/bus.h>
+#include <machine/frame.h>
INTERFACE pic;
-METHOD struct resource * allocate_intr {
+METHOD void dispatch {
device_t dev;
- device_t child;
- int *rid;
- u_long intr;
- u_int flags;
+ struct trapframe *tf;
};
-METHOD int setup_intr {
+METHOD void enable {
device_t dev;
- device_t child;
- struct resource *res;
- int flags;
- driver_filter_t *filter;
- driver_intr_t *intr;
- void *arg;
- void **cookiep;
+ u_int irq;
+ u_int vector;
};
-METHOD int teardown_intr {
+METHOD void eoi {
device_t dev;
- device_t child;
- struct resource *res;
- void *ih;
+ u_int irq;
};
-METHOD int release_intr {
+METHOD void mask {
device_t dev;
- device_t child;
- int rid;
- struct resource *res;
+ u_int irq;
+};
+
+METHOD void unmask {
+ device_t dev;
+ u_int irq;
};
diff --git a/sys/powerpc/psim/openpic_iobus.c b/sys/powerpc/psim/openpic_iobus.c
index 9be65a8..a3a69d3 100644
--- a/sys/powerpc/psim/openpic_iobus.c
+++ b/sys/powerpc/psim/openpic_iobus.c
@@ -60,117 +60,33 @@ __FBSDID("$FreeBSD$");
#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
+ * PSIM IOBus 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[] = {
+static device_method_t openpic_iobus_methods[] = {
/* Device interface */
- DEVMETHOD(device_identify, openpic_psim_identify),
- DEVMETHOD(device_probe, openpic_psim_probe),
- DEVMETHOD(device_attach, openpic_psim_attach),
+ DEVMETHOD(device_probe, openpic_iobus_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),
+ DEVMETHOD(pic_dispatch, openpic_dispatch),
+ DEVMETHOD(pic_enable, openpic_enable),
+ DEVMETHOD(pic_eoi, openpic_eoi),
+ DEVMETHOD(pic_mask, openpic_mask),
+ DEVMETHOD(pic_unmask, openpic_unmask),
{ 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",
openpic_iobus_methods,
- 0
+ sizeof(struct openpic_softc)
};
-static devclass_t openpic_iobus_devclass;
-
-DRIVER_MODULE(openpiciobus, iobus, openpic_iobus_driver,
- openpic_iobus_devclass, 0, 0);
+DRIVER_MODULE(openpic, iobus, openpic_iobus_driver, openpic_devclass, 0, 0);
static int
openpic_iobus_probe(device_t dev)
@@ -179,42 +95,12 @@ openpic_iobus_probe(device_t dev)
name = iobus_get_name(dev);
if (strcmp(name, "interrupt-controller") != 0)
- return (ENXIO);
+ 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);
+ device_set_desc(dev, OPENPIC_DEVSTR);
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_any(dev, SYS_RES_MEMORY, &rid,
- 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