diff --git a/sys/powerpc/include/intr_machdep.h b/sys/powerpc/include/intr_machdep.h index ebab93b39d04..0cadf0ce4669 100644 --- a/sys/powerpc/include/intr_machdep.h +++ b/sys/powerpc/include/intr_machdep.h @@ -43,5 +43,6 @@ 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 *); +int powerpc_config_intr(int, enum intr_trigger, enum intr_polarity); #endif /* _MACHINE_INTR_MACHDEP_H_ */ diff --git a/sys/powerpc/include/openpicvar.h b/sys/powerpc/include/openpicvar.h index f1db26c3b2d1..403823bc745f 100644 --- a/sys/powerpc/include/openpicvar.h +++ b/sys/powerpc/include/openpicvar.h @@ -54,6 +54,7 @@ int openpic_attach(device_t); /* * PIC interface. */ +void openpic_config(device_t, u_int, enum intr_trigger, enum intr_polarity); void openpic_dispatch(device_t, struct trapframe *); void openpic_enable(device_t, u_int, u_int); void openpic_eoi(device_t, u_int); diff --git a/sys/powerpc/mpc85xx/ocpbus.c b/sys/powerpc/mpc85xx/ocpbus.c index 9099fa7ce62c..cc6c724dcb0b 100644 --- a/sys/powerpc/mpc85xx/ocpbus.c +++ b/sys/powerpc/mpc85xx/ocpbus.c @@ -76,6 +76,8 @@ static int ocpbus_read_ivar(device_t, device_t, int, uintptr_t *); static int ocpbus_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int ocpbus_teardown_intr(device_t, device_t, struct resource *, void *); +static int ocpbus_config_intr(device_t, int, enum intr_trigger, + enum intr_polarity); /* * Bus interface definition @@ -91,6 +93,7 @@ static device_method_t ocpbus_methods[] = { DEVMETHOD(bus_read_ivar, ocpbus_read_ivar), DEVMETHOD(bus_setup_intr, ocpbus_setup_intr), DEVMETHOD(bus_teardown_intr, ocpbus_teardown_intr), + DEVMETHOD(bus_config_intr, ocpbus_config_intr), DEVMETHOD(bus_get_resource, ocpbus_get_resource), DEVMETHOD(bus_alloc_resource, ocpbus_alloc_resource), @@ -279,6 +282,9 @@ ocpbus_attach (device_t dev) device_printf(dev, "PORDEVSR=%08x, PORDEVSR2=%08x\n", in32(OCP85XX_PORDEVSR), in32(OCP85XX_PORDEVSR2)); + for (i = 0; i < 4; i++) + powerpc_config_intr(i, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW); + return (bus_generic_attach(dev)); } @@ -594,3 +600,13 @@ ocpbus_teardown_intr(device_t dev, device_t child, struct resource *res, return (powerpc_teardown_intr(cookie)); } + +static int +ocpbus_config_intr(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + + if (irq < PIC_IRQ_START) + return (EINVAL); + return (powerpc_config_intr(irq - PIC_IRQ_START, trig, pol)); +} diff --git a/sys/powerpc/mpc85xx/opic.c b/sys/powerpc/mpc85xx/opic.c index aff8f3652491..529226a5014e 100644 --- a/sys/powerpc/mpc85xx/opic.c +++ b/sys/powerpc/mpc85xx/opic.c @@ -56,6 +56,7 @@ static device_method_t openpic_ocpbus_methods[] = { DEVMETHOD(device_attach, openpic_attach), /* PIC interface */ + DEVMETHOD(pic_config, openpic_config), DEVMETHOD(pic_dispatch, openpic_dispatch), DEVMETHOD(pic_enable, openpic_enable), DEVMETHOD(pic_eoi, openpic_eoi), diff --git a/sys/powerpc/powermac/openpic_macio.c b/sys/powerpc/powermac/openpic_macio.c index 7d4a9c8d8dad..49d935a4d459 100644 --- a/sys/powerpc/powermac/openpic_macio.c +++ b/sys/powerpc/powermac/openpic_macio.c @@ -67,6 +67,7 @@ static device_method_t openpic_macio_methods[] = { DEVMETHOD(device_attach, openpic_attach), /* PIC interface */ + DEVMETHOD(pic_config, openpic_config), DEVMETHOD(pic_dispatch, openpic_dispatch), DEVMETHOD(pic_enable, openpic_enable), DEVMETHOD(pic_eoi, openpic_eoi), diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c index 3449b74aa0a3..2055519c740b 100644 --- a/sys/powerpc/powerpc/intr_machdep.c +++ b/sys/powerpc/powerpc/intr_machdep.c @@ -89,7 +89,10 @@ MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data"); struct powerpc_intr { struct intr_event *event; long *cntp; + enum intr_trigger trig; + enum intr_polarity pol; u_int irq; + u_int vector; }; static struct powerpc_intr *powerpc_intrs[INTR_VECTORS]; @@ -98,6 +101,56 @@ static u_int stray_count; device_t pic; +static struct powerpc_intr * +intr_lookup(u_int irq) +{ + struct powerpc_intr *i, *iscan; + int vector; + + for (vector = 0; vector < nvectors; vector++) { + i = powerpc_intrs[vector]; + if (i != NULL && i->irq == irq) + return (i); + } + + i = malloc(sizeof(*i), M_INTR, M_NOWAIT); + if (i == NULL) + return (NULL); + + i->event = NULL; + i->cntp = NULL; + i->trig = INTR_TRIGGER_CONFORM; + i->pol = INTR_POLARITY_CONFORM; + i->irq = irq; + i->vector = -1; + + /* XXX LOCK */ + + for (vector = 0; vector < INTR_VECTORS && vector <= nvectors; + vector++) { + iscan = powerpc_intrs[vector]; + if (iscan != NULL && iscan->irq == irq) + break; + if (iscan == NULL && i->vector == -1) + i->vector = vector; + iscan = NULL; + } + + if (iscan == NULL && i->vector != -1) { + powerpc_intrs[i->vector] = i; + nvectors++; + } + + /* XXX UNLOCK */ + + if (iscan != NULL || i->vector == -1) { + free(i, M_INTR); + i = iscan; + } + + return (i); +} + static void intrcnt_setname(const char *name, int index) { @@ -149,7 +202,12 @@ powerpc_enable_intr(void) if (i == NULL) continue; - PIC_ENABLE(pic, i->irq, vector); + if (i->trig != INTR_TRIGGER_CONFORM || + i->pol != INTR_POLARITY_CONFORM) + PIC_CONFIG(pic, i->irq, i->trig, i->pol); + + if (i->event != NULL) + PIC_ENABLE(pic, i->irq, vector); } return (0); @@ -160,64 +218,31 @@ 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 powerpc_intr *i; - u_int vector; int error; - /* XXX lock */ + i = intr_lookup(irq); + if (i == NULL) + return (ENOMEM); - 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) { - /* XXX unlock */ - return (ENOMEM); - } + if (i->event == NULL) { error = intr_event_create(&i->event, (void *)irq, 0, powerpc_intr_unmask, #ifdef INTR_FILTER powerpc_intr_eoi, powerpc_intr_mask, #endif "irq%u:", irq); - if (error) { - /* XXX unlock */ - free(i, M_INTR); + if (error) return (error); - } - vector = nvectors++; - powerpc_intrs[vector] = i; - - i->irq = irq; - - /* XXX unlock */ - - i->cntp = &intrcnt[vector]; - intrcnt_setname(i->event->ie_fullname, vector); + i->cntp = &intrcnt[i->vector]; if (!cold) - PIC_ENABLE(pic, i->irq, vector); - } else { - /* XXX unlock */ + PIC_ENABLE(pic, i->irq, i->vector); } error = intr_event_add_handler(i->event, name, filter, handler, arg, intr_priority(flags), flags, cookiep); - if (!error) - intrcnt_setname(i->event->ie_fullname, vector); + intrcnt_setname(i->event->ie_fullname, i->vector); return (error); } @@ -228,6 +253,27 @@ powerpc_teardown_intr(void *cookie) return (intr_event_remove_handler(cookie)); } +int +powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol) +{ + struct powerpc_intr *i; + + if (trig == INTR_TRIGGER_CONFORM && pol == INTR_POLARITY_CONFORM) + return (0); + + i = intr_lookup(irq); + if (i == NULL) + return (ENOMEM); + + i->trig = trig; + i->pol = pol; + + if (!cold) + PIC_CONFIG(pic, irq, trig, pol); + + return (0); +} + void powerpc_dispatch_intr(u_int vector, struct trapframe *tf) { diff --git a/sys/powerpc/powerpc/openpic.c b/sys/powerpc/powerpc/openpic.c index 6d8458f92276..c778a2495d8f 100644 --- a/sys/powerpc/powerpc/openpic.c +++ b/sys/powerpc/powerpc/openpic.c @@ -180,6 +180,26 @@ openpic_attach(device_t dev) * PIC I/F methods */ +void +openpic_config(device_t dev, u_int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + struct openpic_softc *sc; + uint32_t x; + + sc = device_get_softc(dev); + x = openpic_read(sc, OPENPIC_SRC_VECTOR(irq)); + if (pol == INTR_POLARITY_LOW) + x &= ~OPENPIC_POLARITY_POSITIVE; + else + x |= OPENPIC_POLARITY_POSITIVE; + if (trig == INTR_TRIGGER_EDGE) + x &= ~OPENPIC_SENSE_LEVEL; + else + x |= OPENPIC_SENSE_LEVEL; + openpic_write(sc, OPENPIC_SRC_VECTOR(irq), x); +} + void openpic_dispatch(device_t dev, struct trapframe *tf) { diff --git a/sys/powerpc/powerpc/pic_if.m b/sys/powerpc/powerpc/pic_if.m index a569331f99b2..2fc507122340 100644 --- a/sys/powerpc/powerpc/pic_if.m +++ b/sys/powerpc/powerpc/pic_if.m @@ -32,6 +32,13 @@ INTERFACE pic; +METHOD void config { + device_t dev; + u_int irq; + enum intr_trigger trig; + enum intr_polarity pol; +}; + METHOD void dispatch { device_t dev; struct trapframe *tf; diff --git a/sys/powerpc/psim/openpic_iobus.c b/sys/powerpc/psim/openpic_iobus.c index 96d5d4d649cc..4710f597a3b6 100644 --- a/sys/powerpc/psim/openpic_iobus.c +++ b/sys/powerpc/psim/openpic_iobus.c @@ -71,6 +71,7 @@ static device_method_t openpic_iobus_methods[] = { DEVMETHOD(device_attach, openpic_attach), /* PIC interface */ + DEVMETHOD(pic_config, openpic_config), DEVMETHOD(pic_dispatch, openpic_dispatch), DEVMETHOD(pic_enable, openpic_enable), DEVMETHOD(pic_eoi, openpic_eoi),