mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-28 08:02:54 +00:00
Yank crufty INTR_FILTER option
It was introduced to the tree in r169320 and r169321 in May 2007. It never got much use and never became a kernel default. The code duplicates the default path quite a bit, with slight modifications. Just yank out the cruft. Whatever goals were being aimed for can probably be met within the existing framework, without a flag day option. Mostly mechanical change: 'unifdef -m -UINTR_FILTER'. Reviewed by: mmacy Sponsored by: Dell EMC Isilon Differential Revision: https://reviews.freebsd.org/D15546
This commit is contained in:
parent
810c4dcddf
commit
a0638b33f7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=334170
@ -52,7 +52,6 @@ options CD9660 # ISO 9660 Filesystem
|
||||
options PSEUDOFS # Pseudo-filesystem framework
|
||||
options SCSI_DELAY=5000 # Delay (in ms) before probing SCSI
|
||||
options KTRACE # ktrace(1) support
|
||||
options INTR_FILTER
|
||||
options SYSVSHM # SYSV-style shared memory
|
||||
options SYSVMSG # SYSV-style message queues
|
||||
options SYSVSEM # SYSV-style semaphores
|
||||
|
@ -904,9 +904,6 @@ HWPMC_DEBUG opt_global.h
|
||||
HWPMC_HOOKS
|
||||
HWPMC_MIPS_BACKTRACE opt_hwpmc_hooks.h
|
||||
|
||||
# Interrupt filtering
|
||||
INTR_FILTER
|
||||
|
||||
# 802.11 support layer
|
||||
IEEE80211_DEBUG opt_wlan.h
|
||||
IEEE80211_DEBUG_REFCNT opt_wlan.h
|
||||
|
@ -57,8 +57,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include <dev/asmc/asmcvar.h>
|
||||
|
||||
#include "opt_intr_filter.h"
|
||||
|
||||
/*
|
||||
* Device interface.
|
||||
*/
|
||||
@ -85,9 +83,6 @@ static int asmc_temp_getvalue(device_t dev, const char *key);
|
||||
static int asmc_sms_read(device_t, const char *key, int16_t *val);
|
||||
static void asmc_sms_calibrate(device_t dev);
|
||||
static int asmc_sms_intrfast(void *arg);
|
||||
#ifdef INTR_FILTER
|
||||
static void asmc_sms_handler(void *arg);
|
||||
#endif
|
||||
static void asmc_sms_printintr(device_t dev, uint8_t);
|
||||
static void asmc_sms_task(void *arg, int pending);
|
||||
#ifdef DEBUG
|
||||
@ -563,13 +558,11 @@ asmc_attach(device_t dev)
|
||||
* We only need to do this for the non INTR_FILTER case.
|
||||
*/
|
||||
sc->sc_sms_tq = NULL;
|
||||
#ifndef INTR_FILTER
|
||||
TASK_INIT(&sc->sc_sms_task, 0, asmc_sms_task, sc);
|
||||
sc->sc_sms_tq = taskqueue_create_fast("asmc_taskq", M_WAITOK,
|
||||
taskqueue_thread_enqueue, &sc->sc_sms_tq);
|
||||
taskqueue_start_threads(&sc->sc_sms_tq, 1, PI_REALTIME, "%s sms taskq",
|
||||
device_get_nameunit(dev));
|
||||
#endif
|
||||
/*
|
||||
* Allocate an IRQ for the SMS.
|
||||
*/
|
||||
@ -584,11 +577,7 @@ asmc_attach(device_t dev)
|
||||
|
||||
ret = bus_setup_intr(dev, sc->sc_irq,
|
||||
INTR_TYPE_MISC | INTR_MPSAFE,
|
||||
#ifdef INTR_FILTER
|
||||
asmc_sms_intrfast, asmc_sms_handler,
|
||||
#else
|
||||
asmc_sms_intrfast, NULL,
|
||||
#endif
|
||||
dev, &sc->sc_cookie);
|
||||
|
||||
if (ret) {
|
||||
@ -1241,23 +1230,10 @@ asmc_sms_intrfast(void *arg)
|
||||
sc->sc_sms_intrtype = type;
|
||||
asmc_sms_printintr(dev, type);
|
||||
|
||||
#ifdef INTR_FILTER
|
||||
return (FILTER_SCHEDULE_THREAD | FILTER_HANDLED);
|
||||
#else
|
||||
taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task);
|
||||
#endif
|
||||
return (FILTER_HANDLED);
|
||||
}
|
||||
|
||||
#ifdef INTR_FILTER
|
||||
static void
|
||||
asmc_sms_handler(void *arg)
|
||||
{
|
||||
struct asmc_softc *sc = device_get_softc(arg);
|
||||
|
||||
asmc_sms_task(sc, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
|
@ -101,24 +101,11 @@ static struct mtx event_lock;
|
||||
MTX_SYSINIT(intr_event_list, &event_lock, "intr event list", MTX_DEF);
|
||||
|
||||
static void intr_event_update(struct intr_event *ie);
|
||||
#ifdef INTR_FILTER
|
||||
static int intr_event_schedule_thread(struct intr_event *ie,
|
||||
struct intr_thread *ithd);
|
||||
static int intr_filter_loop(struct intr_event *ie,
|
||||
struct trapframe *frame, struct intr_thread **ithd);
|
||||
static struct intr_thread *ithread_create(const char *name,
|
||||
struct intr_handler *ih);
|
||||
#else
|
||||
static int intr_event_schedule_thread(struct intr_event *ie);
|
||||
static struct intr_thread *ithread_create(const char *name);
|
||||
#endif
|
||||
static void ithread_destroy(struct intr_thread *ithread);
|
||||
static void ithread_execute_handlers(struct proc *p,
|
||||
struct intr_event *ie);
|
||||
#ifdef INTR_FILTER
|
||||
static void priv_ithread_execute_handler(struct proc *p,
|
||||
struct intr_handler *ih);
|
||||
#endif
|
||||
static void ithread_loop(void *);
|
||||
static void ithread_update(struct intr_thread *ithd);
|
||||
static void start_softintr(void *);
|
||||
@ -506,7 +493,6 @@ intr_event_destroy(struct intr_event *ie)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifndef INTR_FILTER
|
||||
static struct intr_thread *
|
||||
ithread_create(const char *name)
|
||||
{
|
||||
@ -530,31 +516,6 @@ ithread_create(const char *name)
|
||||
CTR2(KTR_INTR, "%s: created %s", __func__, name);
|
||||
return (ithd);
|
||||
}
|
||||
#else
|
||||
static struct intr_thread *
|
||||
ithread_create(const char *name, struct intr_handler *ih)
|
||||
{
|
||||
struct intr_thread *ithd;
|
||||
struct thread *td;
|
||||
int error;
|
||||
|
||||
ithd = malloc(sizeof(struct intr_thread), M_ITHREAD, M_WAITOK | M_ZERO);
|
||||
|
||||
error = kproc_kthread_add(ithread_loop, ih, &intrproc,
|
||||
&td, RFSTOPPED | RFHIGHPID,
|
||||
0, "intr", "%s", name);
|
||||
if (error)
|
||||
panic("kproc_create() failed with %d", error);
|
||||
thread_lock(td);
|
||||
sched_class(td, PRI_ITHD);
|
||||
TD_SET_IWAIT(td);
|
||||
thread_unlock(td);
|
||||
td->td_pflags |= TDP_ITHREAD;
|
||||
ithd->it_thread = td;
|
||||
CTR2(KTR_INTR, "%s: created %s", __func__, name);
|
||||
return (ithd);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
ithread_destroy(struct intr_thread *ithread)
|
||||
@ -572,7 +533,6 @@ ithread_destroy(struct intr_thread *ithread)
|
||||
thread_unlock(td);
|
||||
}
|
||||
|
||||
#ifndef INTR_FILTER
|
||||
int
|
||||
intr_event_add_handler(struct intr_event *ie, const char *name,
|
||||
driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri,
|
||||
@ -646,90 +606,6 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
|
||||
*cookiep = ih;
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
int
|
||||
intr_event_add_handler(struct intr_event *ie, const char *name,
|
||||
driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri,
|
||||
enum intr_type flags, void **cookiep)
|
||||
{
|
||||
struct intr_handler *ih, *temp_ih;
|
||||
struct intr_thread *it;
|
||||
|
||||
if (ie == NULL || name == NULL || (handler == NULL && filter == NULL))
|
||||
return (EINVAL);
|
||||
|
||||
/* Allocate and populate an interrupt handler structure. */
|
||||
ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO);
|
||||
ih->ih_filter = filter;
|
||||
ih->ih_handler = handler;
|
||||
ih->ih_argument = arg;
|
||||
strlcpy(ih->ih_name, name, sizeof(ih->ih_name));
|
||||
ih->ih_event = ie;
|
||||
ih->ih_pri = pri;
|
||||
if (flags & INTR_EXCL)
|
||||
ih->ih_flags = IH_EXCLUSIVE;
|
||||
if (flags & INTR_MPSAFE)
|
||||
ih->ih_flags |= IH_MPSAFE;
|
||||
if (flags & INTR_ENTROPY)
|
||||
ih->ih_flags |= IH_ENTROPY;
|
||||
|
||||
/* We can only have one exclusive handler in a event. */
|
||||
mtx_lock(&ie->ie_lock);
|
||||
if (!TAILQ_EMPTY(&ie->ie_handlers)) {
|
||||
if ((flags & INTR_EXCL) ||
|
||||
(TAILQ_FIRST(&ie->ie_handlers)->ih_flags & IH_EXCLUSIVE)) {
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
free(ih, M_ITHREAD);
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* For filtered handlers, create a private ithread to run on. */
|
||||
if (filter != NULL && handler != NULL) {
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
it = ithread_create("intr: newborn", ih);
|
||||
mtx_lock(&ie->ie_lock);
|
||||
it->it_event = ie;
|
||||
ih->ih_thread = it;
|
||||
ithread_update(it); /* XXX - do we really need this?!?!? */
|
||||
} else { /* Create the global per-event thread if we need one. */
|
||||
while (ie->ie_thread == NULL && handler != NULL) {
|
||||
if (ie->ie_flags & IE_ADDING_THREAD)
|
||||
msleep(ie, &ie->ie_lock, 0, "ithread", 0);
|
||||
else {
|
||||
ie->ie_flags |= IE_ADDING_THREAD;
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
it = ithread_create("intr: newborn", ih);
|
||||
mtx_lock(&ie->ie_lock);
|
||||
ie->ie_flags &= ~IE_ADDING_THREAD;
|
||||
ie->ie_thread = it;
|
||||
it->it_event = ie;
|
||||
ithread_update(it);
|
||||
wakeup(ie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the new handler to the event in priority order. */
|
||||
TAILQ_FOREACH(temp_ih, &ie->ie_handlers, ih_next) {
|
||||
if (temp_ih->ih_pri > ih->ih_pri)
|
||||
break;
|
||||
}
|
||||
if (temp_ih == NULL)
|
||||
TAILQ_INSERT_TAIL(&ie->ie_handlers, ih, ih_next);
|
||||
else
|
||||
TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
|
||||
intr_event_update(ie);
|
||||
|
||||
CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name,
|
||||
ie->ie_name);
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
|
||||
if (cookiep != NULL)
|
||||
*cookiep = ih;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Append a description preceded by a ':' to the name of the specified
|
||||
@ -846,7 +722,6 @@ _intr_drain(int irq)
|
||||
}
|
||||
|
||||
|
||||
#ifndef INTR_FILTER
|
||||
int
|
||||
intr_event_remove_handler(void *cookie)
|
||||
{
|
||||
@ -997,168 +872,6 @@ intr_event_schedule_thread(struct intr_event *ie)
|
||||
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
int
|
||||
intr_event_remove_handler(void *cookie)
|
||||
{
|
||||
struct intr_handler *handler = (struct intr_handler *)cookie;
|
||||
struct intr_event *ie;
|
||||
struct intr_thread *it;
|
||||
#ifdef INVARIANTS
|
||||
struct intr_handler *ih;
|
||||
#endif
|
||||
#ifdef notyet
|
||||
int dead;
|
||||
#endif
|
||||
|
||||
if (handler == NULL)
|
||||
return (EINVAL);
|
||||
ie = handler->ih_event;
|
||||
KASSERT(ie != NULL,
|
||||
("interrupt handler \"%s\" has a NULL interrupt event",
|
||||
handler->ih_name));
|
||||
mtx_lock(&ie->ie_lock);
|
||||
CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name,
|
||||
ie->ie_name);
|
||||
#ifdef INVARIANTS
|
||||
TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next)
|
||||
if (ih == handler)
|
||||
goto ok;
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
panic("interrupt handler \"%s\" not found in interrupt event \"%s\"",
|
||||
ih->ih_name, ie->ie_name);
|
||||
ok:
|
||||
#endif
|
||||
/*
|
||||
* If there are no ithreads (per event and per handler), then
|
||||
* just remove the handler and return.
|
||||
* XXX: Note that an INTR_FAST handler might be running on another CPU!
|
||||
*/
|
||||
if (ie->ie_thread == NULL && handler->ih_thread == NULL) {
|
||||
TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
free(handler, M_ITHREAD);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Private or global ithread? */
|
||||
it = (handler->ih_thread) ? handler->ih_thread : ie->ie_thread;
|
||||
/*
|
||||
* If the interrupt thread is already running, then just mark this
|
||||
* handler as being dead and let the ithread do the actual removal.
|
||||
*
|
||||
* During a cold boot while cold is set, msleep() does not sleep,
|
||||
* so we have to remove the handler here rather than letting the
|
||||
* thread do it.
|
||||
*/
|
||||
thread_lock(it->it_thread);
|
||||
if (!TD_AWAITING_INTR(it->it_thread) && !cold) {
|
||||
handler->ih_flags |= IH_DEAD;
|
||||
|
||||
/*
|
||||
* Ensure that the thread will process the handler list
|
||||
* again and remove this handler if it has already passed
|
||||
* it on the list.
|
||||
*
|
||||
* The release part of the following store ensures
|
||||
* that the update of ih_flags is ordered before the
|
||||
* it_need setting. See the comment before
|
||||
* atomic_cmpset_acq(&ithd->it_need, ...) operation in
|
||||
* the ithread_execute_handlers().
|
||||
*/
|
||||
atomic_store_rel_int(&it->it_need, 1);
|
||||
} else
|
||||
TAILQ_REMOVE(&ie->ie_handlers, handler, ih_next);
|
||||
thread_unlock(it->it_thread);
|
||||
while (handler->ih_flags & IH_DEAD)
|
||||
msleep(handler, &ie->ie_lock, 0, "iev_rmh", 0);
|
||||
/*
|
||||
* At this point, the handler has been disconnected from the event,
|
||||
* so we can kill the private ithread if any.
|
||||
*/
|
||||
if (handler->ih_thread) {
|
||||
ithread_destroy(handler->ih_thread);
|
||||
handler->ih_thread = NULL;
|
||||
}
|
||||
intr_event_update(ie);
|
||||
#ifdef notyet
|
||||
/*
|
||||
* XXX: This could be bad in the case of ppbus(8). Also, I think
|
||||
* this could lead to races of stale data when servicing an
|
||||
* interrupt.
|
||||
*/
|
||||
dead = 1;
|
||||
TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
|
||||
if (handler != NULL) {
|
||||
dead = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (dead) {
|
||||
ithread_destroy(ie->ie_thread);
|
||||
ie->ie_thread = NULL;
|
||||
}
|
||||
#endif
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
free(handler, M_ITHREAD);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
intr_event_schedule_thread(struct intr_event *ie, struct intr_thread *it)
|
||||
{
|
||||
struct intr_entropy entropy;
|
||||
struct thread *td;
|
||||
struct thread *ctd;
|
||||
struct proc *p;
|
||||
|
||||
/*
|
||||
* If no ithread or no handlers, then we have a stray interrupt.
|
||||
*/
|
||||
if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers) || it == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
ctd = curthread;
|
||||
td = it->it_thread;
|
||||
p = td->td_proc;
|
||||
|
||||
/*
|
||||
* If any of the handlers for this ithread claim to be good
|
||||
* sources of entropy, then gather some.
|
||||
*/
|
||||
if (ie->ie_flags & IE_ENTROPY) {
|
||||
entropy.event = (uintptr_t)ie;
|
||||
entropy.td = ctd;
|
||||
random_harvest_queue(&entropy, sizeof(entropy), 2, RANDOM_INTERRUPT);
|
||||
}
|
||||
|
||||
KASSERT(p != NULL, ("ithread %s has no process", ie->ie_name));
|
||||
|
||||
/*
|
||||
* Set it_need to tell the thread to keep running if it is already
|
||||
* running. Then, lock the thread and see if we actually need to
|
||||
* put it on the runqueue.
|
||||
*
|
||||
* Use store_rel to arrange that the store to ih_need in
|
||||
* swi_sched() is before the store to it_need and prepare for
|
||||
* transfer of this order to loads in the ithread.
|
||||
*/
|
||||
atomic_store_rel_int(&it->it_need, 1);
|
||||
thread_lock(td);
|
||||
if (TD_AWAITING_INTR(td)) {
|
||||
CTR3(KTR_INTR, "%s: schedule pid %d (%s)", __func__, p->p_pid,
|
||||
td->td_name);
|
||||
TD_CLR_IWAIT(td);
|
||||
sched_add(td, SRQ_INTR);
|
||||
} else {
|
||||
CTR5(KTR_INTR, "%s: pid %d (%s): it_need %d, state %d",
|
||||
__func__, p->p_pid, td->td_name, it->it_need, td->td_state);
|
||||
}
|
||||
thread_unlock(td);
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allow interrupt event binding for software interrupt handlers -- a no-op,
|
||||
@ -1231,11 +944,7 @@ swi_sched(void *cookie, int flags)
|
||||
|
||||
if (!(flags & SWI_DELAY)) {
|
||||
VM_CNT_INC(v_soft);
|
||||
#ifdef INTR_FILTER
|
||||
error = intr_event_schedule_thread(ie, ie->ie_thread);
|
||||
#else
|
||||
error = intr_event_schedule_thread(ie);
|
||||
#endif
|
||||
KASSERT(error == 0, ("stray software interrupt"));
|
||||
}
|
||||
}
|
||||
@ -1253,38 +962,6 @@ swi_remove(void *cookie)
|
||||
return (intr_event_remove_handler(cookie));
|
||||
}
|
||||
|
||||
#ifdef INTR_FILTER
|
||||
static void
|
||||
priv_ithread_execute_handler(struct proc *p, struct intr_handler *ih)
|
||||
{
|
||||
struct intr_event *ie;
|
||||
|
||||
ie = ih->ih_event;
|
||||
/*
|
||||
* If this handler is marked for death, remove it from
|
||||
* the list of handlers and wake up the sleeper.
|
||||
*/
|
||||
if (ih->ih_flags & IH_DEAD) {
|
||||
mtx_lock(&ie->ie_lock);
|
||||
TAILQ_REMOVE(&ie->ie_handlers, ih, ih_next);
|
||||
ih->ih_flags &= ~IH_DEAD;
|
||||
wakeup(ih);
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Execute this handler. */
|
||||
CTR6(KTR_INTR, "%s: pid %d exec %p(%p) for %s flg=%x",
|
||||
__func__, p->p_pid, (void *)ih->ih_handler, ih->ih_argument,
|
||||
ih->ih_name, ih->ih_flags);
|
||||
|
||||
if (!(ih->ih_flags & IH_MPSAFE))
|
||||
mtx_lock(&Giant);
|
||||
ih->ih_handler(ih->ih_argument);
|
||||
if (!(ih->ih_flags & IH_MPSAFE))
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is a public function for use by drivers that mux interrupt
|
||||
@ -1380,7 +1057,6 @@ ithread_execute_handlers(struct proc *p, struct intr_event *ie)
|
||||
ie->ie_post_ithread(ie->ie_source);
|
||||
}
|
||||
|
||||
#ifndef INTR_FILTER
|
||||
/*
|
||||
* This is the main code for interrupt threads.
|
||||
*/
|
||||
@ -1554,222 +1230,6 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame)
|
||||
td->td_intr_nesting_level--;
|
||||
return (0);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* This is the main code for interrupt threads.
|
||||
*/
|
||||
static void
|
||||
ithread_loop(void *arg)
|
||||
{
|
||||
struct intr_thread *ithd;
|
||||
struct intr_handler *ih;
|
||||
struct intr_event *ie;
|
||||
struct thread *td;
|
||||
struct proc *p;
|
||||
int priv;
|
||||
int wake;
|
||||
|
||||
td = curthread;
|
||||
p = td->td_proc;
|
||||
ih = (struct intr_handler *)arg;
|
||||
priv = (ih->ih_thread != NULL) ? 1 : 0;
|
||||
ithd = (priv) ? ih->ih_thread : ih->ih_event->ie_thread;
|
||||
KASSERT(ithd->it_thread == td,
|
||||
("%s: ithread and proc linkage out of sync", __func__));
|
||||
ie = ithd->it_event;
|
||||
ie->ie_count = 0;
|
||||
wake = 0;
|
||||
|
||||
/*
|
||||
* As long as we have interrupts outstanding, go through the
|
||||
* list of handlers, giving each one a go at it.
|
||||
*/
|
||||
for (;;) {
|
||||
/*
|
||||
* If we are an orphaned thread, then just die.
|
||||
*/
|
||||
if (ithd->it_flags & IT_DEAD) {
|
||||
CTR3(KTR_INTR, "%s: pid %d (%s) exiting", __func__,
|
||||
p->p_pid, td->td_name);
|
||||
free(ithd, M_ITHREAD);
|
||||
kthread_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Service interrupts. If another interrupt arrives while
|
||||
* we are running, it will set it_need to note that we
|
||||
* should make another pass.
|
||||
*
|
||||
* The load_acq part of the following cmpset ensures
|
||||
* that the load of ih_need in ithread_execute_handlers()
|
||||
* is ordered after the load of it_need here.
|
||||
*/
|
||||
while (atomic_cmpset_acq_int(&ithd->it_need, 1, 0) != 0) {
|
||||
if (priv)
|
||||
priv_ithread_execute_handler(p, ih);
|
||||
else
|
||||
ithread_execute_handlers(p, ie);
|
||||
}
|
||||
WITNESS_WARN(WARN_PANIC, NULL, "suspending ithread");
|
||||
mtx_assert(&Giant, MA_NOTOWNED);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
thread_lock(td);
|
||||
if (atomic_load_acq_int(&ithd->it_need) == 0 &&
|
||||
(ithd->it_flags & (IT_DEAD | IT_WAIT)) == 0) {
|
||||
TD_SET_IWAIT(td);
|
||||
ie->ie_count = 0;
|
||||
mi_switch(SW_VOL | SWT_IWAIT, NULL);
|
||||
}
|
||||
if (ithd->it_flags & IT_WAIT) {
|
||||
wake = 1;
|
||||
ithd->it_flags &= ~IT_WAIT;
|
||||
}
|
||||
thread_unlock(td);
|
||||
if (wake) {
|
||||
wakeup(ithd);
|
||||
wake = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main loop for interrupt filter.
|
||||
*
|
||||
* Some architectures (i386, amd64 and arm) require the optional frame
|
||||
* parameter, and use it as the main argument for fast handler execution
|
||||
* when ih_argument == NULL.
|
||||
*
|
||||
* Return value:
|
||||
* o FILTER_STRAY: No filter recognized the event, and no
|
||||
* filter-less handler is registered on this
|
||||
* line.
|
||||
* o FILTER_HANDLED: A filter claimed the event and served it.
|
||||
* o FILTER_SCHEDULE_THREAD: No filter claimed the event, but there's at
|
||||
* least one filter-less handler on this line.
|
||||
* o FILTER_HANDLED |
|
||||
* FILTER_SCHEDULE_THREAD: A filter claimed the event, and asked for
|
||||
* scheduling the per-handler ithread.
|
||||
*
|
||||
* In case an ithread has to be scheduled, in *ithd there will be a
|
||||
* pointer to a struct intr_thread containing the thread to be
|
||||
* scheduled.
|
||||
*/
|
||||
|
||||
static int
|
||||
intr_filter_loop(struct intr_event *ie, struct trapframe *frame,
|
||||
struct intr_thread **ithd)
|
||||
{
|
||||
struct intr_handler *ih;
|
||||
void *arg;
|
||||
int ret, thread_only;
|
||||
|
||||
ret = 0;
|
||||
thread_only = 0;
|
||||
TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) {
|
||||
/*
|
||||
* Execute fast interrupt handlers directly.
|
||||
* To support clock handlers, if a handler registers
|
||||
* with a NULL argument, then we pass it a pointer to
|
||||
* a trapframe as its argument.
|
||||
*/
|
||||
arg = ((ih->ih_argument == NULL) ? frame : ih->ih_argument);
|
||||
|
||||
CTR5(KTR_INTR, "%s: exec %p/%p(%p) for %s", __func__,
|
||||
ih->ih_filter, ih->ih_handler, arg, ih->ih_name);
|
||||
|
||||
if (ih->ih_filter != NULL)
|
||||
ret = ih->ih_filter(arg);
|
||||
else {
|
||||
thread_only = 1;
|
||||
continue;
|
||||
}
|
||||
KASSERT(ret == FILTER_STRAY ||
|
||||
((ret & (FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) != 0 &&
|
||||
(ret & ~(FILTER_SCHEDULE_THREAD | FILTER_HANDLED)) == 0),
|
||||
("%s: incorrect return value %#x from %s", __func__, ret,
|
||||
ih->ih_name));
|
||||
if (ret & FILTER_STRAY)
|
||||
continue;
|
||||
else {
|
||||
*ithd = ih->ih_thread;
|
||||
return (ret);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* No filters handled the interrupt and we have at least
|
||||
* one handler without a filter. In this case, we schedule
|
||||
* all of the filter-less handlers to run in the ithread.
|
||||
*/
|
||||
if (thread_only) {
|
||||
*ithd = ie->ie_thread;
|
||||
return (FILTER_SCHEDULE_THREAD);
|
||||
}
|
||||
return (FILTER_STRAY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main interrupt handling body.
|
||||
*
|
||||
* Input:
|
||||
* o ie: the event connected to this interrupt.
|
||||
* o frame: some archs (i.e. i386) pass a frame to some.
|
||||
* handlers as their main argument.
|
||||
* Return value:
|
||||
* o 0: everything ok.
|
||||
* o EINVAL: stray interrupt.
|
||||
*/
|
||||
int
|
||||
intr_event_handle(struct intr_event *ie, struct trapframe *frame)
|
||||
{
|
||||
struct intr_thread *ithd;
|
||||
struct trapframe *oldframe;
|
||||
struct thread *td;
|
||||
int thread;
|
||||
|
||||
ithd = NULL;
|
||||
td = curthread;
|
||||
|
||||
if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers))
|
||||
return (EINVAL);
|
||||
|
||||
td->td_intr_nesting_level++;
|
||||
thread = 0;
|
||||
critical_enter();
|
||||
oldframe = td->td_intr_frame;
|
||||
td->td_intr_frame = frame;
|
||||
thread = intr_filter_loop(ie, frame, &ithd);
|
||||
if (thread & FILTER_HANDLED) {
|
||||
if (ie->ie_post_filter != NULL)
|
||||
ie->ie_post_filter(ie->ie_source);
|
||||
} else {
|
||||
if (ie->ie_pre_ithread != NULL)
|
||||
ie->ie_pre_ithread(ie->ie_source);
|
||||
}
|
||||
td->td_intr_frame = oldframe;
|
||||
critical_exit();
|
||||
|
||||
/* Interrupt storm logic */
|
||||
if (thread & FILTER_STRAY) {
|
||||
ie->ie_count++;
|
||||
if (ie->ie_count < intr_storm_threshold)
|
||||
printf("Interrupt stray detection not present\n");
|
||||
}
|
||||
|
||||
/* Schedule an ithread if needed. */
|
||||
if (thread & FILTER_SCHEDULE_THREAD) {
|
||||
if (intr_event_schedule_thread(ie, ithd) != 0)
|
||||
panic("%s: impossible stray interrupt", __func__);
|
||||
}
|
||||
td->td_intr_nesting_level--;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DDB
|
||||
/*
|
||||
|
@ -3,6 +3,6 @@
|
||||
.PATH: ${SRCTOP}/sys/dev/asmc
|
||||
|
||||
KMOD= asmc
|
||||
SRCS= asmc.c opt_acpi.h opt_intr_filter.h acpi_if.h bus_if.h device_if.h
|
||||
SRCS= asmc.c opt_acpi.h acpi_if.h bus_if.h device_if.h
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
Loading…
Reference in New Issue
Block a user