Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/subr_intr.c
Show First 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | |||||||||
#include <sys/interrupt.h> | #include <sys/interrupt.h> | ||||||||
#include <sys/taskqueue.h> | #include <sys/taskqueue.h> | ||||||||
#include <sys/tree.h> | #include <sys/tree.h> | ||||||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||||||
#include <sys/cpuset.h> | #include <sys/cpuset.h> | ||||||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||||||
#include <sys/sched.h> | #include <sys/sched.h> | ||||||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||||||
#include <sys/sysctl.h> | |||||||||
#include <sys/vmmeter.h> | #include <sys/vmmeter.h> | ||||||||
#ifdef HWPMC_HOOKS | #ifdef HWPMC_HOOKS | ||||||||
#include <sys/pmckern.h> | #include <sys/pmckern.h> | ||||||||
#endif | #endif | ||||||||
#include <machine/atomic.h> | #include <machine/atomic.h> | ||||||||
#include <machine/intr.h> | #include <machine/intr.h> | ||||||||
#include <machine/cpu.h> | #include <machine/cpu.h> | ||||||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | |||||||||
static struct mtx pic_list_lock; | static struct mtx pic_list_lock; | ||||||||
static SLIST_HEAD(, intr_pic) pic_list; | static SLIST_HEAD(, intr_pic) pic_list; | ||||||||
static struct intr_pic *pic_lookup(device_t dev, intptr_t xref, int flags); | static struct intr_pic *pic_lookup(device_t dev, intptr_t xref, int flags); | ||||||||
/* Interrupt source definition. */ | /* Interrupt source definition. */ | ||||||||
static struct mtx isrc_table_lock; | static struct mtx isrc_table_lock; | ||||||||
static struct intr_irqsrc *irq_sources[NIRQ]; | static struct intr_irqsrc **irq_sources; | ||||||||
size_t irq_sources_count; | |||||||||
u_int irq_next_free; | u_int irq_next_free; | ||||||||
#ifdef SMP | #ifdef SMP | ||||||||
#ifdef EARLY_AP_STARTUP | #ifdef EARLY_AP_STARTUP | ||||||||
static bool irq_assign_cpu = true; | static bool irq_assign_cpu = true; | ||||||||
#else | #else | ||||||||
static bool irq_assign_cpu = false; | static bool irq_assign_cpu = false; | ||||||||
#endif | #endif | ||||||||
#endif | #endif | ||||||||
/* | int intr_nirq = NIRQ; | ||||||||
mhorne: Since we are now sizing this dynamically, it would make more sense to do it based on `mp_ncpus`. | |||||||||
Done Inline ActionsFixed the constant. I'd like to leave mp_ncpus for another round of changes. gonzo: Fixed the constant. I'd like to leave mp_ncpus for another round of changes. | |||||||||
* - 2 counters for each I/O interrupt. | SYSCTL_UINT(_machdep, OID_AUTO, nirq, CTLFLAG_RDTUN, &intr_nirq, 0, | ||||||||
* - MAXCPU counters for each IPI counters for SMP. | "Number of IRQs"); | ||||||||
*/ | |||||||||
#ifdef SMP | |||||||||
#define INTRCNT_COUNT (NIRQ * 2 + INTR_IPI_COUNT * MAXCPU) | |||||||||
#else | |||||||||
#define INTRCNT_COUNT (NIRQ * 2) | |||||||||
#endif | |||||||||
/* Data for MI statistics reporting. */ | /* Data for MI statistics reporting. */ | ||||||||
Done Inline Actionsmachdep_ is an unusual prefix for a variable --- I don't think anything else is named that way. Maybe intr_nirq if not just nirq? mhorne: `machdep_` is an unusual prefix for a variable --- I don't think anything else is named that… | |||||||||
Done Inline ActionsFixed gonzo: Fixed | |||||||||
u_long intrcnt[INTRCNT_COUNT]; | u_long *intrcnt; | ||||||||
char intrnames[INTRCNT_COUNT * INTRNAME_LEN]; | char *intrnames; | ||||||||
size_t sintrcnt = sizeof(intrcnt); | size_t sintrcnt; | ||||||||
size_t sintrnames = sizeof(intrnames); | size_t sintrnames; | ||||||||
static u_int intrcnt_index; | static u_int intrcnt_index; | ||||||||
static struct intr_irqsrc *intr_map_get_isrc(u_int res_id); | 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); | static void intr_map_set_isrc(u_int res_id, struct intr_irqsrc *isrc); | ||||||||
static struct intr_map_data * intr_map_get_map_data(u_int res_id); | static struct intr_map_data * intr_map_get_map_data(u_int res_id); | ||||||||
static void intr_map_copy_map_data(u_int res_id, device_t *dev, intptr_t *xref, | static void intr_map_copy_map_data(u_int res_id, device_t *dev, intptr_t *xref, | ||||||||
struct intr_map_data **data); | struct intr_map_data **data); | ||||||||
/* | /* | ||||||||
* Interrupt framework initialization routine. | * Interrupt framework initialization routine. | ||||||||
*/ | */ | ||||||||
static void | static void | ||||||||
intr_irq_init(void *dummy __unused) | intr_irq_init(void *dummy __unused) | ||||||||
{ | { | ||||||||
int intrcnt_count; | |||||||||
SLIST_INIT(&pic_list); | SLIST_INIT(&pic_list); | ||||||||
mtx_init(&pic_list_lock, "intr pic list", NULL, MTX_DEF); | mtx_init(&pic_list_lock, "intr pic list", NULL, MTX_DEF); | ||||||||
mtx_init(&isrc_table_lock, "intr isrc table", NULL, MTX_DEF); | mtx_init(&isrc_table_lock, "intr isrc table", NULL, MTX_DEF); | ||||||||
/* | |||||||||
* - 2 counters for each I/O interrupt. | |||||||||
* - MAXCPU counters for each IPI counters for SMP. | |||||||||
*/ | |||||||||
intrcnt_count = intr_nirq * 2; | |||||||||
#ifdef SMP | |||||||||
intrcnt_count += INTR_IPI_COUNT * MAXCPU; | |||||||||
#endif | |||||||||
mhorneUnsubmitted Done Inline ActionsYou can drop the extra newline. mhorne: You can drop the extra newline. | |||||||||
intrcnt = mallocarray(intrcnt_count, sizeof(u_long), M_INTRNG, | |||||||||
M_WAITOK | M_ZERO); | |||||||||
intrnames = mallocarray(intrcnt_count, INTRNAME_LEN, M_INTRNG, | |||||||||
M_WAITOK | M_ZERO); | |||||||||
sintrcnt = intrcnt_count * sizeof(u_long); | |||||||||
sintrnames = intrcnt_count * INTRNAME_LEN; | |||||||||
irq_sources_count = intr_nirq; | |||||||||
irq_sources = mallocarray(irq_sources_count,sizeof(struct intr_irqsrc*), | |||||||||
M_INTRNG, M_WAITOK | M_ZERO); | |||||||||
} | } | ||||||||
SYSINIT(intr_irq_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_irq_init, NULL); | SYSINIT(intr_irq_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_irq_init, NULL); | ||||||||
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", | ||||||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | |||||||||
*/ | */ | ||||||||
static inline int | static inline int | ||||||||
isrc_alloc_irq(struct intr_irqsrc *isrc) | isrc_alloc_irq(struct intr_irqsrc *isrc) | ||||||||
{ | { | ||||||||
u_int maxirqs, irq; | u_int maxirqs, irq; | ||||||||
mtx_assert(&isrc_table_lock, MA_OWNED); | mtx_assert(&isrc_table_lock, MA_OWNED); | ||||||||
maxirqs = nitems(irq_sources); | maxirqs = intr_nirq; | ||||||||
Done Inline ActionsIs there a reason to use irq_sources_count rather than just machdep_nirq? mhorne: Is there a reason to use `irq_sources_count` rather than just `machdep_nirq`? | |||||||||
Done Inline ActionsJust an automatic renaming. Fixed. gonzo: Just an automatic renaming. Fixed. | |||||||||
Done Inline ActionsThanks, but it looks like irq_sources_count can be dropped altogether in favor of machdep_nirq. mhorne: Thanks, but it looks like `irq_sources_count` can be dropped altogether in favor of… | |||||||||
if (irq_next_free >= maxirqs) | if (irq_next_free >= maxirqs) | ||||||||
return (ENOSPC); | return (ENOSPC); | ||||||||
for (irq = irq_next_free; irq < maxirqs; irq++) { | for (irq = irq_next_free; irq < maxirqs; irq++) { | ||||||||
if (irq_sources[irq] == NULL) | if (irq_sources[irq] == NULL) | ||||||||
goto found; | goto found; | ||||||||
} | } | ||||||||
for (irq = 0; irq < irq_next_free; irq++) { | for (irq = 0; irq < irq_next_free; irq++) { | ||||||||
Show All 18 Lines | |||||||||
* Free unique interrupt number (resource handle) from interrupt source. | * Free unique interrupt number (resource handle) from interrupt source. | ||||||||
*/ | */ | ||||||||
static inline int | static inline int | ||||||||
isrc_free_irq(struct intr_irqsrc *isrc) | isrc_free_irq(struct intr_irqsrc *isrc) | ||||||||
{ | { | ||||||||
mtx_assert(&isrc_table_lock, MA_OWNED); | mtx_assert(&isrc_table_lock, MA_OWNED); | ||||||||
if (isrc->isrc_irq >= nitems(irq_sources)) | if (isrc->isrc_irq >= irq_sources_count) | ||||||||
return (EINVAL); | return (EINVAL); | ||||||||
if (irq_sources[isrc->isrc_irq] != isrc) | if (irq_sources[isrc->isrc_irq] != isrc) | ||||||||
return (EINVAL); | return (EINVAL); | ||||||||
irq_sources[isrc->isrc_irq] = NULL; | irq_sources[isrc->isrc_irq] = NULL; | ||||||||
isrc->isrc_irq = INTR_IRQ_INVALID; /* just to be safe */ | isrc->isrc_irq = INTR_IRQ_INVALID; /* just to be safe */ | ||||||||
return (0); | return (0); | ||||||||
} | } | ||||||||
▲ Show 20 Lines • Show All 786 Lines • ▼ Show 20 Lines | intr_irq_shuffle(void *arg __unused) | ||||||||
struct intr_irqsrc *isrc; | struct intr_irqsrc *isrc; | ||||||||
u_int i; | u_int i; | ||||||||
if (mp_ncpus == 1) | if (mp_ncpus == 1) | ||||||||
return; | return; | ||||||||
mtx_lock(&isrc_table_lock); | mtx_lock(&isrc_table_lock); | ||||||||
irq_assign_cpu = true; | irq_assign_cpu = true; | ||||||||
for (i = 0; i < NIRQ; i++) { | for (i = 0; i < intr_nirq; i++) { | ||||||||
isrc = irq_sources[i]; | isrc = irq_sources[i]; | ||||||||
if (isrc == NULL || isrc->isrc_handlers == 0 || | if (isrc == NULL || isrc->isrc_handlers == 0 || | ||||||||
isrc->isrc_flags & (INTR_ISRCF_PPI | INTR_ISRCF_IPI)) | isrc->isrc_flags & (INTR_ISRCF_PPI | INTR_ISRCF_IPI)) | ||||||||
continue; | continue; | ||||||||
if (isrc->isrc_event != NULL && | if (isrc->isrc_event != NULL && | ||||||||
isrc->isrc_flags & INTR_ISRCF_BOUND && | isrc->isrc_flags & INTR_ISRCF_BOUND && | ||||||||
isrc->isrc_event->ie_cpu != CPU_FFS(&isrc->isrc_cpu) - 1) | isrc->isrc_event->ie_cpu != CPU_FFS(&isrc->isrc_cpu) - 1) | ||||||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | |||||||||
#ifdef DDB | #ifdef DDB | ||||||||
DB_SHOW_COMMAND(irqs, db_show_irqs) | DB_SHOW_COMMAND(irqs, db_show_irqs) | ||||||||
{ | { | ||||||||
u_int i, irqsum; | u_int i, irqsum; | ||||||||
u_long num; | u_long num; | ||||||||
struct intr_irqsrc *isrc; | struct intr_irqsrc *isrc; | ||||||||
for (irqsum = 0, i = 0; i < NIRQ; i++) { | for (irqsum = 0, i = 0; i < intr_nirq; i++) { | ||||||||
isrc = irq_sources[i]; | isrc = irq_sources[i]; | ||||||||
if (isrc == NULL) | if (isrc == NULL) | ||||||||
continue; | continue; | ||||||||
num = isrc->isrc_count != NULL ? isrc->isrc_count[0] : 0; | num = isrc->isrc_count != NULL ? isrc->isrc_count[0] : 0; | ||||||||
db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i, | db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i, | ||||||||
isrc->isrc_name, isrc->isrc_cpu.__bits[0], | isrc->isrc_name, isrc->isrc_cpu.__bits[0], | ||||||||
isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", num); | isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", num); | ||||||||
Show All 15 Lines | struct intr_map_entry | ||||||||
intptr_t xref; | intptr_t xref; | ||||||||
struct intr_map_data *map_data; | struct intr_map_data *map_data; | ||||||||
struct intr_irqsrc *isrc; | struct intr_irqsrc *isrc; | ||||||||
/* XXX TODO DISCONECTED PICs */ | /* XXX TODO DISCONECTED PICs */ | ||||||||
/*int flags */ | /*int flags */ | ||||||||
}; | }; | ||||||||
/* XXX Convert irq_map[] to dynamicaly expandable one. */ | /* XXX Convert irq_map[] to dynamicaly expandable one. */ | ||||||||
static struct intr_map_entry *irq_map[2 * NIRQ]; | static struct intr_map_entry **irq_map; | ||||||||
static int irq_map_count = nitems(irq_map); | static int irq_map_count; | ||||||||
static int irq_map_first_free_idx; | static int irq_map_first_free_idx; | ||||||||
static struct mtx irq_map_lock; | static struct mtx irq_map_lock; | ||||||||
static struct intr_irqsrc * | static struct intr_irqsrc * | ||||||||
intr_map_get_isrc(u_int res_id) | intr_map_get_isrc(u_int res_id) | ||||||||
{ | { | ||||||||
struct intr_irqsrc *isrc; | struct intr_irqsrc *isrc; | ||||||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | intr_map_clone_irq(u_int old_res_id) | ||||||||
return (intr_map_irq(map_dev, map_xref, data)); | return (intr_map_irq(map_dev, map_xref, data)); | ||||||||
} | } | ||||||||
static void | static void | ||||||||
intr_map_init(void *dummy __unused) | intr_map_init(void *dummy __unused) | ||||||||
{ | { | ||||||||
mtx_init(&irq_map_lock, "intr map table", NULL, MTX_DEF); | mtx_init(&irq_map_lock, "intr map table", NULL, MTX_DEF); | ||||||||
irq_map_count = 2 * intr_nirq; | |||||||||
irq_map = mallocarray(irq_map_count, sizeof(struct intr_map_entry*), | |||||||||
Done Inline Actions
Could push M_WAITOK to the next line if it becomes too long. mhorne: Could push M_WAITOK to the next line if it becomes too long. | |||||||||
M_INTRNG, M_WAITOK | M_ZERO); | |||||||||
} | } | ||||||||
SYSINIT(intr_map_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_map_init, NULL); | SYSINIT(intr_map_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_map_init, NULL); |
Since we are now sizing this dynamically, it would make more sense to do it based on mp_ncpus. You might also drop this constant and just inline it in intr_irq_init(), since it is not used elsewhere.