diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -834,24 +834,6 @@ static void watchdog_fire(void) { - int nintr; - uint64_t inttotal; - u_long *curintr; - char *curname; - - curintr = intrcnt; - curname = intrnames; - inttotal = 0; - nintr = sintrcnt / sizeof(u_long); - - printf("interrupt total\n"); - while (--nintr >= 0) { - if (*curintr) - printf("%-12s %20lu\n", curname, *curintr); - curname += strlen(curname) + 1; - inttotal += *curintr++; - } - printf("Total %20ju\n", (uintmax_t)inttotal); #if defined(KDB) && !defined(KDB_UNATTENDED) kdb_backtrace(); diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -3,6 +3,7 @@ * * Copyright (c) 1997, Stefan Esser * All rights reserved. + * Copyright © 2022 Elliott Mitchell * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -54,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -109,8 +111,8 @@ #endif static TAILQ_HEAD(, intr_event) event_list = TAILQ_HEAD_INITIALIZER(event_list); -static struct mtx event_lock; -MTX_SYSINIT(intr_event_list, &event_lock, "intr event list", MTX_DEF); +static struct sx event_lock; +SX_SYSINIT(intr_event_list, &event_lock, "intr event list"); static void intr_event_update(struct intr_event *ie); static int intr_event_schedule_thread(struct intr_event *ie, struct trapframe *frame); @@ -297,6 +299,8 @@ ie->ie_assign_cpu = assign_cpu; ie->ie_flags = flags; ie->ie_cpu = NOCPU; + ie->ie_stray = 0; + ie->ie_intrcnt = 0; CK_SLIST_INIT(&ie->ie_handlers); mtx_init(&ie->ie_lock, "intr event", NULL, MTX_DEF); @@ -304,9 +308,9 @@ vsnprintf(ie->ie_name, sizeof(ie->ie_name), fmt, ap); va_end(ap); strlcpy(ie->ie_fullname, ie->ie_name, sizeof(ie->ie_fullname)); - mtx_lock(&event_lock); + sx_xlock(&event_lock); TAILQ_INSERT_TAIL(&event_list, ie, ie_list); - mtx_unlock(&event_lock); + sx_xunlock(&event_lock); if (event != NULL) *event = ie; CTR2(KTR_INTR, "%s: created %s", __func__, ie->ie_name); @@ -515,11 +519,11 @@ if (ie == NULL) return (EINVAL); - mtx_lock(&event_lock); + sx_xlock(&event_lock); mtx_lock(&ie->ie_lock); if (!CK_SLIST_EMPTY(&ie->ie_handlers)) { mtx_unlock(&ie->ie_lock); - mtx_unlock(&event_lock); + sx_xunlock(&event_lock); return (EBUSY); } TAILQ_REMOVE(&event_list, ie, ie_list); @@ -530,7 +534,7 @@ } #endif mtx_unlock(&ie->ie_lock); - mtx_unlock(&event_lock); + sx_xunlock(&event_lock); mtx_destroy(&ie->ie_lock); free(ie, M_ITHREAD); return (0); @@ -1330,9 +1334,9 @@ * handlers as their main argument. * Return value: * o 0: everything ok. - * o EINVAL: stray interrupt. + * o non-0: stray interrupt, current count. */ -int +u_long intr_event_handle(struct intr_event *ie, struct trapframe *frame) { struct intr_handler *ih; @@ -1348,9 +1352,16 @@ intr_prof_stack_use(td, frame); #endif - /* An interrupt with no event or handlers is a stray interrupt. */ - if (ie == NULL || CK_SLIST_EMPTY(&ie->ie_handlers)) - return (EINVAL); + /* An interrupt with no event is a stray interrupt. */ + if (ie == NULL) + return (~0UL); + + /* Increment the interrupt counter. */ + atomic_add_long(&ie->ie_intrcnt, 1); + + /* An interrupt with no handlers is a stray interrupt. */ + if (CK_SLIST_EMPTY(&ie->ie_handlers)) + return (atomic_fetchadd_long(&ie->ie_stray, 1) + 1); /* * Execute fast interrupt handlers directly. @@ -1452,7 +1463,7 @@ #ifdef notyet /* The interrupt is not aknowledged by any filter and has no ithread. */ if (!thread && !filter) - return (EINVAL); + return (atomic_fetchadd_long(&ie->ie_stray, 1) + 1); #endif return (0); } @@ -1612,52 +1623,74 @@ /* * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. - * The data for this machine dependent, and the declarations are in machine - * dependent code. The layout of intrnames and intrcnt however is machine - * independent. - * - * We do not know the length of intrcnt and intrnames at compile time, so - * calculate things at run time. + * The data for this machine independent. */ -static int -sysctl_intrnames(SYSCTL_HANDLER_ARGS) +int +intr_event_sysctl_intrnames(SYSCTL_HANDLER_ARGS) { - return (sysctl_handle_opaque(oidp, intrnames, sintrnames, req)); -} + struct intr_event *ie; + u_int len; + const char straystr[] = "stray "; + int error; -SYSCTL_PROC(_hw, OID_AUTO, intrnames, - CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, - sysctl_intrnames, "", - "Interrupt Names"); + sx_slock(&event_lock); + TAILQ_FOREACH(ie, &event_list, ie_list) { + len = strnlen(ie->ie_fullname, sizeof(ie->ie_fullname)) + 1; + error = SYSCTL_OUT(req, ie->ie_fullname, len); + if (error != 0) + goto out; + + error = SYSCTL_OUT(req, straystr, sizeof(straystr) - 1); + if (error != 0) + goto out; + error = SYSCTL_OUT(req, ie->ie_fullname, len); + if (error != 0) + goto out; + } +out: + sx_sunlock(&event_lock); + return (error); +} -static int -sysctl_intrcnt(SYSCTL_HANDLER_ARGS) +int +intr_event_sysctl_intrcnt(SYSCTL_HANDLER_ARGS) { + struct intr_event *ie; + int error = 0; + int sz = sizeof(ie->ie_intrcnt); + u_long val; + void *arg = &val; #ifdef SCTL_MASK32 - uint32_t *intrcnt32; - unsigned i; - int error; + uint32_t val32; if (req->flags & SCTL_MASK32) { - if (!req->oldptr) - return (sysctl_handle_opaque(oidp, NULL, sintrcnt / 2, req)); - intrcnt32 = malloc(sintrcnt / 2, M_TEMP, M_NOWAIT); - if (intrcnt32 == NULL) - return (ENOMEM); - for (i = 0; i < sintrcnt / sizeof (u_long); i++) - intrcnt32[i] = intrcnt[i]; - error = sysctl_handle_opaque(oidp, intrcnt32, sintrcnt / 2, req); - free(intrcnt32, M_TEMP); - return (error); + sz = sizeof(val32); + arg = &val32; } #endif - return (sysctl_handle_opaque(oidp, intrcnt, sintrcnt, req)); -} -SYSCTL_PROC(_hw, OID_AUTO, intrcnt, - CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, - sysctl_intrcnt, "", - "Interrupt Counts"); + sx_slock(&event_lock); + TAILQ_FOREACH(ie, &event_list, ie_list) { +#ifdef SCTL_MASK32 + val32 = +#endif + val = ie->ie_intrcnt; + error = SYSCTL_OUT(req, arg, sz); + if (error != 0) + goto out; + +#ifdef SCTL_MASK32 + val32 = +#endif + val = ie->ie_stray; + error = SYSCTL_OUT(req, arg, sz); + if (error != 0) + goto out; + } +out: + sx_sunlock(&event_lock); + return (error); +} #ifdef DDB /* @@ -1665,19 +1698,11 @@ */ DB_SHOW_COMMAND_FLAGS(intrcnt, db_show_intrcnt, DB_CMD_MEMSAFE) { - u_long *i; - char *cp; - u_int j; - - cp = intrnames; - j = 0; - for (i = intrcnt; j < (sintrcnt / sizeof(u_long)) && !db_pager_quit; - i++, j++) { - if (*cp == '\0') - break; - if (*i != 0) - db_printf("%s\t%lu\n", cp, *i); - cp += strlen(cp) + 1; - } + struct intr_event *ie; + + for (ie = TAILQ_FIRST(&event_list); ie && !db_pager_quit; + ie = TAILQ_NEXT(ie, ie_list)) + db_printf("%s\t%lu\nstray %s\t%lu\n", ie->ie_fullname, + ie->ie_intrcnt, ie->ie_fullname, ie->ie_stray); } #endif diff --git a/sys/kern/subr_intr.c b/sys/kern/subr_intr.c --- a/sys/kern/subr_intr.c +++ b/sys/kern/subr_intr.c @@ -152,7 +152,7 @@ char *intrnames; size_t sintrcnt; size_t sintrnames; -static u_int intrcnt_index; +u_int nintrcnt; static struct intr_irqsrc *intr_map_get_isrc(u_int res_id); static void intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc); @@ -166,7 +166,6 @@ static void intr_irq_init(void *dummy __unused) { - u_int intrcnt_count; SLIST_INIT(&pic_list); mtx_init(&pic_list_lock, "intr pic list", NULL, MTX_DEF); @@ -177,17 +176,15 @@ * - 2 counters for each I/O interrupt. * - MAXCPU counters for each IPI counters for SMP. */ - intrcnt_count = intr_nirq * 2; + nintrcnt = 1; #ifdef SMP - intrcnt_count += INTR_IPI_COUNT * MAXCPU; + nintrcnt += INTR_IPI_COUNT * MAXCPU; #endif - intrcnt = mallocarray(intrcnt_count, sizeof(u_long), M_INTRNG, + intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTRNG, M_WAITOK | M_ZERO); - intrnames = mallocarray(intrcnt_count, INTRNAME_LEN, M_INTRNG, + intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTRNG, M_WAITOK | M_ZERO); - sintrcnt = intrcnt_count * sizeof(u_long); - sintrnames = intrcnt_count * INTRNAME_LEN; irq_sources = mallocarray(intr_nirq, sizeof(struct intr_irqsrc*), M_INTRNG, M_WAITOK | M_ZERO); } @@ -201,41 +198,7 @@ INTRNAME_LEN - 1, name); } -/* - * Update name for interrupt source with interrupt event. - */ -static void -intrcnt_updatename(struct intr_irqsrc *isrc) -{ - - /* QQQ: What about stray counter name? */ - mtx_assert(&isrc_table_lock, MA_OWNED); - intrcnt_setname(isrc->isrc_event->ie_fullname, isrc->isrc_index); -} - -/* - * Virtualization for interrupt source interrupt counter increment. - */ -static inline void -isrc_increment_count(struct intr_irqsrc *isrc) -{ - - if (isrc->isrc_flags & INTR_ISRCF_PPI) - atomic_add_long(&isrc->isrc_count[0], 1); - else - isrc->isrc_count[0]++; -} - -/* - * Virtualization for interrupt source interrupt stray counter increment. - */ -static inline void -isrc_increment_straycount(struct intr_irqsrc *isrc) -{ - - isrc->isrc_count[1]++; -} - +#ifdef INTR_SOLO /* * Virtualization for interrupt source interrupt name update. */ @@ -246,47 +209,15 @@ mtx_assert(&isrc_table_lock, MA_OWNED); - if (name != NULL) { + if (name != NULL) snprintf(str, INTRNAME_LEN, "%s: %s", isrc->isrc_name, name); - intrcnt_setname(str, isrc->isrc_index); - snprintf(str, INTRNAME_LEN, "stray %s: %s", isrc->isrc_name, - name); - intrcnt_setname(str, isrc->isrc_index + 1); - } else { + else snprintf(str, INTRNAME_LEN, "%s:", isrc->isrc_name); - intrcnt_setname(str, isrc->isrc_index); - snprintf(str, INTRNAME_LEN, "stray %s:", isrc->isrc_name); - intrcnt_setname(str, isrc->isrc_index + 1); - } -} - -/* - * Virtualization for interrupt source interrupt counters setup. - */ -static void -isrc_setup_counters(struct intr_irqsrc *isrc) -{ - u_int index; - /* - * XXX - it does not work well with removable controllers and - * interrupt sources !!! - */ - index = atomic_fetchadd_int(&intrcnt_index, 2); - isrc->isrc_index = index; - isrc->isrc_count = &intrcnt[index]; - isrc_update_name(isrc, NULL); -} - -/* - * Virtualization for interrupt source interrupt counters release. - */ -static void -isrc_release_counters(struct intr_irqsrc *isrc) -{ - - panic("%s: not implemented", __func__); + strlcpy(isrc->isrc_event->ie_fullname, str, + sizeof(isrc->isrc_event->ie_fullname)); } +#endif #ifdef SMP /* @@ -298,7 +229,12 @@ u_int index, i; char str[INTRNAME_LEN]; - index = atomic_fetchadd_int(&intrcnt_index, MAXCPU); + index = (u_int)(atomic_fetchadd_ptr(&sintrcnt, + sizeof(u_long) * MAXCPU) / sizeof(u_long)); + if (index >= nintrcnt) + panic("overflowed IPI interrupt name table size (index=%u)", + index); + atomic_add_ptr(&sintrnames, INTRNAME_LEN * MAXCPU); for (i = 0; i < MAXCPU; i++) { snprintf(str, INTRNAME_LEN, "cpu%d:%s", i, name); intrcnt_setname(str, index + i); @@ -368,8 +304,6 @@ KASSERT(isrc != NULL, ("%s: no source", __func__)); - isrc_increment_count(isrc); - #ifdef INTR_SOLO if (isrc->isrc_filter != NULL) { int error; @@ -384,7 +318,6 @@ return (0); } - isrc_increment_straycount(isrc); return (EINVAL); } @@ -484,13 +417,7 @@ mtx_unlock(&isrc_table_lock); return (error); } - /* - * Setup interrupt counters, but not for IPI sources. Those are setup - * later and only for used ones (up to INTR_IPI_COUNT) to not exhaust - * our counter pool. - */ - if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0) - isrc_setup_counters(isrc); + mtx_unlock(&isrc_table_lock); return (0); } @@ -504,8 +431,6 @@ int error; mtx_lock(&isrc_table_lock); - if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0) - isrc_release_counters(isrc); error = isrc_free_irq(isrc); mtx_unlock(&isrc_table_lock); return (error); @@ -721,15 +646,8 @@ return (error); } - error = intr_event_add_handler(isrc->isrc_event, name, filter, handler, - arg, intr_priority(flags), flags, cookiep); - if (error == 0) { - mtx_lock(&isrc_table_lock); - intrcnt_updatename(isrc); - mtx_unlock(&isrc_table_lock); - } - - return (error); + return (intr_event_add_handler(isrc->isrc_event, name, filter, handler, + arg, intr_priority(flags), flags, cookiep)); } /* @@ -1159,7 +1077,6 @@ if (isrc->isrc_handlers == 0) PIC_DISABLE_INTR(isrc->isrc_dev, isrc); PIC_TEARDOWN_INTR(isrc->isrc_dev, isrc, res, data); - intrcnt_updatename(isrc); mtx_unlock(&isrc_table_lock); } return (error); @@ -1169,7 +1086,6 @@ intr_describe_irq(device_t dev, struct resource *res, void *cookie, const char *descr) { - int error; struct intr_irqsrc *isrc; u_int res_id; @@ -1191,13 +1107,7 @@ return (0); } #endif - error = intr_event_describe_handler(isrc->isrc_event, cookie, descr); - if (error == 0) { - mtx_lock(&isrc_table_lock); - intrcnt_updatename(isrc); - mtx_unlock(&isrc_table_lock); - } - return (error); + return (intr_event_describe_handler(isrc->isrc_event, cookie, descr)); } #ifdef SMP @@ -1569,7 +1479,7 @@ if (isrc == NULL) continue; - num = isrc->isrc_count != NULL ? isrc->isrc_count[0] : 0; + num = isrc->isrc_event != NULL ? isrc->isrc_event->ie_intrcnt : 0; db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i, isrc->isrc_name, isrc->isrc_cpu.__bits[0], isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", num); @@ -1753,3 +1663,53 @@ M_INTRNG, M_WAITOK | M_ZERO); } SYSINIT(intr_map_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_map_init, NULL); + +/* + * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. + */ +static int +sysctl_intrnames(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_opaque(oidp, intrnames, sintrnames, req); + if (error != 0) + return (error); + + return (intr_event_sysctl_intrnames(oidp, intrnames, sintrnames, req)); +} + +SYSCTL_PROC(_hw, OID_AUTO, intrnames, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_intrnames, + "", "Interrupt Names"); + +static int +sysctl_intrcnt(SYSCTL_HANDLER_ARGS) +{ + int error = 0; +#ifdef SCTL_MASK32 + u_int idx; + uint32_t val32; + + if (req->flags & SCTL_MASK32) + for (idx = 0; idx <= sintrcnt / sizeof(u_long) ; ++idx) { + val32 = intrcnt[idx]; + error = SYSCTL_OUT(req, &val32, sizeof(val32)); + if (error != 0) + return (error); + } else +#endif + { + error = sysctl_handle_opaque(oidp, intrcnt, sintrcnt, req); + if (error != 0) + return (error); + } + + return (intr_event_sysctl_intrcnt(oidp, intrcnt, sintrcnt, req)); +} + +SYSCTL_PROC(_hw, OID_AUTO, intrcnt, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_intrcnt, + "", "Interrupt Counts"); diff --git a/sys/powerpc/powerpc/intr_machdep.c b/sys/powerpc/powerpc/intr_machdep.c --- a/sys/powerpc/powerpc/intr_machdep.c +++ b/sys/powerpc/powerpc/intr_machdep.c @@ -93,13 +93,11 @@ struct powerpc_intr { struct intr_event *event; - long *cntp; void *priv; /* PIC-private data */ device_t pic; u_int irq; u_int intline; u_int vector; - u_int cntindex; int fwcode; int ipi; int pi_domain; @@ -116,7 +114,6 @@ int base; }; -static u_int intrcnt_index = 0; static struct mtx intr_table_lock; static struct powerpc_intr **powerpc_intrs; static struct pic piclist[MAX_PICS]; @@ -131,9 +128,9 @@ u_long *intrcnt; char *intrnames; -size_t sintrcnt = sizeof(intrcnt); -size_t sintrnames = sizeof(intrnames); -int nintrcnt; +size_t sintrcnt; +size_t sintrnames; +u_int nintrcnt; /* * Just to start @@ -172,7 +169,7 @@ powerpc_intrs = mallocarray(num_io_irqs, sizeof(*powerpc_intrs), M_INTR, M_WAITOK | M_ZERO); - nintrcnt = 1 + num_io_irqs * 2 + mp_ncpus * 2; + nintrcnt = 1 + mp_ncpus * 2; #ifdef COUNT_IPIS if (mp_ncpus > 1) nintrcnt += 8 * mp_ncpus; @@ -181,11 +178,6 @@ M_ZERO); intrnames = mallocarray(nintrcnt, MAXCOMLEN + 1, M_INTR, M_WAITOK | M_ZERO); - sintrcnt = nintrcnt * sizeof(u_long); - sintrnames = nintrcnt * (MAXCOMLEN + 1); - - intrcnt_setname("???", 0); - intrcnt_index = 1; } /* * This needs to happen before SI_SUB_CPU @@ -211,11 +203,12 @@ void intrcnt_add(const char *name, u_long **countp) { - int idx; + u_int idx; - idx = atomic_fetchadd_int(&intrcnt_index, 1); - KASSERT(idx < nintrcnt, ("intrcnt_add: Interrupt counter index %d/%d" - "reached nintrcnt : %d", intrcnt_index, idx, nintrcnt)); + idx = atomic_fetchadd_int(&sintrcnt, sizeof(u_long)) / sizeof(u_long); + KASSERT(idx < nintrcnt, ("%s: Interrupt counter index %u reached " + "nintrcnt : %u, for \"%s\"", __func__, idx, nintrcnt, name)); + atomic_add_int(&sintrnames, MAXCOMLEN + 1); *countp = &intrcnt[idx]; intrcnt_setname(name, idx); } @@ -224,7 +217,6 @@ static struct powerpc_intr * intr_create(u_int irq) { - char intrname[16]; struct powerpc_intr *i, *iscan; int vector; @@ -244,7 +236,6 @@ } i->event = NULL; - i->cntp = NULL; i->priv = NULL; i->trig = INTR_TRIGGER_CONFORM; i->pol = INTR_POLARITY_CONFORM; @@ -272,10 +263,8 @@ if (iscan == NULL && i->vector != -1) { powerpc_intrs[i->vector] = i; - i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1); - i->cntp = &intrcnt[i->cntindex]; - sprintf(intrname, "irq%u:", i->irq); - intrcnt_setname(intrname, i->cntindex); + snprintf(i->event->ie_fullname, sizeof(i->event->ie_fullname), + "irq%u:", i->irq); nvectors++; } mtx_unlock(&intr_table_lock); @@ -576,9 +565,6 @@ CPU_ZERO(&i->pi_cpuset); CPU_COPY(&cpuset_domain[domain], &i->pi_cpuset); } - mtx_lock(&intr_table_lock); - intrcnt_setname(i->event->ie_fullname, i->cntindex); - mtx_unlock(&intr_table_lock); if (!cold) { error = powerpc_map_irq(i); @@ -674,8 +660,6 @@ if (i == NULL) goto stray; - (*i->cntp)++; - ie = i->event; KASSERT(ie != NULL, ("%s: interrupt without an event", __func__)); @@ -727,3 +711,53 @@ PIC_UNMASK(i->pic, i->intline, i->priv); } + +/* + * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. + */ +static int +sysctl_intrnames(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_opaque(oidp, intrnames, sintrnames, req); + if (error != 0) + return (error); + + return (intr_event_sysctl_intrnames(oidp, intrnames, sintrnames, req)); +} + +SYSCTL_PROC(_hw, OID_AUTO, intrnames, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_intrnames, + "", "Interrupt Names"); + +static int +sysctl_intrcnt(SYSCTL_HANDLER_ARGS) +{ + int error = 0; +#ifdef SCTL_MASK32 + u_int idx; + uint32_t val32; + + if (req->flags & SCTL_MASK32) + for (idx = 0; idx <= sintrcnt / sizeof(u_long) ; ++idx) { + val32 = intrcnt[idx]; + error = SYSCTL_OUT(req, &val32, sizeof(val32)); + if (error != 0) + return (error); + } else +#endif + { + error = sysctl_handle_opaque(oidp, intrcnt, sintrcnt, req); + if (error != 0) + return (error); + } + + return (intr_event_sysctl_intrcnt(oidp, intrcnt, sintrcnt, req)); +} + +SYSCTL_PROC(_hw, OID_AUTO, intrcnt, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_intrcnt, + "", "Interrupt Counts"); diff --git a/sys/sys/interrupt.h b/sys/sys/interrupt.h --- a/sys/sys/interrupt.h +++ b/sys/sys/interrupt.h @@ -34,6 +34,7 @@ #include #include #include +#include struct intr_event; struct intr_thread; @@ -126,6 +127,8 @@ int ie_cpu; /* CPU this event is bound to. */ volatile int ie_phase; /* Switched to establish a barrier. */ volatile int ie_active[2]; /* Filters in ISR context. */ + u_long ie_stray; /* Stray interrupt counter */ + u_long ie_intrcnt; /* Interrupt counter */ }; /* Interrupt event flags kept in ie_flags. */ @@ -156,12 +159,6 @@ extern struct intr_event *clk_intr_event; -/* Counts and names for statistics (defined in MD code). */ -extern u_long *intrcnt; /* counts for each device and stray */ -extern char *intrnames; /* string table containing device names */ -extern size_t sintrcnt; /* size of intrcnt table */ -extern size_t sintrnames; /* size of intrnames table */ - #ifdef DDB void db_dump_intr_event(struct intr_event *ie, int handlers); #endif @@ -182,7 +179,7 @@ int intr_event_describe_handler(struct intr_event *ie, void *cookie, const char *descr); int intr_event_destroy(struct intr_event *ie); -int intr_event_handle(struct intr_event *ie, struct trapframe *frame); +u_long intr_event_handle(struct intr_event *ie, struct trapframe *frame); int intr_event_remove_handler(void *cookie); int intr_event_suspend_handler(void *cookie); int intr_event_resume_handler(void *cookie); @@ -196,4 +193,8 @@ void swi_sched(void *cookie, int flags); int swi_remove(void *cookie); +/* For handling the core interrupt counters and names */ +extern int intr_event_sysctl_intrnames(SYSCTL_HANDLER_ARGS); +extern int intr_event_sysctl_intrcnt(SYSCTL_HANDLER_ARGS); + #endif diff --git a/sys/sys/intr.h b/sys/sys/intr.h --- a/sys/sys/intr.h +++ b/sys/sys/intr.h @@ -104,8 +104,6 @@ u_int isrc_flags; char isrc_name[INTR_ISRC_NAMELEN]; cpuset_t isrc_cpu; /* on which CPUs is enabled */ - u_int isrc_index; - u_long * isrc_count; u_int isrc_handlers; struct intr_event * isrc_event; #ifdef INTR_SOLO diff --git a/sys/x86/include/intr.h b/sys/x86/include/intr.h --- a/sys/x86/include/intr.h +++ b/sys/x86/include/intr.h @@ -128,9 +128,6 @@ struct intsrc { struct pic *is_pic; struct intr_event *is_event; - u_long *is_count; - u_long *is_straycount; - u_int is_index; u_int is_handlers; u_int is_domain; u_int is_cpu; diff --git a/sys/x86/isa/atpic.c b/sys/x86/isa/atpic.c --- a/sys/x86/isa/atpic.c +++ b/sys/x86/isa/atpic.c @@ -131,8 +131,6 @@ inthand_t *at_intr, *at_intr_pti; int at_irq; /* Relative to PIC base. */ enum intr_trigger at_trigger; - u_long at_count; - u_long at_straycount; }; static void atpic_register_sources(struct pic *pic); @@ -464,8 +462,6 @@ for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) { if (i == ICU_SLAVEID) continue; - ai->at_intsrc.is_count = &ai->at_count; - ai->at_intsrc.is_straycount = &ai->at_straycount; setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase + ai->at_irq, pti ? ai->at_intr_pti : ai->at_intr, SDT_ATPIC, SEL_KPL, GSEL_ATPIC); diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c --- a/sys/x86/x86/intr_machdep.c +++ b/sys/x86/x86/intr_machdep.c @@ -76,7 +76,6 @@ typedef void (*mask_fn)(void *); -static int intrcnt_index; static struct intsrc **interrupt_sources; #ifdef SMP static struct intsrc **interrupt_sorted; @@ -97,9 +96,9 @@ u_long *intrcnt; char *intrnames; -size_t sintrcnt = sizeof(intrcnt); -size_t sintrnames = sizeof(intrnames); -int nintrcnt; +size_t sintrcnt; +size_t sintrnames; +u_int nintrcnt; static MALLOC_DEFINE(M_INTR, "intr", "Interrupt Sources"); @@ -108,8 +107,6 @@ static void intr_init(void *__dummy); static int intr_pic_registered(struct pic *pic); 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: @@ -176,13 +173,12 @@ #endif /* - * - 1 ??? dummy counter. * - 2 counters for each I/O interrupt. * - 1 counter for each CPU for lapic timer. * - 1 counter for each CPU for the Hyper-V vmbus driver. * - 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 if (mp_ncpus > 1) nintrcnt += 8 * mp_ncpus; @@ -191,11 +187,6 @@ M_ZERO); intrnames = mallocarray(nintrcnt, MAXCOMLEN + 1, M_INTR, M_WAITOK | M_ZERO); - sintrcnt = nintrcnt * sizeof(u_long); - sintrnames = nintrcnt * (MAXCOMLEN + 1); - - intrcnt_setname("???", 0); - intrcnt_index = 1; /* * NB: intrpic_lock is not held here to avoid LORs due to @@ -239,7 +230,6 @@ intr_event_destroy(isrc->is_event); return (EEXIST); } - intrcnt_register(isrc); interrupt_sources[vector] = isrc; isrc->is_handlers = 0; sx_xunlock(&intrsrc_lock); @@ -270,7 +260,6 @@ arg, intr_priority(flags), flags, cookiep); if (error == 0) { sx_xlock(&intrsrc_lock); - intrcnt_updatename(isrc); isrc->is_handlers++; if (isrc->is_handlers == 1) { isrc->is_domain = domain; @@ -297,7 +286,6 @@ isrc->is_pic->pic_disable_source(isrc, PIC_NO_EOI); isrc->is_pic->pic_disable_intr(isrc); } - intrcnt_updatename(isrc); sx_xunlock(&intrsrc_lock); } return (error); @@ -328,6 +316,7 @@ { struct intr_event *ie; int vector; + u_long strays; /* * We count software interrupts when we process them. The @@ -335,7 +324,6 @@ * argument for counting hardware interrupts when they're * processed too. */ - (*isrc->is_count)++; VM_CNT_INC(v_intr); ie = isrc->is_event; @@ -352,12 +340,11 @@ * For stray interrupts, mask and EOI the source, bump the * stray count, and log the condition. */ - if (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_straycount)++; - if (*isrc->is_straycount < INTR_STRAY_LOG_MAX) + if (strays < INTR_STRAY_LOG_MAX) log(LOG_ERR, "stray irq%d\n", vector); - else if (*isrc->is_straycount == INTR_STRAY_LOG_MAX) + else if (strays == INTR_STRAY_LOG_MAX) log(LOG_CRIT, "too many stray irq %d's: not logging anymore\n", vector); @@ -434,41 +421,16 @@ MAXCOMLEN, 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[MAXCOMLEN + 1]; - - KASSERT(is->is_event != NULL, ("%s: isrc with no event", __func__)); - mtx_lock_spin(&intrcnt_lock); - MPASS(intrcnt_index + 2 <= nintrcnt); - is->is_index = intrcnt_index; - intrcnt_index += 2; - snprintf(straystr, MAXCOMLEN + 1, "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 intrcnt_add(const char *name, u_long **countp) { mtx_lock_spin(&intrcnt_lock); - MPASS(intrcnt_index < nintrcnt); - *countp = &intrcnt[intrcnt_index]; - intrcnt_setname(name, intrcnt_index); - intrcnt_index++; + MPASS(sintrcnt < nintrcnt * sizeof(u_long)); + *countp = &intrcnt[sintrcnt / sizeof(u_long)]; + intrcnt_setname(name, sintrcnt / sizeof(u_long)); + sintrcnt += sizeof(u_long); + sintrnames += MAXCOMLEN + 1; mtx_unlock_spin(&intrcnt_lock); } @@ -525,16 +487,11 @@ intr_describe(u_int vector, void *ih, const char *descr) { struct intsrc *isrc; - int error; isrc = intr_lookup(vector); if (isrc == NULL) return (EINVAL); - error = intr_event_describe_handler(isrc->is_event, ih, descr); - if (error) - return (error); - intrcnt_updatename(isrc); - return (0); + return (intr_event_describe_handler(isrc->is_event, ih, descr)); } void @@ -735,12 +692,11 @@ isrc = interrupt_sources[i]; if (isrc == NULL) 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_index, isrc->is_cpu, isrc->is_domain, - *isrc->is_count); + isrc->is_event->ie_intrcnt); } sx_sunlock(&intrsrc_lock); @@ -751,7 +707,7 @@ SYSCTL_PROC(_hw, OID_AUTO, intrs, CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 0, sysctl_hw_intrs, "A", - "interrupt:number @cpu: count"); + "interrupt @cpu: count"); /* * Compare two, possibly NULL, entries in the interrupt source array @@ -765,7 +721,7 @@ i1 = *(const struct intsrc * const *)one; i2 = *(const struct intsrc * const *)two; if (i1 != NULL && i2 != NULL) - return (*i1->is_count - *i2->is_count); + return (i1->is_event->ie_intrcnt - i2->is_event->ie_intrcnt); if (i1 != NULL) return (1); if (i2 != NULL) @@ -845,3 +801,53 @@ return (PCPU_GET(apic_id)); } #endif + +/* + * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. + */ +static int +sysctl_intrnames(SYSCTL_HANDLER_ARGS) +{ + int error; + + error = sysctl_handle_opaque(oidp, intrnames, sintrnames, req); + if (error != 0) + return (error); + + return (intr_event_sysctl_intrnames(oidp, intrnames, sintrnames, req)); +} + +SYSCTL_PROC(_hw, OID_AUTO, intrnames, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_intrnames, + "", "Interrupt Names"); + +static int +sysctl_intrcnt(SYSCTL_HANDLER_ARGS) +{ + int error = 0; +#ifdef SCTL_MASK32 + u_int idx; + uint32_t val32; + + if (req->flags & SCTL_MASK32) + for (idx = 0; idx <= sintrcnt / sizeof(u_long) ; ++idx) { + val32 = intrcnt[idx]; + error = SYSCTL_OUT(req, &val32, sizeof(val32)); + if (error != 0) + return (error); + } else +#endif + { + error = sysctl_handle_opaque(oidp, intrcnt, sintrcnt, req); + if (error != 0) + return (error); + } + + return (intr_event_sysctl_intrcnt(oidp, intrcnt, sintrcnt, req)); +} + +SYSCTL_PROC(_hw, OID_AUTO, intrcnt, + CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0, + sysctl_intrcnt, + "", "Interrupt Counts");