mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 01:30:30 -04:00
Use the MI ithread helper functions in the x86 interrupt code.
This commit is contained in:
parent
062d8ff5a0
commit
2e0c76cd20
12 changed files with 406 additions and 890 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue