summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2001-02-09 17:47:44 +0000
committerjhb <jhb@FreeBSD.org>2001-02-09 17:47:44 +0000
commita0b05a52af8750d38933ae348f2f0e67135df35f (patch)
tree63226881d3381798f464e06aa971474f6cf1c5b6
parentb30904d8405e0fc49c1043759a015628e89a2a2c (diff)
downloadFreeBSD-src-a0b05a52af8750d38933ae348f2f0e67135df35f.zip
FreeBSD-src-a0b05a52af8750d38933ae348f2f0e67135df35f.tar.gz
Use the MI ithread helper functions in the x86 interrupt code.
-rw-r--r--sys/amd64/amd64/legacy.c18
-rw-r--r--sys/amd64/amd64/nexus.c18
-rw-r--r--sys/amd64/isa/intr_machdep.c243
-rw-r--r--sys/amd64/isa/intr_machdep.h11
-rw-r--r--sys/amd64/isa/ithread.c111
-rw-r--r--sys/amd64/isa/nmi.c243
-rw-r--r--sys/i386/i386/legacy.c18
-rw-r--r--sys/i386/i386/nexus.c18
-rw-r--r--sys/i386/isa/intr_machdep.c243
-rw-r--r--sys/i386/isa/intr_machdep.h11
-rw-r--r--sys/i386/isa/ithread.c111
-rw-r--r--sys/i386/isa/nmi.c243
12 files changed, 402 insertions, 886 deletions
diff --git a/sys/amd64/amd64/legacy.c b/sys/amd64/amd64/legacy.c
index 76c41ae..ce2c9cd 100644
--- a/sys/amd64/amd64/legacy.c
+++ b/sys/amd64/amd64/legacy.c
@@ -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);
}
diff --git a/sys/amd64/amd64/nexus.c b/sys/amd64/amd64/nexus.c
index 76c41ae..ce2c9cd 100644
--- a/sys/amd64/amd64/nexus.c
+++ b/sys/amd64/amd64/nexus.c
@@ -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);
}
diff --git a/sys/amd64/isa/intr_machdep.c b/sys/amd64/isa/intr_machdep.c
index 70b9378..2dd96d7 100644
--- a/sys/amd64/isa/intr_machdep.c
+++ b/sys/amd64/isa/intr_machdep.c
@@ -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 *
+static void
+ithds_init(void *dummy)
+{
+
+ 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,
- int pri, int flags)
+ enum intr_type flags, void **cookiep)
{
- 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 */
+ 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);
}
+ }
+
+ errcode = ithread_add_handler(ithd, name, handler, arg,
+ ithread_priority(flags), flags, cookiep);
+
+ if ((flags & INTR_FAST) == 0 || errcode)
/*
- * 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.
+ * The interrupt process must be in place, but
+ * not necessarily schedulable, before we
+ * initialize the ICU, since it may cause an
+ * immediate interrupt.
*/
- 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;
-
- 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);
+ if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
+ panic("inthand_add: Can't initialize ICU");
- /* 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));
}
diff --git a/sys/amd64/isa/intr_machdep.h b/sys/amd64/isa/intr_machdep.h
index 53d782f..b42c348 100644
--- a/sys/amd64/isa/intr_machdep.h
+++ b/sys/amd64/isa/intr_machdep.h
@@ -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 */
diff --git a/sys/amd64/isa/ithread.c b/sys/amd64/isa/ithread.c
index 99a1abf..8fb1924 100644
--- a/sys/amd64/isa/ithread.c
+++ b/sys/amd64/isa/ithread.c
@@ -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);
- }
-}
diff --git a/sys/amd64/isa/nmi.c b/sys/amd64/isa/nmi.c
index 70b9378..2dd96d7 100644
--- a/sys/amd64/isa/nmi.c
+++ b/sys/amd64/isa/nmi.c
@@ -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 *
+static void
+ithds_init(void *dummy)
+{
+
+ 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,
- int pri, int flags)
+ enum intr_type flags, void **cookiep)
{
- 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 */
+ 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);
}
+ }
+
+ errcode = ithread_add_handler(ithd, name, handler, arg,
+ ithread_priority(flags), flags, cookiep);
+
+ if ((flags & INTR_FAST) == 0 || errcode)
/*
- * 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.
+ * The interrupt process must be in place, but
+ * not necessarily schedulable, before we
+ * initialize the ICU, since it may cause an
+ * immediate interrupt.
*/
- 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;
-
- 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);
+ if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
+ panic("inthand_add: Can't initialize ICU");
- /* 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));
}
diff --git a/sys/i386/i386/legacy.c b/sys/i386/i386/legacy.c
index 76c41ae..ce2c9cd 100644
--- a/sys/i386/i386/legacy.c
+++ b/sys/i386/i386/legacy.c
@@ -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);
}
diff --git a/sys/i386/i386/nexus.c b/sys/i386/i386/nexus.c
index 76c41ae..ce2c9cd 100644
--- a/sys/i386/i386/nexus.c
+++ b/sys/i386/i386/nexus.c
@@ -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);
}
diff --git a/sys/i386/isa/intr_machdep.c b/sys/i386/isa/intr_machdep.c
index 70b9378..2dd96d7 100644
--- a/sys/i386/isa/intr_machdep.c
+++ b/sys/i386/isa/intr_machdep.c
@@ -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 *
+static void
+ithds_init(void *dummy)
+{
+
+ 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,
- int pri, int flags)
+ enum intr_type flags, void **cookiep)
{
- 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 */
+ 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);
}
+ }
+
+ errcode = ithread_add_handler(ithd, name, handler, arg,
+ ithread_priority(flags), flags, cookiep);
+
+ if ((flags & INTR_FAST) == 0 || errcode)
/*
- * 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.
+ * The interrupt process must be in place, but
+ * not necessarily schedulable, before we
+ * initialize the ICU, since it may cause an
+ * immediate interrupt.
*/
- 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;
-
- 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);
+ if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
+ panic("inthand_add: Can't initialize ICU");
- /* 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));
}
diff --git a/sys/i386/isa/intr_machdep.h b/sys/i386/isa/intr_machdep.h
index 53d782f..b42c348 100644
--- a/sys/i386/isa/intr_machdep.h
+++ b/sys/i386/isa/intr_machdep.h
@@ -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 */
diff --git a/sys/i386/isa/ithread.c b/sys/i386/isa/ithread.c
index 99a1abf..8fb1924 100644
--- a/sys/i386/isa/ithread.c
+++ b/sys/i386/isa/ithread.c
@@ -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);
- }
-}
diff --git a/sys/i386/isa/nmi.c b/sys/i386/isa/nmi.c
index 70b9378..2dd96d7 100644
--- a/sys/i386/isa/nmi.c
+++ b/sys/i386/isa/nmi.c
@@ -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 *
+static void
+ithds_init(void *dummy)
+{
+
+ 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,
- int pri, int flags)
+ enum intr_type flags, void **cookiep)
{
- 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 */
+ 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);
}
+ }
+
+ errcode = ithread_add_handler(ithd, name, handler, arg,
+ ithread_priority(flags), flags, cookiep);
+
+ if ((flags & INTR_FAST) == 0 || errcode)
/*
- * 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.
+ * The interrupt process must be in place, but
+ * not necessarily schedulable, before we
+ * initialize the ICU, since it may cause an
+ * immediate interrupt.
*/
- 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;
-
- 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);
+ if (icu_setup(irq, &sched_ithd, arg, flags) != 0)
+ panic("inthand_add: Can't initialize ICU");
- /* 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));
}
OpenPOWER on IntegriCloud