Changeset View
Changeset View
Standalone View
Standalone View
head/sys/kern/kern_intr.c
Show First 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <sys/unistd.h> | #include <sys/unistd.h> | ||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/smp.h> | |||||
#include <machine/stdarg.h> | #include <machine/stdarg.h> | ||||
#ifdef DDB | #ifdef DDB | ||||
#include <ddb/ddb.h> | #include <ddb/ddb.h> | ||||
#include <ddb/db_sym.h> | #include <ddb/db_sym.h> | ||||
#endif | #endif | ||||
/* | /* | ||||
* Describe an interrupt thread. There is one of these per interrupt event. | * Describe an interrupt thread. There is one of these per interrupt event. | ||||
Show All 9 Lines | |||||
#define IT_DEAD 0x000001 /* Thread is waiting to exit. */ | #define IT_DEAD 0x000001 /* Thread is waiting to exit. */ | ||||
#define IT_WAIT 0x000002 /* Thread is waiting for completion. */ | #define IT_WAIT 0x000002 /* Thread is waiting for completion. */ | ||||
struct intr_entropy { | struct intr_entropy { | ||||
struct thread *td; | struct thread *td; | ||||
uintptr_t event; | uintptr_t event; | ||||
}; | }; | ||||
struct intr_event *clk_intr_event; | |||||
struct intr_event *tty_intr_event; | struct intr_event *tty_intr_event; | ||||
void *vm_ih; | void *vm_ih; | ||||
struct proc *intrproc; | struct proc *intrproc; | ||||
static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); | static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); | ||||
static int intr_storm_threshold = 0; | static int intr_storm_threshold = 0; | ||||
SYSCTL_INT(_hw, OID_AUTO, intr_storm_threshold, CTLFLAG_RWTUN, | SYSCTL_INT(_hw, OID_AUTO, intr_storm_threshold, CTLFLAG_RWTUN, | ||||
▲ Show 20 Lines • Show All 917 Lines • ▼ Show 20 Lines | |||||
* Add a software interrupt handler to a specified event. If a given event | * Add a software interrupt handler to a specified event. If a given event | ||||
* is not specified, then a new event is created. | * is not specified, then a new event is created. | ||||
*/ | */ | ||||
int | int | ||||
swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, | swi_add(struct intr_event **eventp, const char *name, driver_intr_t handler, | ||||
void *arg, int pri, enum intr_type flags, void **cookiep) | void *arg, int pri, enum intr_type flags, void **cookiep) | ||||
{ | { | ||||
struct intr_event *ie; | struct intr_event *ie; | ||||
int error; | int error = 0; | ||||
if (flags & INTR_ENTROPY) | if (flags & INTR_ENTROPY) | ||||
return (EINVAL); | return (EINVAL); | ||||
ie = (eventp != NULL) ? *eventp : NULL; | ie = (eventp != NULL) ? *eventp : NULL; | ||||
if (ie != NULL) { | if (ie != NULL) { | ||||
if (!(ie->ie_flags & IE_SOFT)) | if (!(ie->ie_flags & IE_SOFT)) | ||||
return (EINVAL); | return (EINVAL); | ||||
} else { | } else { | ||||
error = intr_event_create(&ie, NULL, IE_SOFT, 0, | error = intr_event_create(&ie, NULL, IE_SOFT, 0, | ||||
NULL, NULL, NULL, swi_assign_cpu, "swi%d:", pri); | NULL, NULL, NULL, swi_assign_cpu, "swi%d:", pri); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
if (eventp != NULL) | if (eventp != NULL) | ||||
*eventp = ie; | *eventp = ie; | ||||
} | } | ||||
if (handler != NULL) { | |||||
error = intr_event_add_handler(ie, name, NULL, handler, arg, | error = intr_event_add_handler(ie, name, NULL, handler, arg, | ||||
PI_SWI(pri), flags, cookiep); | PI_SWI(pri), flags, cookiep); | ||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Schedule a software interrupt thread. | * Schedule a software interrupt thread. | ||||
*/ | */ | ||||
void | void | ||||
swi_sched(void *cookie, int flags) | swi_sched(void *cookie, int flags) | ||||
{ | { | ||||
struct intr_handler *ih = (struct intr_handler *)cookie; | struct intr_handler *ih = (struct intr_handler *)cookie; | ||||
struct intr_event *ie = ih->ih_event; | struct intr_event *ie = ih->ih_event; | ||||
struct intr_entropy entropy; | struct intr_entropy entropy; | ||||
int error __unused; | int error __unused; | ||||
CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name, | CTR3(KTR_INTR, "swi_sched: %s %s need=%d", ie->ie_name, ih->ih_name, | ||||
ih->ih_need); | ih->ih_need); | ||||
if ((flags & SWI_FROMNMI) == 0) { | |||||
entropy.event = (uintptr_t)ih; | entropy.event = (uintptr_t)ih; | ||||
entropy.td = curthread; | entropy.td = curthread; | ||||
random_harvest_queue(&entropy, sizeof(entropy), RANDOM_SWI); | random_harvest_queue(&entropy, sizeof(entropy), RANDOM_SWI); | ||||
} | |||||
/* | /* | ||||
* Set ih_need for this handler so that if the ithread is already | * Set ih_need for this handler so that if the ithread is already | ||||
* running it will execute this handler on the next pass. Otherwise, | * running it will execute this handler on the next pass. Otherwise, | ||||
* it will execute it the next time it runs. | * it will execute it the next time it runs. | ||||
*/ | */ | ||||
ih->ih_need = 1; | ih->ih_need = 1; | ||||
if (!(flags & SWI_DELAY)) { | if (flags & SWI_DELAY) | ||||
return; | |||||
if (flags & SWI_FROMNMI) { | |||||
#if defined(SMP) && (defined(__i386__) || defined(__amd64__)) | |||||
KASSERT(ie == clk_intr_event, | |||||
("SWI_FROMNMI used not with clk_intr_event")); | |||||
ipi_self_from_nmi(IPI_SWI); | |||||
#endif | |||||
} else { | |||||
VM_CNT_INC(v_soft); | VM_CNT_INC(v_soft); | ||||
error = intr_event_schedule_thread(ie); | error = intr_event_schedule_thread(ie); | ||||
KASSERT(error == 0, ("stray software interrupt")); | KASSERT(error == 0, ("stray software interrupt")); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Remove a software interrupt handler. Currently this code does not | * Remove a software interrupt handler. Currently this code does not | ||||
▲ Show 20 Lines • Show All 263 Lines • ▼ Show 20 Lines | #endif | ||||
* This fence is required to ensure that no later loads are | * This fence is required to ensure that no later loads are | ||||
* re-ordered before the ie_active store. | * re-ordered before the ie_active store. | ||||
*/ | */ | ||||
atomic_thread_fence_seq_cst(); | atomic_thread_fence_seq_cst(); | ||||
CK_SLIST_FOREACH(ih, &ie->ie_handlers, ih_next) { | CK_SLIST_FOREACH(ih, &ie->ie_handlers, ih_next) { | ||||
if ((ih->ih_flags & IH_SUSP) != 0) | if ((ih->ih_flags & IH_SUSP) != 0) | ||||
continue; | continue; | ||||
if ((ie->ie_flags & IE_SOFT) != 0 && ih->ih_need == 0) | |||||
continue; | |||||
if (ih->ih_filter == NULL) { | if (ih->ih_filter == NULL) { | ||||
thread = true; | thread = true; | ||||
continue; | continue; | ||||
} | } | ||||
CTR4(KTR_INTR, "%s: exec %p(%p) for %s", __func__, | CTR4(KTR_INTR, "%s: exec %p(%p) for %s", __func__, | ||||
ih->ih_filter, ih->ih_argument == NULL ? frame : | ih->ih_filter, ih->ih_argument == NULL ? frame : | ||||
ih->ih_argument, ih->ih_name); | ih->ih_argument, ih->ih_name); | ||||
if (ih->ih_argument == NULL) | if (ih->ih_argument == NULL) | ||||
▲ Show 20 Lines • Show All 208 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Start standard software interrupt threads | * Start standard software interrupt threads | ||||
*/ | */ | ||||
static void | static void | ||||
start_softintr(void *dummy) | start_softintr(void *dummy) | ||||
{ | { | ||||
if (swi_add(&clk_intr_event, "clk", NULL, NULL, SWI_CLOCK, | |||||
INTR_MPSAFE, NULL)) | |||||
panic("died while creating clk swi ithread"); | |||||
if (swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih)) | if (swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, INTR_MPSAFE, &vm_ih)) | ||||
panic("died while creating vm swi ithread"); | panic("died while creating vm swi ithread"); | ||||
} | } | ||||
SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, | SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, | ||||
NULL); | NULL); | ||||
/* | /* | ||||
* Sysctls used by systat and others: hw.intrnames and hw.intrcnt. | * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. | ||||
▲ Show 20 Lines • Show All 69 Lines • Show Last 20 Lines |