Use the MI ithread helper functions in the alpha hardware interrupt code.

This commit is contained in:
John Baldwin 2001-02-09 17:53:23 +00:00
parent 5781f5419e
commit 522be16a94
9 changed files with 63 additions and 266 deletions

View File

@ -48,6 +48,7 @@
#include <sys/malloc.h>
#include <sys/interrupt.h>
#include <sys/ipl.h>
#include <sys/kernel.h>
#include <sys/kthread.h>
#include <sys/ktr.h>
#include <sys/mutex.h>
@ -82,7 +83,6 @@ void (*perf_irq)(unsigned long, struct trapframe *) = dummy_perf;
static u_int schedclk2;
static void ithd_loop(void *);
static driver_intr_t alpha_clock_interrupt;
void
@ -322,180 +322,72 @@ struct alpha_intr {
int vector; /* vector to match */
struct ithd *ithd; /* interrupt thread */
volatile long *cntp; /* interrupt counter */
void (*disable)(int); /* disable source */
void (*enable)(int); /* enable source */
};
static struct mtx alpha_intr_hash_lock;
static struct alpha_intr_list alpha_intr_hash[31];
static void ithds_init(void *dummy);
static void
ithds_init(void *dummy)
{
mtx_init(&alpha_intr_hash_lock, "ithread table lock", MTX_SPIN);
}
SYSINIT(ithds_init, SI_SUB_INTR, SI_ORDER_SECOND, ithds_init, NULL);
int
alpha_setup_intr(const char *name, int vector, driver_intr_t *handler,
void *arg, int pri, int flags, void **cookiep,
volatile long *cntp, void (*disable)(int), void (*enable)(int))
alpha_setup_intr(const char *name, int vector, driver_intr_t handler, void *arg,
enum intr_type flags, void **cookiep, volatile long *cntp,
void (*disable)(int), void (*enable)(int))
{
int h = HASHVEC(vector);
struct alpha_intr *i;
struct intrhand *head, *idesc;
struct ithd *ithd;
struct proc *p;
int s, errcode;
int errcode;
/*
* XXX - Can we have more than one device on a vector? If so, we have
* a race condition here that needs to be worked around similar to
* the fashion done in the i386 inthand_add() function.
*/
/* First, check for an existing hash table entry for this vector. */
mtx_lock_spin(&alpha_intr_hash_lock);
for (i = LIST_FIRST(&alpha_intr_hash[h]); i && i->vector != vector;
i = LIST_NEXT(i, list))
; /* nothing */
mtx_unlock_spin(&alpha_intr_hash_lock);
if (i == NULL) {
/* None was found, so create an entry. */
i = malloc(sizeof(struct alpha_intr), M_DEVBUF, M_NOWAIT);
if (i == NULL)
return ENOMEM;
i->vector = vector;
i->ithd = NULL;
i->cntp = cntp;
i->disable = disable;
i->enable = enable;
errcode = ithread_create(&i->ithd, vector, 0, disable, enable,
"intr:");
if (errcode) {
free(i, M_DEVBUF);
return errcode;
}
s = save_intr();
disable_intr();
mtx_lock_spin(&alpha_intr_hash_lock);
LIST_INSERT_HEAD(&alpha_intr_hash[h], i, list);
restore_intr(s);
mtx_unlock_spin(&alpha_intr_hash_lock);
}
/* Second, create the interrupt thread if needed. */
ithd = i->ithd;
if (ithd == NULL || ithd->it_ih == NULL) {
/* first handler for this vector */
if (ithd == NULL) {
ithd = malloc(sizeof(struct ithd), M_DEVBUF,
M_WAITOK | M_ZERO);
if (ithd == NULL)
return ENOMEM;
ithd->irq = vector;
ithd->it_md = i;
i->ithd = ithd;
}
/* Create a kernel thread if needed. */
if ((flags & INTR_FAST) == 0) {
if (ithd->it_proc == NULL) {
errcode = kthread_create(ithd_loop, NULL, &p,
RFSTOPPED | RFHIGHPID, "intr: %s", name);
if (errcode)
panic(
"alpha_setup_intr: Can't create interrupt thread");
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,
"intr: %s", name);
p->p_rtprio.prio = pri;
}
} else if ((flags & INTR_EXCL) != 0 ||
(ithd->it_ih->ih_flags & INTR_EXCL) != 0) {
/*
* We can't have more than one exclusive handler for a given
* interrupt.
*/
if (bootverbose)
printf(
"\tdevice combination %s and %s doesn't support shared vector %x\n",
ithd->it_ih->ih_name, name, vector);
return EINVAL;
} else if ((flags & INTR_FAST) != 0) {
/* We can only have one fast interrupt by itself. */
if (bootverbose)
printf(
"\tCan't add fast interrupt %s to normal interrupt %s on vector %x\n",
name, ithd->it_ih->ih_name, vector);
return EINVAL;
} else if (ithd->it_proc == NULL) {
if (bootverbose)
printf(
"\tCan't add normal interrupt %s to fast interrupt %s on vector %x\n",
name, ithd->it_ih->ih_name, vector);
return EINVAL;
} else {
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, "+");
}
/* Third, setup the interrupt descriptor for this handler. */
idesc = malloc(sizeof (struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO);
if (idesc == NULL)
return ENOMEM;
idesc->ih_handler = handler;
idesc->ih_argument = arg;
idesc->ih_flags = flags;
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);
/* Fourth, add our handler to the end of the ithread's handler list. */
head = ithd->it_ih;
if (head) {
while (head->ih_next != NULL)
head = head->ih_next;
head->ih_next = idesc;
} else
ithd->it_ih = idesc;
*cookiep = idesc;
return 0;
/* Second, add this handler. */
return (ithread_add_handler(i->ithd, name, handler, arg,
ithread_priority(flags), flags, cookiep));
}
int
alpha_teardown_intr(void *cookie)
{
struct intrhand *idesc = cookie;
struct ithd *ithd;
struct intrhand *head;
#if 0
struct alpha_intr *i;
int s;
#endif
/* First, detach ourself from our interrupt thread. */
ithd = idesc->ih_ithd;
KASSERT(ithd != NULL, ("idesc without an interrupt thread"));
head = ithd->it_ih;
if (head == idesc)
ithd->it_ih = idesc->ih_next;
else {
while (head != NULL && head->ih_next != idesc)
head = head->ih_next;
if (head == NULL)
return (-1); /* couldn't find ourself */
head->ih_next = idesc->ih_next;
}
free(idesc, M_DEVBUF);
/* XXX - if the ithd has no handlers left, we should remove it */
#if 0
s = save_intr();
disable_intr();
LIST_REMOVE(i, list);
restore_intr(s);
free(i, M_DEVBUF);
#endif
return 0;
return (ithread_remove_handler(cookie));
}
void
@ -504,7 +396,7 @@ alpha_dispatch_intr(void *frame, unsigned long vector)
int h = HASHVEC(vector);
struct alpha_intr *i;
struct ithd *ithd; /* our interrupt thread */
int saveintr;
struct intrhand *ih;
/*
* Walk the hash bucket for this vector looking for this vector's
@ -520,10 +412,10 @@ alpha_dispatch_intr(void *frame, unsigned long vector)
KASSERT(ithd != NULL, ("interrupt vector without a thread"));
/*
* As an optomization until we have kthread_cancel(), if an ithread
* has no handlers, don't schedule it to run.
* As an optomization, if an ithread has no handlers, don't
* schedule it to run.
*/
if (ithd->it_ih == NULL)
if (TAILQ_EMPTY(&ithd->it_handlers))
return;
atomic_add_long(i->cntp, 1);
@ -533,18 +425,13 @@ alpha_dispatch_intr(void *frame, unsigned long vector)
* interrupt by calling the handler directly without Giant. Note
* that this means that any fast interrupt handler must be MP safe.
*/
if (ithd->it_proc == NULL) {
KASSERT((ithd->it_ih->ih_flags & INTR_FAST) != 0,
("threaded interrupt without a thread"));
KASSERT(ithd->it_ih->ih_next == NULL,
("fast interrupt with more than one handler"));
ithd->it_ih->ih_handler(ithd->it_ih->ih_argument);
ih = TAILQ_FIRST(&ithd->it_handlers);
if ((ih->ih_flags & INTR_FAST) != 0) {
ih->ih_handler(ih->ih_argument);
return;
}
CTR3(KTR_INTR, "sched_ithd pid %d(%s) need=%d",
CTR3(KTR_INTR, "alpha_dispatch_intr: pid %d(%s) need=%d",
ithd->it_proc->p_pid, ithd->it_proc->p_comm, ithd->it_need);
/*
@ -555,10 +442,10 @@ alpha_dispatch_intr(void *frame, unsigned long vector)
* is higher priority than their current thread, it gets run now.
*/
ithd->it_need = 1;
if (i->disable) {
if (ithd->it_disable) {
CTR1(KTR_INTR,
"alpha_dispatch_intr: disabling vector 0x%x", i->vector);
i->disable(i->vector);
ithd->it_disable(ithd->it_vector);
}
mtx_lock_spin(&sched_lock);
if (ithd->it_proc->p_stat == SWAIT) {
@ -566,98 +453,16 @@ alpha_dispatch_intr(void *frame, unsigned long vector)
CTR1(KTR_INTR, "alpha_dispatch_intr: setrunqueue %d",
ithd->it_proc->p_pid);
alpha_mb(); /* XXX - ??? */
alpha_mb(); /* XXX - this is bogus, mtx_lock_spin has a barrier */
ithd->it_proc->p_stat = SRUN;
setrunqueue(ithd->it_proc);
#ifdef PREEMPTION
/* Does not work on 4100 and PC164 */
if (!cold) {
saveintr = sched_lock.mtx_saveintr;
sched_lock.mtx_saveintr = ALPHA_PSL_IPL_0;
if (curproc != PCPU_GET(idleproc))
setrunqueue(curproc);
mi_switch();
sched_lock.mtx_saveintr = saveintr;
}
#else
need_resched();
#endif
} else {
CTR3(KTR_INTR, "alpha_dispatch_intr: %d: it_need %d, state %d",
ithd->it_proc->p_pid, ithd->it_need, ithd->it_proc->p_stat);
need_resched();
}
mtx_unlock_spin(&sched_lock);
}
void
ithd_loop(void *dummy)
{
struct ithd *ithd; /* our thread context */
struct intrhand *ih; /* list of handlers */
struct alpha_intr *i; /* interrupt source */
ithd = curproc->p_ithd;
i = ithd->it_md;
/*
* As long as we have interrupts outstanding, go through the
* list of handlers, giving each one a go at it.
*/
for (;;) {
CTR3(KTR_INTR, "ithd_loop pid %d(%s) need=%d",
ithd->it_proc->p_pid, ithd->it_proc->p_comm, ithd->it_need);
while (ithd->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.
*/
ithd->it_need = 0;
alpha_wmb(); /* push out "it_need=0" */
for (ih = ithd->it_ih; ih != NULL; ih = ih->ih_next) {
CTR5(KTR_INTR,
"ithd_loop pid %d ih=%p: %p(%p) flg=%x",
ithd->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);
}
/*
* Reenable the source to give it a chance to
* set it_need again.
*/
if (i->enable)
i->enable(i->vector);
}
/*
* 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 (!ithd->it_need) {
ithd->it_proc->p_stat = SWAIT; /* we're idle */
CTR1(KTR_INTR, "ithd_loop pid %d: done",
ithd->it_proc->p_pid);
mi_switch();
CTR1(KTR_INTR, "ithd_loop pid %d: resumed",
ithd->it_proc->p_pid);
}
mtx_unlock_spin(&sched_lock);
}
}
static void
alpha_clock_interrupt(void *framep)

View File

@ -29,11 +29,10 @@
#ifndef _MACHINE_INTR_H_
#define _MACHINE_INTR_H_
int alpha_setup_intr(const char *name, int vector,
driver_intr_t *handle, void *arg, int pri, int flags,
void **cookiep, volatile long *cntp,
void (*disable)(int), void (*enable)(int));
int alpha_teardown_intr(void *cookie);
void alpha_dispatch_intr(void *frame, unsigned long vector);
int alpha_setup_intr(const char *name, int vector, driver_intr_t handler,
void *arg, enum intr_type flags, void **cookiep,
volatile long *cntp, void (*disable)(int), void (*enable)(int));
int alpha_teardown_intr(void *cookie);
void alpha_dispatch_intr(void *frame, unsigned long vector);
#endif /* !_MACHINE_INTR_H_ */

View File

@ -353,8 +353,7 @@ isa_setup_intr(device_t dev, device_t child,
device_get_nameunit(child ? child : dev),
0x800 + (irq->r_start << 4),
((flags & INTR_FAST) ? isa_handle_fast_intr :
isa_handle_intr), ii,
ithread_priority(flags), flags, &ii->ih,
isa_handle_intr), ii, flags, &ii->ih,
&intrcnt[INTRCNT_ISA_IRQ + irq->r_start],
isa_disable_intr, isa_enable_intr);
if (error) {

View File

@ -345,7 +345,7 @@ mcpcia_setup_intr(device_t dev, device_t child, struct resource *ir, int flags,
driver_intr_t *intr, void *arg, void **cp)
{
struct mcpcia_softc *sc = MCPCIA_SOFTC(dev);
int slot, mid, gid, birq, irq, error, intpin, h, pri;
int slot, mid, gid, birq, irq, error, intpin, h;
intpin = pci_get_intpin(child);
if (intpin == 0) {
@ -394,9 +394,8 @@ mcpcia_setup_intr(device_t dev, device_t child, struct resource *ir, int flags,
((intpin - 1) * MCPCIA_VECWIDTH_PER_INTPIN);
}
birq = irq + INTRCNT_KN300_IRQ;
pri = ithread_priority(flags);
error = alpha_setup_intr(device_get_nameunit(child ? child : dev), h,
intr, arg, pri, flags, cp, &intrcnt[birq],
intr, arg, flags, cp, &intrcnt[birq],
mcpcia_disable_intr_vec, mcpcia_enable_intr_vec);
if (error)
return error;

View File

@ -370,8 +370,7 @@ apecs_setup_intr(device_t dev, device_t child,
return error;
error = alpha_setup_intr(device_get_nameunit(child ? child : dev),
0x900 + (irq->r_start << 4), intr, arg,
ithread_priority(flags), flags, cookiep,
0x900 + (irq->r_start << 4), intr, arg, flags, cookiep,
&intrcnt[INTRCNT_EB64PLUS_IRQ + irq->r_start],
apecs_disable_intr, apecs_enable_intr);
if (error)

View File

@ -542,8 +542,7 @@ cia_setup_intr(device_t dev, device_t child,
error = alpha_setup_intr(
device_get_nameunit(child ? child : dev),
0x900 + (irq->r_start << 4), intr, arg,
ithread_priority(flags), flags, cookiep,
0x900 + (irq->r_start << 4), intr, arg, flags, cookiep,
&intrcnt[INTRCNT_EB164_IRQ + irq->r_start],
cia_disable_intr, cia_enable_intr);
if (error)

View File

@ -666,9 +666,8 @@ t2_setup_intr(device_t dev, device_t child,
return error;
error = alpha_setup_intr(device_get_nameunit(child ? child : dev),
vector, intr, arg, ithread_priority(flags), flags,
cookiep, &intrcnt[irq->r_start],
t2_disable_vec, t2_enable_vec);
vector, intr, arg, flags, cookiep,
&intrcnt[irq->r_start], t2_disable_vec, t2_enable_vec);
if (error)
return error;

View File

@ -330,8 +330,7 @@ tsunami_setup_intr(device_t dev, device_t child,
return error;
error = alpha_setup_intr(device_get_nameunit(child ? child : dev),
0x900 + (irq->r_start << 4), intr, arg,
ithread_priority(flags), flags, cookiep,
0x900 + (irq->r_start << 4), intr, arg, flags, cookiep,
&intrcnt[INTRCNT_EB164_IRQ + irq->r_start],
tsunami_disable_intr_vec, tsunami_enable_intr_vec);
if (error)

View File

@ -379,7 +379,7 @@ dwlpx_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
driver_intr_t *intr, void *arg, void **cookiep)
{
struct dwlpx_softc *sc = DWLPX_SOFTC(dev);
int slot, ionode, hose, error, vector, intpin, pri;
int slot, ionode, hose, error, vector, intpin;
error = rman_activate_resource(irq);
if (error)
@ -391,9 +391,8 @@ dwlpx_setup_intr(device_t dev, device_t child, struct resource *irq, int flags,
hose = sc->bushose & 0x3;
vector = DWLPX_MVEC(ionode, hose, slot);
pri = ithread_priority(flags);
error = alpha_setup_intr(device_get_nameunit(child ? child : dev),
vector, intr, arg, pri, flags, cookiep,
vector, intr, arg, flags, cookiep,
&intrcnt[INTRCNT_KN8AE_IRQ], NULL, NULL);
if (error)
return error;