diff options
-rw-r--r-- | sys/powerpc/aim/interrupt.c | 19 | ||||
-rw-r--r-- | sys/powerpc/aim/nexus.c | 95 | ||||
-rw-r--r-- | sys/powerpc/include/intr_machdep.h | 29 | ||||
-rw-r--r-- | sys/powerpc/include/md_var.h | 9 | ||||
-rw-r--r-- | sys/powerpc/include/openpicvar.h | 33 | ||||
-rw-r--r-- | sys/powerpc/powermac/hrowpic.c | 436 | ||||
-rw-r--r-- | sys/powerpc/powermac/hrowpicvar.h | 12 | ||||
-rw-r--r-- | sys/powerpc/powermac/openpic_macio.c | 156 | ||||
-rw-r--r-- | sys/powerpc/powerpc/autoconf.c | 9 | ||||
-rw-r--r-- | sys/powerpc/powerpc/interrupt.c | 19 | ||||
-rw-r--r-- | sys/powerpc/powerpc/intr_machdep.c | 187 | ||||
-rw-r--r-- | sys/powerpc/powerpc/nexus.c | 95 | ||||
-rw-r--r-- | sys/powerpc/powerpc/openpic.c | 316 | ||||
-rw-r--r-- | sys/powerpc/powerpc/pic_if.m | 36 | ||||
-rw-r--r-- | sys/powerpc/psim/openpic_iobus.c | 142 |
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)); -} - - |