Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/x86/intr_machdep.c
Show First 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | |||||
static MALLOC_DEFINE(M_INTR, "intr", "Interrupt Sources"); | static MALLOC_DEFINE(M_INTR, "intr", "Interrupt Sources"); | ||||
static int intr_assign_cpu(void *arg, int cpu); | static int intr_assign_cpu(void *arg, int cpu); | ||||
static void intr_disable_src(void *arg); | static void intr_disable_src(void *arg); | ||||
static void intr_init(void *__dummy); | static void intr_init(void *__dummy); | ||||
static int intr_pic_registered(struct pic *pic); | static int intr_pic_registered(struct pic *pic); | ||||
static void intrcnt_setname(const char *name, int index); | static void intrcnt_setname(const char *name, int index); | ||||
static void intrcnt_updatename(struct intsrc *is); | |||||
static void intrcnt_register(struct intsrc *is); | |||||
/* | /* | ||||
* SYSINIT levels for SI_SUB_INTR: | * SYSINIT levels for SI_SUB_INTR: | ||||
* | * | ||||
* SI_ORDER_FIRST: Initialize locks and pics TAILQ, xen_hvm_cpu_init | * SI_ORDER_FIRST: Initialize locks and pics TAILQ, xen_hvm_cpu_init | ||||
* SI_ORDER_SECOND: Xen PICs | * SI_ORDER_SECOND: Xen PICs | ||||
* SI_ORDER_THIRD: Add I/O APIC PICs, alloc MSI and Xen IRQ ranges | * SI_ORDER_THIRD: Add I/O APIC PICs, alloc MSI and Xen IRQ ranges | ||||
* SI_ORDER_FOURTH: Add 8259A PICs | * SI_ORDER_FOURTH: Add 8259A PICs | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | interrupt_sources = mallocarray(num_io_irqs, sizeof(*interrupt_sources), | ||||
M_INTR, M_WAITOK | M_ZERO); | M_INTR, M_WAITOK | M_ZERO); | ||||
#ifdef SMP | #ifdef SMP | ||||
interrupt_sorted = mallocarray(num_io_irqs, sizeof(*interrupt_sorted), | interrupt_sorted = mallocarray(num_io_irqs, sizeof(*interrupt_sorted), | ||||
M_INTR, M_WAITOK | M_ZERO); | M_INTR, M_WAITOK | M_ZERO); | ||||
#endif | #endif | ||||
/* | /* | ||||
* - 1 ??? dummy counter. | * - 1 ??? dummy counter. | ||||
* - 2 counters for each I/O interrupt. | |||||
* - 1 counter for each CPU for lapic timer. | * - 1 counter for each CPU for lapic timer. | ||||
* - 1 counter for each CPU for the Hyper-V vmbus driver. | * - 1 counter for each CPU for hypervisor drivers. | ||||
* - 8 counters for each CPU for IPI counters for SMP. | * - 8 counters for each CPU for IPI counters for SMP. | ||||
*/ | */ | ||||
nintrcnt = 1 + num_io_irqs * 2 + mp_ncpus * 2; | nintrcnt = 1 + mp_ncpus * 2; | ||||
#ifdef COUNT_IPIS | #ifdef COUNT_IPIS | ||||
if (mp_ncpus > 1) | if (mp_ncpus > 1) | ||||
nintrcnt += 8 * mp_ncpus; | nintrcnt += 8 * mp_ncpus; | ||||
#endif | #endif | ||||
intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTR, M_WAITOK | | intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTR, M_WAITOK | | ||||
M_ZERO); | M_ZERO); | ||||
intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTR, M_WAITOK | | intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTR, M_WAITOK | | ||||
M_ZERO); | M_ZERO); | ||||
Show All 38 Lines | intr_register_source(struct intsrc *isrc) | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
sx_xlock(&intrsrc_lock); | sx_xlock(&intrsrc_lock); | ||||
if (interrupt_sources[vector] != NULL) { | if (interrupt_sources[vector] != NULL) { | ||||
sx_xunlock(&intrsrc_lock); | sx_xunlock(&intrsrc_lock); | ||||
intr_event_destroy(isrc->is_event); | intr_event_destroy(isrc->is_event); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
intrcnt_register(isrc); | |||||
interrupt_sources[vector] = isrc; | interrupt_sources[vector] = isrc; | ||||
isrc->is_handlers = 0; | isrc->is_handlers = 0; | ||||
sx_xunlock(&intrsrc_lock); | sx_xunlock(&intrsrc_lock); | ||||
return (0); | return (0); | ||||
} | } | ||||
struct intsrc * | struct intsrc * | ||||
intr_lookup_source(int vector) | intr_lookup_source(int vector) | ||||
Show All 14 Lines | intr_add_handler(const char *name, int vector, driver_filter_t filter, | ||||
isrc = intr_lookup_source(vector); | isrc = intr_lookup_source(vector); | ||||
if (isrc == NULL) | if (isrc == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = intr_event_add_handler(isrc->is_event, name, filter, handler, | error = intr_event_add_handler(isrc->is_event, name, filter, handler, | ||||
arg, intr_priority(flags), flags, cookiep); | arg, intr_priority(flags), flags, cookiep); | ||||
if (error == 0) { | if (error == 0) { | ||||
sx_xlock(&intrsrc_lock); | sx_xlock(&intrsrc_lock); | ||||
intrcnt_updatename(isrc); | |||||
isrc->is_handlers++; | isrc->is_handlers++; | ||||
if (isrc->is_handlers == 1) { | if (isrc->is_handlers == 1) { | ||||
isrc->is_domain = domain; | isrc->is_domain = domain; | ||||
isrc->is_pic->pic_enable_intr(isrc); | isrc->is_pic->pic_enable_intr(isrc); | ||||
isrc->is_pic->pic_enable_source(isrc); | isrc->is_pic->pic_enable_source(isrc); | ||||
} | } | ||||
sx_xunlock(&intrsrc_lock); | sx_xunlock(&intrsrc_lock); | ||||
} | } | ||||
Show All 10 Lines | intr_remove_handler(void *cookie) | ||||
error = intr_event_remove_handler(cookie); | error = intr_event_remove_handler(cookie); | ||||
if (error == 0) { | if (error == 0) { | ||||
sx_xlock(&intrsrc_lock); | sx_xlock(&intrsrc_lock); | ||||
isrc->is_handlers--; | isrc->is_handlers--; | ||||
if (isrc->is_handlers == 0) { | if (isrc->is_handlers == 0) { | ||||
isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); | isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); | ||||
isrc->is_pic->pic_disable_intr(isrc); | isrc->is_pic->pic_disable_intr(isrc); | ||||
} | } | ||||
intrcnt_updatename(isrc); | |||||
sx_xunlock(&intrsrc_lock); | sx_xunlock(&intrsrc_lock); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) | intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol) | ||||
{ | { | ||||
Show All 22 Lines | intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame) | ||||
u_long strays; | u_long strays; | ||||
/* | /* | ||||
* We count software interrupts when we process them. The | * We count software interrupts when we process them. The | ||||
* code here follows previous practice, but there's an | * code here follows previous practice, but there's an | ||||
* argument for counting hardware interrupts when they're | * argument for counting hardware interrupts when they're | ||||
* processed too. | * processed too. | ||||
*/ | */ | ||||
(*isrc->is_count)++; | |||||
VM_CNT_INC(v_intr); | VM_CNT_INC(v_intr); | ||||
ie = isrc->is_event; | ie = isrc->is_event; | ||||
/* | /* | ||||
* XXX: We assume that IRQ 0 is only used for the ISA timer | * XXX: We assume that IRQ 0 is only used for the ISA timer | ||||
* device (clk). | * device (clk). | ||||
*/ | */ | ||||
vector = isrc->is_pic->pic_vector(isrc); | vector = isrc->is_pic->pic_vector(isrc); | ||||
if (vector == 0) | if (vector == 0) | ||||
clkintr_pending = 1; | clkintr_pending = 1; | ||||
/* | /* | ||||
* For stray interrupts, mask and EOI the source, bump the | * For stray interrupts, mask and EOI the source, bump the | ||||
* stray count, and log the condition. | * stray count, and log the condition. | ||||
*/ | */ | ||||
if ((strays = intr_event_handle(ie, frame)) != 0) { | if ((strays = intr_event_handle(ie, frame)) != 0) { | ||||
isrc->is_pic->pic_disable_source(isrc, PIC_EOI); | isrc->is_pic->pic_disable_source(isrc, PIC_EOI); | ||||
(*isrc->is_straycount)++; | |||||
if (strays < INTR_STRAY_LOG_MAX) | if (strays < INTR_STRAY_LOG_MAX) | ||||
log(LOG_ERR, "stray irq%d\n", vector); | log(LOG_ERR, "stray irq%d\n", vector); | ||||
else if (strays == INTR_STRAY_LOG_MAX) | else if (strays == INTR_STRAY_LOG_MAX) | ||||
log(LOG_CRIT, | log(LOG_CRIT, | ||||
"too many stray irq %d's: not logging anymore\n", | "too many stray irq %d's: not logging anymore\n", | ||||
vector); | vector); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
intrcnt_setname(const char *name, int index) | intrcnt_setname(const char *name, int index) | ||||
{ | { | ||||
snprintf(intrnames + INTRNAME_LEN * index, INTRNAME_LEN, "%-*s", | snprintf(intrnames + INTRNAME_LEN * index, INTRNAME_LEN, "%-*s", | ||||
INTRNAME_LEN - 1, name); | INTRNAME_LEN - 1, name); | ||||
} | } | ||||
static void | |||||
intrcnt_updatename(struct intsrc *is) | |||||
{ | |||||
intrcnt_setname(is->is_event->ie_fullname, is->is_index); | |||||
} | |||||
static void | |||||
intrcnt_register(struct intsrc *is) | |||||
{ | |||||
char straystr[INTRNAME_LEN]; | |||||
KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__)); | |||||
mtx_lock_spin(&intrcnt_lock); | |||||
MPASS(intrcnt_index + 2 <= nintrcnt); | |||||
is->is_index = nintrcnt - 2; | |||||
snprintf(straystr, sizeof(straystr), "stray irq%d", | |||||
is->is_pic->pic_vector(is)); | |||||
intrcnt_updatename(is); | |||||
is->is_count = &intrcnt[is->is_index]; | |||||
intrcnt_setname(straystr, is->is_index + 1); | |||||
is->is_straycount = &intrcnt[is->is_index + 1]; | |||||
mtx_unlock_spin(&intrcnt_lock); | |||||
} | |||||
void | void | ||||
intrcnt_add(const char *name, u_long **countp) | intrcnt_add(const char *name, u_long **countp) | ||||
{ | { | ||||
mtx_lock_spin(&intrcnt_lock); | mtx_lock_spin(&intrcnt_lock); | ||||
MPASS(intrcnt_index < nintrcnt); | MPASS(intrcnt_index < nintrcnt); | ||||
*countp = &intrcnt[intrcnt_index]; | *countp = &intrcnt[intrcnt_index]; | ||||
intrcnt_setname(name, intrcnt_index); | intrcnt_setname(name, intrcnt_index); | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
#endif | #endif | ||||
/* Add a description to an active interrupt handler. */ | /* Add a description to an active interrupt handler. */ | ||||
int | int | ||||
intr_describe(u_int vector, void *ih, const char *descr) | intr_describe(u_int vector, void *ih, const char *descr) | ||||
{ | { | ||||
struct intsrc *isrc; | struct intsrc *isrc; | ||||
int error; | |||||
isrc = intr_lookup_source(vector); | isrc = intr_lookup_source(vector); | ||||
if (isrc == NULL) | if (isrc == NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = intr_event_describe_handler(isrc->is_event, ih, descr); | return (intr_event_describe_handler(isrc->is_event, ih, descr)); | ||||
if (error) | |||||
return (error); | |||||
intrcnt_updatename(isrc); | |||||
return (0); | |||||
} | } | ||||
void | void | ||||
intr_reprogram(void) | intr_reprogram(void) | ||||
{ | { | ||||
struct intsrc *is; | struct intsrc *is; | ||||
u_int v; | u_int v; | ||||
▲ Show 20 Lines • Show All 184 Lines • ▼ Show 20 Lines | if (error != 0) | ||||
return (error); | return (error); | ||||
sbuf_new_for_sysctl(&sbuf, NULL, 128, req); | sbuf_new_for_sysctl(&sbuf, NULL, 128, req); | ||||
sx_slock(&intrsrc_lock); | sx_slock(&intrsrc_lock); | ||||
for (i = 0; i < num_io_irqs; i++) { | for (i = 0; i < num_io_irqs; i++) { | ||||
isrc = interrupt_sources[i]; | isrc = interrupt_sources[i]; | ||||
if (isrc == NULL) | if (isrc == NULL) | ||||
continue; | continue; | ||||
sbuf_printf(&sbuf, "%s:%d @cpu%d(domain%d): %ld\n", | sbuf_printf(&sbuf, "%s @cpu%d(domain%d): %lu\n", | ||||
isrc->is_event->ie_fullname, | isrc->is_event->ie_fullname, | ||||
isrc->is_index, | |||||
isrc->is_cpu, | isrc->is_cpu, | ||||
isrc->is_domain, | isrc->is_domain, | ||||
isrc->is_event->ie_intrcnt); | isrc->is_event->ie_intrcnt); | ||||
} | } | ||||
sx_sunlock(&intrsrc_lock); | sx_sunlock(&intrsrc_lock); | ||||
error = sbuf_finish(&sbuf); | error = sbuf_finish(&sbuf); | ||||
sbuf_delete(&sbuf); | sbuf_delete(&sbuf); | ||||
return (error); | return (error); | ||||
} | } | ||||
SYSCTL_PROC(_hw, OID_AUTO, intrs, | SYSCTL_PROC(_hw, OID_AUTO, intrs, | ||||
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, | CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, | ||||
0, 0, sysctl_hw_intrs, "A", | 0, 0, sysctl_hw_intrs, "A", | ||||
"interrupt:number @cpu: count"); | "interrupt @cpu: count"); | ||||
/* | /* | ||||
* Compare two, possibly NULL, entries in the interrupt source array | * Compare two, possibly NULL, entries in the interrupt source array | ||||
* by load. | * by load. | ||||
*/ | */ | ||||
static int | static int | ||||
intrcmp(const void *one, const void *two) | intrcmp(const void *one, const void *two) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 156 Lines • Show Last 20 Lines |