Add support for the BUS_CONFIG_INTR() method to the platform and to

openpic(4). Make use of it in ocpbus(4). On the MPC85xxCDS, IRQ0:4
are active-low.
This commit is contained in:
Marcel Moolenaar 2008-03-07 22:08:43 +00:00
parent 6e7ed93017
commit d6f5929710
9 changed files with 136 additions and 42 deletions

View File

@ -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_ */

View File

@ -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);

View File

@ -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));
}

View File

@ -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),

View File

@ -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),

View File

@ -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)
{

View File

@ -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)
{

View File

@ -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;

View File

@ -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),