Use the MI ithread helper functions in the x86 interrupt code.

This commit is contained in:
John Baldwin 2001-02-09 17:47:44 +00:00
parent 062d8ff5a0
commit 2e0c76cd20
12 changed files with 406 additions and 890 deletions

View file

@ -560,23 +560,17 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
int flags, void (*ihand)(void *), void *arg, void **cookiep)
{
driver_t *driver;
int error, icflags;
int pri; /* interrupt thread priority */
int error;
/* somebody tried to setup an irq that failed to allocate! */
if (irq == NULL)
panic("nexus_setup_intr: NULL irq resource!");
*cookiep = 0;
if (irq->r_flags & RF_SHAREABLE)
icflags = 0;
else
icflags = INTR_EXCL;
if ((irq->r_flags & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
driver = device_get_driver(child);
pri = ithread_priority(flags);
if (flags & INTR_FAST)
icflags |= INTR_FAST;
/*
* We depend here on rman_activate_resource() being idempotent.
@ -585,10 +579,8 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
if (error)
return (error);
*cookiep = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, pri, icflags);
if (*cookiep == NULL)
error = EINVAL; /* XXX ??? */
error = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, flags, cookiep);
return (error);
}

View file

@ -560,23 +560,17 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
int flags, void (*ihand)(void *), void *arg, void **cookiep)
{
driver_t *driver;
int error, icflags;
int pri; /* interrupt thread priority */
int error;
/* somebody tried to setup an irq that failed to allocate! */
if (irq == NULL)
panic("nexus_setup_intr: NULL irq resource!");
*cookiep = 0;
if (irq->r_flags & RF_SHAREABLE)
icflags = 0;
else
icflags = INTR_EXCL;
if ((irq->r_flags & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
driver = device_get_driver(child);
pri = ithread_priority(flags);
if (flags & INTR_FAST)
icflags |= INTR_FAST;
/*
* We depend here on rman_activate_resource() being idempotent.
@ -585,10 +579,8 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
if (error)
return (error);
*cookiep = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, pri, icflags);
if (*cookiep == NULL)
error = EINVAL; /* XXX ??? */
error = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, flags, cookiep);
return (error);
}

View file

@ -93,10 +93,12 @@
* Per-interrupt data.
*/
u_long *intr_countp[ICU_LEN]; /* pointers to interrupt counters */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
void *intr_unit[ICU_LEN];
static struct mtx ithds_table_lock; /* protect the ithds table */
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
@ -133,6 +135,10 @@ static inthand_t *slowintr[ICU_LEN] = {
static driver_intr_t isa_strayintr;
static void ithds_init(void *dummy);
static void ithread_enable(int vector);
static void ithread_disable(int vector);
#ifdef PC98
#define NMI_PARITY 0x04
#define NMI_EPARITY 0x02
@ -388,7 +394,7 @@ isa_irq_pending()
* vmstat(8) and the like.
*/
static void
update_intrname(int intr, char *name)
update_intrname(int intr, const char *name)
{
char buf[32];
char *cp;
@ -536,132 +542,90 @@ icu_unset(intr, handler)
return (0);
}
struct intrhand *
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
int pri, int flags)
static void
ithds_init(void *dummy)
{
struct ithd *ithd = ithds[irq]; /* descriptor for the IRQ */
struct intrhand *head; /* chain of handlers for IRQ */
struct intrhand *idesc; /* descriptor for this handler */
struct proc *p; /* interrupt thread */
mtx_init(&ithds_table_lock, "ithread table lock", MTX_SPIN);
}
SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL);
static void
ithread_enable(int vector)
{
INTREN(1 << vector);
}
static void
ithread_disable(int vector)
{
INTRDIS(1 << vector);
}
int
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep)
{
struct ithd *ithd; /* descriptor for the IRQ */
int errcode = 0;
int created_ithd = 0;
if (name == NULL) /* no name? */
panic ("anonymous interrupt");
if (ithd == NULL || ithd->it_ih == NULL) {
/* first handler for this irq. */
if (ithd == NULL) {
ithd = malloc(sizeof (struct ithd), M_DEVBUF,
M_WAITOK | M_ZERO);
if (ithd == NULL)
return (NULL);
ithd->irq = irq;
/*
* Work around a race where more than one CPU may be registering
* handlers on the same IRQ at the same time.
*/
mtx_lock_spin(&ithds_table_lock);
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
if (ithd == NULL) {
errcode = ithread_create(&ithd, irq, 0, ithread_disable,
ithread_enable, "irq%d:", irq);
if (errcode)
return (errcode);
mtx_lock_spin(&ithds_table_lock);
if (ithds[irq] == NULL) {
ithds[irq] = ithd;
created_ithd++;
mtx_unlock_spin(&ithds_table_lock);
} else {
struct ithd *orphan;
orphan = ithd;
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
ithread_destroy(orphan);
}
/*
* If we have a fast interrupt, we need to set the
* handler address directly. Do that below. For a
* slow interrupt, we don't need to know more details,
* so do it here because it's tidier.
*/
if ((flags & INTR_FAST) == 0) {
/*
* Only create a kernel thread if we don't already
* have one.
*/
if (ithd->it_proc == NULL) {
errcode = kthread_create(ithd_loop, NULL, &p,
RFSTOPPED | RFHIGHPID, "irq%d: %s", irq,
name);
if (errcode)
panic("inthand_add: Can't create "
"interrupt thread");
p->p_intr_nesting_level = 1;
p->p_rtprio.type = RTP_PRIO_ITHREAD;
p->p_stat = SWAIT; /* we're idle */
/* Put in linkages. */
ithd->it_proc = p;
p->p_ithd = ithd;
} else
snprintf(ithd->it_proc->p_comm, MAXCOMLEN,
"irq%d: %s", irq, name);
p->p_rtprio.prio = pri;
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
}
} else if ((flags & INTR_EXCL) != 0
|| (ithd->it_ih->ih_flags & INTR_EXCL) != 0) {
/*
* We can't append the new handler if either
* list ithd or new handler do not allow
* interrupts to be shared.
*/
if (bootverbose)
printf("\tdevice combination %s and %s "
"doesn't support shared irq%d\n",
ithd->it_ih->ih_name, name, irq);
return(NULL);
} else if (flags & INTR_FAST) {
/* We can only have one fast interrupt by itself. */
if (bootverbose)
printf("\tCan't add fast interrupt %s"
" to normal interrupt %s on irq%d",
name, ithd->it_ih->ih_name, irq);
return (NULL);
} else { /* update p_comm */
p = ithd->it_proc;
if (strlen(p->p_comm) + strlen(name) < MAXCOMLEN) {
strcat(p->p_comm, " ");
strcat(p->p_comm, name);
} else if (strlen(p->p_comm) == MAXCOMLEN)
p->p_comm[MAXCOMLEN - 1] = '+';
else
strcat(p->p_comm, "+");
}
idesc = malloc(sizeof (struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO);
if (idesc == NULL)
return (NULL);
idesc->ih_handler = handler;
idesc->ih_argument = arg;
idesc->ih_flags = flags;
idesc->ih_ithd = ithd;
errcode = ithread_add_handler(ithd, name, handler, arg,
ithread_priority(flags), flags, cookiep);
if ((flags & INTR_FAST) == 0 || errcode)
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
idesc->ih_name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
if (idesc->ih_name == NULL) {
free(idesc, M_DEVBUF);
return (NULL);
}
strcpy(idesc->ih_name, name);
/* Slow interrupts got set up above. */
if ((flags & INTR_FAST)
&& (icu_setup(irq, idesc->ih_handler, idesc->ih_argument,
idesc->ih_flags) != 0) ) {
if (bootverbose)
if (errcode)
return (errcode);
if (flags & INTR_FAST) {
errcode = icu_setup(irq, handler, arg, flags);
if (errcode && bootverbose)
printf("\tinthand_add(irq%d) failed, result=%d\n",
irq, errcode);
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return NULL;
if (errcode)
return (errcode);
}
head = ithd->it_ih; /* look at chain of handlers */
if (head) {
while (head->ih_next != NULL)
head = head->ih_next; /* find the end */
head->ih_next = idesc; /* hook it in there */
} else
ithd->it_ih = idesc; /* put it up front */
update_intrname(irq, idesc->ih_name);
return (idesc);
update_intrname(irq, name);
return (0);
}
/*
@ -673,50 +637,9 @@ inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
* structure to the system. First ensure the handler is not actively
* in use.
*/
int
inthand_remove(struct intrhand *idesc)
inthand_remove(void *cookie)
{
struct ithd *ithd; /* descriptor for the IRQ */
struct intrhand *ih; /* chain of handlers */
if (idesc == NULL)
return (-1);
ithd = idesc->ih_ithd;
ih = ithd->it_ih;
if (ih == idesc) /* first in the chain */
ithd->it_ih = idesc->ih_next; /* unhook it */
else {
while ((ih != NULL)
&& (ih->ih_next != idesc) )
ih = ih->ih_next;
if (ih->ih_next != idesc)
return (-1);
ih->ih_next = ih->ih_next->ih_next;
}
if (ithd->it_ih == NULL) { /* no handlers left, */
icu_unset(ithd->irq, idesc->ih_handler);
ithds[ithd->irq] = NULL;
if ((idesc->ih_flags & INTR_FAST) == 0) {
mtx_lock_spin(&sched_lock);
if (ithd->it_proc->p_stat == SWAIT) {
ithd->it_proc->p_intr_nesting_level = 0;
ithd->it_proc->p_stat = SRUN;
setrunqueue(ithd->it_proc);
/*
* We don't do an ast here because we really
* don't care when it runs next.
*
* XXX: should we lower the threads priority?
*/
}
mtx_unlock_spin(&sched_lock);
}
}
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return (0);
return (ithread_remove_handler(cookie));
}

View file

@ -220,13 +220,10 @@ int icu_unset __P((int intr, driver_intr_t *handler));
* WARNING: These are internal functions and not to be used by device drivers!
* They are subject to change without notice.
*/
struct intrhand *inthand_add(const char *name, int irq, driver_intr_t handler,
void *arg, int pri, int flags);
int inthand_remove(struct intrhand *idesc);
void sched_ithd(void *);
void ithd_loop(void *);
void start_softintr(void *);
void intr_soft(void *);
int inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep);
int inthand_remove(void *cookie);
void sched_ithd(void *dummy);
#endif /* LOCORE */

View file

@ -51,6 +51,8 @@
#include <sys/unistd.h>
#include <sys/errno.h>
#include <sys/interrupt.h>
#include <sys/random.h>
#include <sys/time.h>
#include <machine/md_var.h>
#include <machine/segments.h>
@ -64,6 +66,11 @@
#include <sys/ktr.h>
#include <machine/cpu.h>
struct int_entropy {
struct proc *p;
int irq;
};
static u_int straycount[NHWI];
#define MAX_STRAY_LOG 5
@ -87,6 +94,19 @@ sched_ithd(void *cookie)
*/
atomic_add_long(intr_countp[irq], 1); /* one more for this IRQ */
atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */
/*
* If this interrupt is marked as being a source of entropy, use
* the current timestamp to feed entropy to the PRNG.
*/
if (ir != NULL && (ir->it_flags & IT_ENTROPY)) {
struct int_entropy entropy;
entropy.irq = irq;
entropy.p = curproc;
random_harvest(&entropy, sizeof(entropy), 2, 0,
RANDOM_INTERRUPT);
}
/*
* If we don't have an interrupt resource or an interrupt thread for
@ -121,102 +141,13 @@ sched_ithd(void *cookie)
/* membar_lock(); */
ir->it_proc->p_stat = SRUN;
setrunqueue(ir->it_proc);
if (!cold) {
if (curproc != PCPU_GET(idleproc))
setrunqueue(curproc);
mi_switch();
}
need_resched();
}
else {
CTR3(KTR_INTR, "sched_ithd %d: it_need %d, state %d",
ir->it_proc->p_pid,
ir->it_need,
ir->it_proc->p_stat );
need_resched();
}
mtx_unlock_spin(&sched_lock);
}
/*
* This is the main code for all interrupt threads. It gets put on
* whichkqs by setrunqueue above.
*/
void
ithd_loop(void *dummy)
{
struct ithd *me; /* our thread context */
struct intrhand *ih; /* and our interrupt handler chain */
me = curproc->p_ithd; /* point to myself */
/*
* As long as we have interrupts outstanding, go through the
* list of handlers, giving each one a go at it.
*/
for (;;) {
/*
* If we don't have any handlers, then we are an orphaned
* thread and just need to die.
*/
if (me->it_ih == NULL) {
CTR2(KTR_INTR, "ithd_loop pid %d(%s) exiting",
me->it_proc->p_pid, me->it_proc->p_comm);
curproc->p_ithd = NULL;
free(me, M_DEVBUF);
mtx_lock(&Giant);
kthread_exit(0);
}
CTR3(KTR_INTR, "ithd_loop pid %d(%s) need=%d",
me->it_proc->p_pid, me->it_proc->p_comm, me->it_need);
while (me->it_need) {
/*
* Service interrupts. If another interrupt
* arrives while we are running, they will set
* it_need to denote that we should make
* another pass.
*/
me->it_need = 0;
#if 0
membar_unlock(); /* push out "it_need=0" */
#endif
for (ih = me->it_ih; ih != NULL; ih = ih->ih_next) {
CTR5(KTR_INTR,
"ithd_loop pid %d ih=%p: %p(%p) flg=%x",
me->it_proc->p_pid, (void *)ih,
(void *)ih->ih_handler, ih->ih_argument,
ih->ih_flags);
if ((ih->ih_flags & INTR_MPSAFE) == 0)
mtx_lock(&Giant);
ih->ih_handler(ih->ih_argument);
if ((ih->ih_flags & INTR_MPSAFE) == 0)
mtx_unlock(&Giant);
}
}
/*
* Processed all our interrupts. Now get the sched
* lock. This may take a while and it_need may get
* set again, so we have to check it again.
*/
mtx_assert(&Giant, MA_NOTOWNED);
mtx_lock_spin(&sched_lock);
if (!me->it_need) {
INTREN (1 << me->irq); /* reset the mask bit */
me->it_proc->p_stat = SWAIT; /* we're idle */
#ifdef APIC_IO
CTR2(KTR_INTR, "ithd_loop pid %d: done, apic_imen=%x",
me->it_proc->p_pid, apic_imen);
#else
CTR2(KTR_INTR, "ithd_loop pid %d: done, imen=%x",
me->it_proc->p_pid, imen);
#endif
mi_switch();
CTR1(KTR_INTR, "ithd_loop pid %d: resumed",
me->it_proc->p_pid);
}
mtx_unlock_spin(&sched_lock);
}
}

View file

@ -93,10 +93,12 @@
* Per-interrupt data.
*/
u_long *intr_countp[ICU_LEN]; /* pointers to interrupt counters */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
void *intr_unit[ICU_LEN];
static struct mtx ithds_table_lock; /* protect the ithds table */
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
@ -133,6 +135,10 @@ static inthand_t *slowintr[ICU_LEN] = {
static driver_intr_t isa_strayintr;
static void ithds_init(void *dummy);
static void ithread_enable(int vector);
static void ithread_disable(int vector);
#ifdef PC98
#define NMI_PARITY 0x04
#define NMI_EPARITY 0x02
@ -388,7 +394,7 @@ isa_irq_pending()
* vmstat(8) and the like.
*/
static void
update_intrname(int intr, char *name)
update_intrname(int intr, const char *name)
{
char buf[32];
char *cp;
@ -536,132 +542,90 @@ icu_unset(intr, handler)
return (0);
}
struct intrhand *
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
int pri, int flags)
static void
ithds_init(void *dummy)
{
struct ithd *ithd = ithds[irq]; /* descriptor for the IRQ */
struct intrhand *head; /* chain of handlers for IRQ */
struct intrhand *idesc; /* descriptor for this handler */
struct proc *p; /* interrupt thread */
mtx_init(&ithds_table_lock, "ithread table lock", MTX_SPIN);
}
SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL);
static void
ithread_enable(int vector)
{
INTREN(1 << vector);
}
static void
ithread_disable(int vector)
{
INTRDIS(1 << vector);
}
int
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep)
{
struct ithd *ithd; /* descriptor for the IRQ */
int errcode = 0;
int created_ithd = 0;
if (name == NULL) /* no name? */
panic ("anonymous interrupt");
if (ithd == NULL || ithd->it_ih == NULL) {
/* first handler for this irq. */
if (ithd == NULL) {
ithd = malloc(sizeof (struct ithd), M_DEVBUF,
M_WAITOK | M_ZERO);
if (ithd == NULL)
return (NULL);
ithd->irq = irq;
/*
* Work around a race where more than one CPU may be registering
* handlers on the same IRQ at the same time.
*/
mtx_lock_spin(&ithds_table_lock);
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
if (ithd == NULL) {
errcode = ithread_create(&ithd, irq, 0, ithread_disable,
ithread_enable, "irq%d:", irq);
if (errcode)
return (errcode);
mtx_lock_spin(&ithds_table_lock);
if (ithds[irq] == NULL) {
ithds[irq] = ithd;
created_ithd++;
mtx_unlock_spin(&ithds_table_lock);
} else {
struct ithd *orphan;
orphan = ithd;
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
ithread_destroy(orphan);
}
/*
* If we have a fast interrupt, we need to set the
* handler address directly. Do that below. For a
* slow interrupt, we don't need to know more details,
* so do it here because it's tidier.
*/
if ((flags & INTR_FAST) == 0) {
/*
* Only create a kernel thread if we don't already
* have one.
*/
if (ithd->it_proc == NULL) {
errcode = kthread_create(ithd_loop, NULL, &p,
RFSTOPPED | RFHIGHPID, "irq%d: %s", irq,
name);
if (errcode)
panic("inthand_add: Can't create "
"interrupt thread");
p->p_intr_nesting_level = 1;
p->p_rtprio.type = RTP_PRIO_ITHREAD;
p->p_stat = SWAIT; /* we're idle */
/* Put in linkages. */
ithd->it_proc = p;
p->p_ithd = ithd;
} else
snprintf(ithd->it_proc->p_comm, MAXCOMLEN,
"irq%d: %s", irq, name);
p->p_rtprio.prio = pri;
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
}
} else if ((flags & INTR_EXCL) != 0
|| (ithd->it_ih->ih_flags & INTR_EXCL) != 0) {
/*
* We can't append the new handler if either
* list ithd or new handler do not allow
* interrupts to be shared.
*/
if (bootverbose)
printf("\tdevice combination %s and %s "
"doesn't support shared irq%d\n",
ithd->it_ih->ih_name, name, irq);
return(NULL);
} else if (flags & INTR_FAST) {
/* We can only have one fast interrupt by itself. */
if (bootverbose)
printf("\tCan't add fast interrupt %s"
" to normal interrupt %s on irq%d",
name, ithd->it_ih->ih_name, irq);
return (NULL);
} else { /* update p_comm */
p = ithd->it_proc;
if (strlen(p->p_comm) + strlen(name) < MAXCOMLEN) {
strcat(p->p_comm, " ");
strcat(p->p_comm, name);
} else if (strlen(p->p_comm) == MAXCOMLEN)
p->p_comm[MAXCOMLEN - 1] = '+';
else
strcat(p->p_comm, "+");
}
idesc = malloc(sizeof (struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO);
if (idesc == NULL)
return (NULL);
idesc->ih_handler = handler;
idesc->ih_argument = arg;
idesc->ih_flags = flags;
idesc->ih_ithd = ithd;
errcode = ithread_add_handler(ithd, name, handler, arg,
ithread_priority(flags), flags, cookiep);
if ((flags & INTR_FAST) == 0 || errcode)
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
idesc->ih_name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
if (idesc->ih_name == NULL) {
free(idesc, M_DEVBUF);
return (NULL);
}
strcpy(idesc->ih_name, name);
/* Slow interrupts got set up above. */
if ((flags & INTR_FAST)
&& (icu_setup(irq, idesc->ih_handler, idesc->ih_argument,
idesc->ih_flags) != 0) ) {
if (bootverbose)
if (errcode)
return (errcode);
if (flags & INTR_FAST) {
errcode = icu_setup(irq, handler, arg, flags);
if (errcode && bootverbose)
printf("\tinthand_add(irq%d) failed, result=%d\n",
irq, errcode);
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return NULL;
if (errcode)
return (errcode);
}
head = ithd->it_ih; /* look at chain of handlers */
if (head) {
while (head->ih_next != NULL)
head = head->ih_next; /* find the end */
head->ih_next = idesc; /* hook it in there */
} else
ithd->it_ih = idesc; /* put it up front */
update_intrname(irq, idesc->ih_name);
return (idesc);
update_intrname(irq, name);
return (0);
}
/*
@ -673,50 +637,9 @@ inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
* structure to the system. First ensure the handler is not actively
* in use.
*/
int
inthand_remove(struct intrhand *idesc)
inthand_remove(void *cookie)
{
struct ithd *ithd; /* descriptor for the IRQ */
struct intrhand *ih; /* chain of handlers */
if (idesc == NULL)
return (-1);
ithd = idesc->ih_ithd;
ih = ithd->it_ih;
if (ih == idesc) /* first in the chain */
ithd->it_ih = idesc->ih_next; /* unhook it */
else {
while ((ih != NULL)
&& (ih->ih_next != idesc) )
ih = ih->ih_next;
if (ih->ih_next != idesc)
return (-1);
ih->ih_next = ih->ih_next->ih_next;
}
if (ithd->it_ih == NULL) { /* no handlers left, */
icu_unset(ithd->irq, idesc->ih_handler);
ithds[ithd->irq] = NULL;
if ((idesc->ih_flags & INTR_FAST) == 0) {
mtx_lock_spin(&sched_lock);
if (ithd->it_proc->p_stat == SWAIT) {
ithd->it_proc->p_intr_nesting_level = 0;
ithd->it_proc->p_stat = SRUN;
setrunqueue(ithd->it_proc);
/*
* We don't do an ast here because we really
* don't care when it runs next.
*
* XXX: should we lower the threads priority?
*/
}
mtx_unlock_spin(&sched_lock);
}
}
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return (0);
return (ithread_remove_handler(cookie));
}

View file

@ -560,23 +560,17 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
int flags, void (*ihand)(void *), void *arg, void **cookiep)
{
driver_t *driver;
int error, icflags;
int pri; /* interrupt thread priority */
int error;
/* somebody tried to setup an irq that failed to allocate! */
if (irq == NULL)
panic("nexus_setup_intr: NULL irq resource!");
*cookiep = 0;
if (irq->r_flags & RF_SHAREABLE)
icflags = 0;
else
icflags = INTR_EXCL;
if ((irq->r_flags & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
driver = device_get_driver(child);
pri = ithread_priority(flags);
if (flags & INTR_FAST)
icflags |= INTR_FAST;
/*
* We depend here on rman_activate_resource() being idempotent.
@ -585,10 +579,8 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
if (error)
return (error);
*cookiep = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, pri, icflags);
if (*cookiep == NULL)
error = EINVAL; /* XXX ??? */
error = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, flags, cookiep);
return (error);
}

View file

@ -560,23 +560,17 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
int flags, void (*ihand)(void *), void *arg, void **cookiep)
{
driver_t *driver;
int error, icflags;
int pri; /* interrupt thread priority */
int error;
/* somebody tried to setup an irq that failed to allocate! */
if (irq == NULL)
panic("nexus_setup_intr: NULL irq resource!");
*cookiep = 0;
if (irq->r_flags & RF_SHAREABLE)
icflags = 0;
else
icflags = INTR_EXCL;
if ((irq->r_flags & RF_SHAREABLE) == 0)
flags |= INTR_EXCL;
driver = device_get_driver(child);
pri = ithread_priority(flags);
if (flags & INTR_FAST)
icflags |= INTR_FAST;
/*
* We depend here on rman_activate_resource() being idempotent.
@ -585,10 +579,8 @@ nexus_setup_intr(device_t bus, device_t child, struct resource *irq,
if (error)
return (error);
*cookiep = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, pri, icflags);
if (*cookiep == NULL)
error = EINVAL; /* XXX ??? */
error = inthand_add(device_get_nameunit(child), irq->r_start,
ihand, arg, flags, cookiep);
return (error);
}

View file

@ -93,10 +93,12 @@
* Per-interrupt data.
*/
u_long *intr_countp[ICU_LEN]; /* pointers to interrupt counters */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
void *intr_unit[ICU_LEN];
static struct mtx ithds_table_lock; /* protect the ithds table */
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
@ -133,6 +135,10 @@ static inthand_t *slowintr[ICU_LEN] = {
static driver_intr_t isa_strayintr;
static void ithds_init(void *dummy);
static void ithread_enable(int vector);
static void ithread_disable(int vector);
#ifdef PC98
#define NMI_PARITY 0x04
#define NMI_EPARITY 0x02
@ -388,7 +394,7 @@ isa_irq_pending()
* vmstat(8) and the like.
*/
static void
update_intrname(int intr, char *name)
update_intrname(int intr, const char *name)
{
char buf[32];
char *cp;
@ -536,132 +542,90 @@ icu_unset(intr, handler)
return (0);
}
struct intrhand *
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
int pri, int flags)
static void
ithds_init(void *dummy)
{
struct ithd *ithd = ithds[irq]; /* descriptor for the IRQ */
struct intrhand *head; /* chain of handlers for IRQ */
struct intrhand *idesc; /* descriptor for this handler */
struct proc *p; /* interrupt thread */
mtx_init(&ithds_table_lock, "ithread table lock", MTX_SPIN);
}
SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL);
static void
ithread_enable(int vector)
{
INTREN(1 << vector);
}
static void
ithread_disable(int vector)
{
INTRDIS(1 << vector);
}
int
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep)
{
struct ithd *ithd; /* descriptor for the IRQ */
int errcode = 0;
int created_ithd = 0;
if (name == NULL) /* no name? */
panic ("anonymous interrupt");
if (ithd == NULL || ithd->it_ih == NULL) {
/* first handler for this irq. */
if (ithd == NULL) {
ithd = malloc(sizeof (struct ithd), M_DEVBUF,
M_WAITOK | M_ZERO);
if (ithd == NULL)
return (NULL);
ithd->irq = irq;
/*
* Work around a race where more than one CPU may be registering
* handlers on the same IRQ at the same time.
*/
mtx_lock_spin(&ithds_table_lock);
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
if (ithd == NULL) {
errcode = ithread_create(&ithd, irq, 0, ithread_disable,
ithread_enable, "irq%d:", irq);
if (errcode)
return (errcode);
mtx_lock_spin(&ithds_table_lock);
if (ithds[irq] == NULL) {
ithds[irq] = ithd;
created_ithd++;
mtx_unlock_spin(&ithds_table_lock);
} else {
struct ithd *orphan;
orphan = ithd;
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
ithread_destroy(orphan);
}
/*
* If we have a fast interrupt, we need to set the
* handler address directly. Do that below. For a
* slow interrupt, we don't need to know more details,
* so do it here because it's tidier.
*/
if ((flags & INTR_FAST) == 0) {
/*
* Only create a kernel thread if we don't already
* have one.
*/
if (ithd->it_proc == NULL) {
errcode = kthread_create(ithd_loop, NULL, &p,
RFSTOPPED | RFHIGHPID, "irq%d: %s", irq,
name);
if (errcode)
panic("inthand_add: Can't create "
"interrupt thread");
p->p_intr_nesting_level = 1;
p->p_rtprio.type = RTP_PRIO_ITHREAD;
p->p_stat = SWAIT; /* we're idle */
/* Put in linkages. */
ithd->it_proc = p;
p->p_ithd = ithd;
} else
snprintf(ithd->it_proc->p_comm, MAXCOMLEN,
"irq%d: %s", irq, name);
p->p_rtprio.prio = pri;
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
}
} else if ((flags & INTR_EXCL) != 0
|| (ithd->it_ih->ih_flags & INTR_EXCL) != 0) {
/*
* We can't append the new handler if either
* list ithd or new handler do not allow
* interrupts to be shared.
*/
if (bootverbose)
printf("\tdevice combination %s and %s "
"doesn't support shared irq%d\n",
ithd->it_ih->ih_name, name, irq);
return(NULL);
} else if (flags & INTR_FAST) {
/* We can only have one fast interrupt by itself. */
if (bootverbose)
printf("\tCan't add fast interrupt %s"
" to normal interrupt %s on irq%d",
name, ithd->it_ih->ih_name, irq);
return (NULL);
} else { /* update p_comm */
p = ithd->it_proc;
if (strlen(p->p_comm) + strlen(name) < MAXCOMLEN) {
strcat(p->p_comm, " ");
strcat(p->p_comm, name);
} else if (strlen(p->p_comm) == MAXCOMLEN)
p->p_comm[MAXCOMLEN - 1] = '+';
else
strcat(p->p_comm, "+");
}
idesc = malloc(sizeof (struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO);
if (idesc == NULL)
return (NULL);
idesc->ih_handler = handler;
idesc->ih_argument = arg;
idesc->ih_flags = flags;
idesc->ih_ithd = ithd;
errcode = ithread_add_handler(ithd, name, handler, arg,
ithread_priority(flags), flags, cookiep);
if ((flags & INTR_FAST) == 0 || errcode)
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
idesc->ih_name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
if (idesc->ih_name == NULL) {
free(idesc, M_DEVBUF);
return (NULL);
}
strcpy(idesc->ih_name, name);
/* Slow interrupts got set up above. */
if ((flags & INTR_FAST)
&& (icu_setup(irq, idesc->ih_handler, idesc->ih_argument,
idesc->ih_flags) != 0) ) {
if (bootverbose)
if (errcode)
return (errcode);
if (flags & INTR_FAST) {
errcode = icu_setup(irq, handler, arg, flags);
if (errcode && bootverbose)
printf("\tinthand_add(irq%d) failed, result=%d\n",
irq, errcode);
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return NULL;
if (errcode)
return (errcode);
}
head = ithd->it_ih; /* look at chain of handlers */
if (head) {
while (head->ih_next != NULL)
head = head->ih_next; /* find the end */
head->ih_next = idesc; /* hook it in there */
} else
ithd->it_ih = idesc; /* put it up front */
update_intrname(irq, idesc->ih_name);
return (idesc);
update_intrname(irq, name);
return (0);
}
/*
@ -673,50 +637,9 @@ inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
* structure to the system. First ensure the handler is not actively
* in use.
*/
int
inthand_remove(struct intrhand *idesc)
inthand_remove(void *cookie)
{
struct ithd *ithd; /* descriptor for the IRQ */
struct intrhand *ih; /* chain of handlers */
if (idesc == NULL)
return (-1);
ithd = idesc->ih_ithd;
ih = ithd->it_ih;
if (ih == idesc) /* first in the chain */
ithd->it_ih = idesc->ih_next; /* unhook it */
else {
while ((ih != NULL)
&& (ih->ih_next != idesc) )
ih = ih->ih_next;
if (ih->ih_next != idesc)
return (-1);
ih->ih_next = ih->ih_next->ih_next;
}
if (ithd->it_ih == NULL) { /* no handlers left, */
icu_unset(ithd->irq, idesc->ih_handler);
ithds[ithd->irq] = NULL;
if ((idesc->ih_flags & INTR_FAST) == 0) {
mtx_lock_spin(&sched_lock);
if (ithd->it_proc->p_stat == SWAIT) {
ithd->it_proc->p_intr_nesting_level = 0;
ithd->it_proc->p_stat = SRUN;
setrunqueue(ithd->it_proc);
/*
* We don't do an ast here because we really
* don't care when it runs next.
*
* XXX: should we lower the threads priority?
*/
}
mtx_unlock_spin(&sched_lock);
}
}
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return (0);
return (ithread_remove_handler(cookie));
}

View file

@ -220,13 +220,10 @@ int icu_unset __P((int intr, driver_intr_t *handler));
* WARNING: These are internal functions and not to be used by device drivers!
* They are subject to change without notice.
*/
struct intrhand *inthand_add(const char *name, int irq, driver_intr_t handler,
void *arg, int pri, int flags);
int inthand_remove(struct intrhand *idesc);
void sched_ithd(void *);
void ithd_loop(void *);
void start_softintr(void *);
void intr_soft(void *);
int inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep);
int inthand_remove(void *cookie);
void sched_ithd(void *dummy);
#endif /* LOCORE */

View file

@ -51,6 +51,8 @@
#include <sys/unistd.h>
#include <sys/errno.h>
#include <sys/interrupt.h>
#include <sys/random.h>
#include <sys/time.h>
#include <machine/md_var.h>
#include <machine/segments.h>
@ -64,6 +66,11 @@
#include <sys/ktr.h>
#include <machine/cpu.h>
struct int_entropy {
struct proc *p;
int irq;
};
static u_int straycount[NHWI];
#define MAX_STRAY_LOG 5
@ -87,6 +94,19 @@ sched_ithd(void *cookie)
*/
atomic_add_long(intr_countp[irq], 1); /* one more for this IRQ */
atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */
/*
* If this interrupt is marked as being a source of entropy, use
* the current timestamp to feed entropy to the PRNG.
*/
if (ir != NULL && (ir->it_flags & IT_ENTROPY)) {
struct int_entropy entropy;
entropy.irq = irq;
entropy.p = curproc;
random_harvest(&entropy, sizeof(entropy), 2, 0,
RANDOM_INTERRUPT);
}
/*
* If we don't have an interrupt resource or an interrupt thread for
@ -121,102 +141,13 @@ sched_ithd(void *cookie)
/* membar_lock(); */
ir->it_proc->p_stat = SRUN;
setrunqueue(ir->it_proc);
if (!cold) {
if (curproc != PCPU_GET(idleproc))
setrunqueue(curproc);
mi_switch();
}
need_resched();
}
else {
CTR3(KTR_INTR, "sched_ithd %d: it_need %d, state %d",
ir->it_proc->p_pid,
ir->it_need,
ir->it_proc->p_stat );
need_resched();
}
mtx_unlock_spin(&sched_lock);
}
/*
* This is the main code for all interrupt threads. It gets put on
* whichkqs by setrunqueue above.
*/
void
ithd_loop(void *dummy)
{
struct ithd *me; /* our thread context */
struct intrhand *ih; /* and our interrupt handler chain */
me = curproc->p_ithd; /* point to myself */
/*
* As long as we have interrupts outstanding, go through the
* list of handlers, giving each one a go at it.
*/
for (;;) {
/*
* If we don't have any handlers, then we are an orphaned
* thread and just need to die.
*/
if (me->it_ih == NULL) {
CTR2(KTR_INTR, "ithd_loop pid %d(%s) exiting",
me->it_proc->p_pid, me->it_proc->p_comm);
curproc->p_ithd = NULL;
free(me, M_DEVBUF);
mtx_lock(&Giant);
kthread_exit(0);
}
CTR3(KTR_INTR, "ithd_loop pid %d(%s) need=%d",
me->it_proc->p_pid, me->it_proc->p_comm, me->it_need);
while (me->it_need) {
/*
* Service interrupts. If another interrupt
* arrives while we are running, they will set
* it_need to denote that we should make
* another pass.
*/
me->it_need = 0;
#if 0
membar_unlock(); /* push out "it_need=0" */
#endif
for (ih = me->it_ih; ih != NULL; ih = ih->ih_next) {
CTR5(KTR_INTR,
"ithd_loop pid %d ih=%p: %p(%p) flg=%x",
me->it_proc->p_pid, (void *)ih,
(void *)ih->ih_handler, ih->ih_argument,
ih->ih_flags);
if ((ih->ih_flags & INTR_MPSAFE) == 0)
mtx_lock(&Giant);
ih->ih_handler(ih->ih_argument);
if ((ih->ih_flags & INTR_MPSAFE) == 0)
mtx_unlock(&Giant);
}
}
/*
* Processed all our interrupts. Now get the sched
* lock. This may take a while and it_need may get
* set again, so we have to check it again.
*/
mtx_assert(&Giant, MA_NOTOWNED);
mtx_lock_spin(&sched_lock);
if (!me->it_need) {
INTREN (1 << me->irq); /* reset the mask bit */
me->it_proc->p_stat = SWAIT; /* we're idle */
#ifdef APIC_IO
CTR2(KTR_INTR, "ithd_loop pid %d: done, apic_imen=%x",
me->it_proc->p_pid, apic_imen);
#else
CTR2(KTR_INTR, "ithd_loop pid %d: done, imen=%x",
me->it_proc->p_pid, imen);
#endif
mi_switch();
CTR1(KTR_INTR, "ithd_loop pid %d: resumed",
me->it_proc->p_pid);
}
mtx_unlock_spin(&sched_lock);
}
}

View file

@ -93,10 +93,12 @@
* Per-interrupt data.
*/
u_long *intr_countp[ICU_LEN]; /* pointers to interrupt counters */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
driver_intr_t *intr_handler[ICU_LEN]; /* first level interrupt handler */
struct ithd *ithds[ICU_LEN]; /* real interrupt handler */
void *intr_unit[ICU_LEN];
static struct mtx ithds_table_lock; /* protect the ithds table */
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
&IDTVEC(fastintr2), &IDTVEC(fastintr3),
@ -133,6 +135,10 @@ static inthand_t *slowintr[ICU_LEN] = {
static driver_intr_t isa_strayintr;
static void ithds_init(void *dummy);
static void ithread_enable(int vector);
static void ithread_disable(int vector);
#ifdef PC98
#define NMI_PARITY 0x04
#define NMI_EPARITY 0x02
@ -388,7 +394,7 @@ isa_irq_pending()
* vmstat(8) and the like.
*/
static void
update_intrname(int intr, char *name)
update_intrname(int intr, const char *name)
{
char buf[32];
char *cp;
@ -536,132 +542,90 @@ icu_unset(intr, handler)
return (0);
}
struct intrhand *
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
int pri, int flags)
static void
ithds_init(void *dummy)
{
struct ithd *ithd = ithds[irq]; /* descriptor for the IRQ */
struct intrhand *head; /* chain of handlers for IRQ */
struct intrhand *idesc; /* descriptor for this handler */
struct proc *p; /* interrupt thread */
mtx_init(&ithds_table_lock, "ithread table lock", MTX_SPIN);
}
SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL);
static void
ithread_enable(int vector)
{
INTREN(1 << vector);
}
static void
ithread_disable(int vector)
{
INTRDIS(1 << vector);
}
int
inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep)
{
struct ithd *ithd; /* descriptor for the IRQ */
int errcode = 0;
int created_ithd = 0;
if (name == NULL) /* no name? */
panic ("anonymous interrupt");
if (ithd == NULL || ithd->it_ih == NULL) {
/* first handler for this irq. */
if (ithd == NULL) {
ithd = malloc(sizeof (struct ithd), M_DEVBUF,
M_WAITOK | M_ZERO);
if (ithd == NULL)
return (NULL);
ithd->irq = irq;
/*
* Work around a race where more than one CPU may be registering
* handlers on the same IRQ at the same time.
*/
mtx_lock_spin(&ithds_table_lock);
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
if (ithd == NULL) {
errcode = ithread_create(&ithd, irq, 0, ithread_disable,
ithread_enable, "irq%d:", irq);
if (errcode)
return (errcode);
mtx_lock_spin(&ithds_table_lock);
if (ithds[irq] == NULL) {
ithds[irq] = ithd;
created_ithd++;
mtx_unlock_spin(&ithds_table_lock);
} else {
struct ithd *orphan;
orphan = ithd;
ithd = ithds[irq];
mtx_unlock_spin(&ithds_table_lock);
ithread_destroy(orphan);
}
/*
* If we have a fast interrupt, we need to set the
* handler address directly. Do that below. For a
* slow interrupt, we don't need to know more details,
* so do it here because it's tidier.
*/
if ((flags & INTR_FAST) == 0) {
/*
* Only create a kernel thread if we don't already
* have one.
*/
if (ithd->it_proc == NULL) {
errcode = kthread_create(ithd_loop, NULL, &p,
RFSTOPPED | RFHIGHPID, "irq%d: %s", irq,
name);
if (errcode)
panic("inthand_add: Can't create "
"interrupt thread");
p->p_intr_nesting_level = 1;
p->p_rtprio.type = RTP_PRIO_ITHREAD;
p->p_stat = SWAIT; /* we're idle */
/* Put in linkages. */
ithd->it_proc = p;
p->p_ithd = ithd;
} else
snprintf(ithd->it_proc->p_comm, MAXCOMLEN,
"irq%d: %s", irq, name);
p->p_rtprio.prio = pri;
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
}
} else if ((flags & INTR_EXCL) != 0
|| (ithd->it_ih->ih_flags & INTR_EXCL) != 0) {
/*
* We can't append the new handler if either
* list ithd or new handler do not allow
* interrupts to be shared.
*/
if (bootverbose)
printf("\tdevice combination %s and %s "
"doesn't support shared irq%d\n",
ithd->it_ih->ih_name, name, irq);
return(NULL);
} else if (flags & INTR_FAST) {
/* We can only have one fast interrupt by itself. */
if (bootverbose)
printf("\tCan't add fast interrupt %s"
" to normal interrupt %s on irq%d",
name, ithd->it_ih->ih_name, irq);
return (NULL);
} else { /* update p_comm */
p = ithd->it_proc;
if (strlen(p->p_comm) + strlen(name) < MAXCOMLEN) {
strcat(p->p_comm, " ");
strcat(p->p_comm, name);
} else if (strlen(p->p_comm) == MAXCOMLEN)
p->p_comm[MAXCOMLEN - 1] = '+';
else
strcat(p->p_comm, "+");
}
idesc = malloc(sizeof (struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO);
if (idesc == NULL)
return (NULL);
idesc->ih_handler = handler;
idesc->ih_argument = arg;
idesc->ih_flags = flags;
idesc->ih_ithd = ithd;
errcode = ithread_add_handler(ithd, name, handler, arg,
ithread_priority(flags), flags, cookiep);
if ((flags & INTR_FAST) == 0 || errcode)
/*
* The interrupt process must be in place, but
* not necessarily schedulable, before we
* initialize the ICU, since it may cause an
* immediate interrupt.
*/
if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
panic("inthand_add: Can't initialize ICU");
idesc->ih_name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK);
if (idesc->ih_name == NULL) {
free(idesc, M_DEVBUF);
return (NULL);
}
strcpy(idesc->ih_name, name);
/* Slow interrupts got set up above. */
if ((flags & INTR_FAST)
&& (icu_setup(irq, idesc->ih_handler, idesc->ih_argument,
idesc->ih_flags) != 0) ) {
if (bootverbose)
if (errcode)
return (errcode);
if (flags & INTR_FAST) {
errcode = icu_setup(irq, handler, arg, flags);
if (errcode && bootverbose)
printf("\tinthand_add(irq%d) failed, result=%d\n",
irq, errcode);
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return NULL;
if (errcode)
return (errcode);
}
head = ithd->it_ih; /* look at chain of handlers */
if (head) {
while (head->ih_next != NULL)
head = head->ih_next; /* find the end */
head->ih_next = idesc; /* hook it in there */
} else
ithd->it_ih = idesc; /* put it up front */
update_intrname(irq, idesc->ih_name);
return (idesc);
update_intrname(irq, name);
return (0);
}
/*
@ -673,50 +637,9 @@ inthand_add(const char *name, int irq, driver_intr_t handler, void *arg,
* structure to the system. First ensure the handler is not actively
* in use.
*/
int
inthand_remove(struct intrhand *idesc)
inthand_remove(void *cookie)
{
struct ithd *ithd; /* descriptor for the IRQ */
struct intrhand *ih; /* chain of handlers */
if (idesc == NULL)
return (-1);
ithd = idesc->ih_ithd;
ih = ithd->it_ih;
if (ih == idesc) /* first in the chain */
ithd->it_ih = idesc->ih_next; /* unhook it */
else {
while ((ih != NULL)
&& (ih->ih_next != idesc) )
ih = ih->ih_next;
if (ih->ih_next != idesc)
return (-1);
ih->ih_next = ih->ih_next->ih_next;
}
if (ithd->it_ih == NULL) { /* no handlers left, */
icu_unset(ithd->irq, idesc->ih_handler);
ithds[ithd->irq] = NULL;
if ((idesc->ih_flags & INTR_FAST) == 0) {
mtx_lock_spin(&sched_lock);
if (ithd->it_proc->p_stat == SWAIT) {
ithd->it_proc->p_intr_nesting_level = 0;
ithd->it_proc->p_stat = SRUN;
setrunqueue(ithd->it_proc);
/*
* We don't do an ast here because we really
* don't care when it runs next.
*
* XXX: should we lower the threads priority?
*/
}
mtx_unlock_spin(&sched_lock);
}
}
free(idesc->ih_name, M_DEVBUF);
free(idesc, M_DEVBUF);
return (0);
return (ithread_remove_handler(cookie));
}