#include <sys/thread2.h>
#include <sys/mplock2.h>
-struct info_info;
+struct intr_info;
typedef struct intrec {
struct intrec *next;
int i_state;
int i_errorticks;
unsigned long i_straycount;
-} intr_info_ary[MAX_INTS];
+ int i_cpuid;
+ int i_intr;
+};
+
+static struct intr_info intr_info_ary[MAXCPU][MAX_INTS];
+static struct intr_info *swi_info_ary[MAX_SOFTINTS];
static int max_installed_hard_intr[MAXCPU];
static void emergency_intr_timer_callback(systimer_t, int, struct intrframe *);
static void ithread_handler(void *arg);
static void ithread_emergency(void *arg);
-static void report_stray_interrupt(int intr, struct intr_info *info);
+static void report_stray_interrupt(struct intr_info *info, const char *func);
static void int_moveto_destcpu(int *, int);
static void int_moveto_origcpu(int, int);
-
-int intr_info_size = NELEM(intr_info_ary);
+static void sched_ithd_intern(struct intr_info *info);
static struct systimer emergency_intr_timer[MAXCPU];
static struct thread emergency_intr_thread[MAXCPU];
panic("register_int: bad intr %d", intr);
if (name == NULL)
name = "???";
- info = &intr_info_ary[intr];
+ info = &intr_info_ary[cpuid][intr];
/*
* Construct an interrupt handler record
if (emergency_intr_thread[cpuid].td_kstack == NULL) {
lwkt_create(ithread_emergency, NULL, NULL,
&emergency_intr_thread[cpuid],
- TDF_NOSTART | TDF_INTTHREAD, cpuid, "ithread emerg %d",
+ TDF_NOSTART | TDF_INTTHREAD, cpuid, "ithreadE %d",
cpuid);
systimer_init_periodic_nq(&emergency_intr_timer[cpuid],
emergency_intr_timer_callback,
info->i_state = ISTATE_NORMAL;
lwkt_create(ithread_handler, (void *)(intptr_t)intr, NULL,
&info->i_thread, TDF_NOSTART | TDF_INTTHREAD, cpuid,
- "ithread %d", intr);
+ "ithread%d %d", intr, cpuid);
if (intr >= FIRST_SOFTINT)
lwkt_setpri(&info->i_thread, TDPRI_SOFT_NORM);
else
max_installed_hard_intr[cpuid] = intr + 1;
}
+ if (intr >= FIRST_SOFTINT)
+ swi_info_ary[intr - FIRST_SOFTINT] = info;
+
/*
* Setup the machine level interrupt vector
*/
if (intr < 0 || intr >= MAX_INTS)
panic("register_int: bad intr %d", intr);
- info = &intr_info_ary[intr];
+ info = &intr_info_ary[cpuid][intr];
int_moveto_destcpu(&orig_cpuid, cpuid);
info->i_mplock_required = 0;
}
+ if (intr >= FIRST_SOFTINT && info->i_reclist == NULL)
+ swi_info_ary[intr - FIRST_SOFTINT] = NULL;
+
crit_exit();
int_moveto_origcpu(orig_cpuid, cpuid);
}
long
-get_interrupt_counter(int intr)
+get_interrupt_counter(int intr, int cpuid)
{
struct intr_info *info;
+ KKASSERT(cpuid >= 0 && cpuid < ncpus);
+
if (intr < 0 || intr >= MAX_INTS)
panic("register_int: bad intr %d", intr);
- info = &intr_info_ary[intr];
+ info = &intr_info_ary[cpuid][intr];
return(info->i_count);
}
register_randintr(int intr)
{
struct intr_info *info;
+ int cpuid;
if (intr < 0 || intr >= MAX_INTS)
panic("register_randintr: bad intr %d", intr);
- info = &intr_info_ary[intr];
- info->i_random.sc_intr = intr;
- info->i_random.sc_enabled = 1;
+
+ for (cpuid = 0; cpuid < ncpus; ++cpuid) {
+ info = &intr_info_ary[cpuid][intr];
+ info->i_random.sc_intr = intr;
+ info->i_random.sc_enabled = 1;
+ }
}
void
unregister_randintr(int intr)
{
struct intr_info *info;
+ int cpuid;
if (intr < 0 || intr >= MAX_INTS)
panic("register_swi: bad intr %d", intr);
- info = &intr_info_ary[intr];
- info->i_random.sc_enabled = -1;
+
+ for (cpuid = 0; cpuid < ncpus; ++cpuid) {
+ info = &intr_info_ary[cpuid][intr];
+ info->i_random.sc_enabled = -1;
+ }
}
int
if (intr < 0 || intr >= MAX_INTS)
panic("register_swi: bad intr %d", intr);
+
while (intr < MAX_INTS) {
- info = &intr_info_ary[intr];
- if (info->i_random.sc_enabled > 0)
- break;
+ int cpuid;
+
+ for (cpuid = 0; cpuid < ncpus; ++cpuid) {
+ info = &intr_info_ary[cpuid][intr];
+ if (info->i_random.sc_enabled > 0)
+ return intr;
+ }
++intr;
}
- return(intr);
+ return intr;
}
/*
static void
sched_ithd_remote(void *arg)
{
- sched_ithd((int)(intptr_t)arg);
+ sched_ithd_intern(arg);
}
#endif
-void
-sched_ithd(int intr)
+static void
+sched_ithd_intern(struct intr_info *info)
{
- struct intr_info *info;
-
- info = &intr_info_ary[intr];
-
++info->i_count;
if (info->i_state != ISTATE_NOTHREAD) {
if (info->i_reclist == NULL) {
- report_stray_interrupt(intr, info);
+ report_stray_interrupt(info, "sched_ithd");
} else {
#ifdef SMP
if (info->i_thread.td_gd == mycpu) {
lwkt_schedule(&info->i_thread); /* MIGHT PREEMPT */
}
} else {
- lwkt_send_ipiq(info->i_thread.td_gd,
- sched_ithd_remote, (void *)(intptr_t)intr);
+ lwkt_send_ipiq(info->i_thread.td_gd, sched_ithd_remote, info);
}
#else
if (info->i_running == 0) {
#endif
}
} else {
- report_stray_interrupt(intr, info);
+ report_stray_interrupt(info, "sched_ithd");
}
}
+void
+sched_ithd_soft(int intr)
+{
+ struct intr_info *info;
+
+ KKASSERT(intr >= FIRST_SOFTINT && intr < MAX_INTS);
+
+ info = swi_info_ary[intr - FIRST_SOFTINT];
+ if (info != NULL) {
+ sched_ithd_intern(info);
+ } else {
+ kprintf("unregistered softint %d got scheduled on cpu%d\n",
+ intr, mycpuid);
+ }
+}
+
+void
+sched_ithd_hard(int intr)
+{
+ KKASSERT(intr >= 0 && intr < MAX_HARDINTS);
+ sched_ithd_intern(&intr_info_ary[mycpuid][intr]);
+}
+
static void
-report_stray_interrupt(int intr, struct intr_info *info)
+report_stray_interrupt(struct intr_info *info, const char *func)
{
++info->i_straycount;
if (info->i_straycount < 10) {
if (info->i_errorticks == ticks)
return;
info->i_errorticks = ticks;
- kprintf("sched_ithd: stray interrupt %d on cpu %d\n",
- intr, mycpuid);
+ kprintf("%s: stray interrupt %d on cpu%d\n",
+ func, info->i_intr, mycpuid);
} else if (info->i_straycount == 10) {
- kprintf("sched_ithd: %ld stray interrupts %d on cpu %d - "
- "there will be no further reports\n",
- info->i_straycount, intr, mycpuid);
+ kprintf("%s: %ld stray interrupts %d on cpu%d - "
+ "there will be no further reports\n", func,
+ info->i_straycount, info->i_intr, mycpuid);
}
}
{
struct intr_info *info;
- info = &intr_info_ary[(int)(intptr_t)st->data];
+ info = &intr_info_ary[mycpuid][(int)(intptr_t)st->data];
if (info->i_state != ISTATE_NOTHREAD)
lwkt_schedule(&info->i_thread);
}
/*
* Schedule ithread within fast intr handler
*
- * XXX Protect sched_ithd() call with gd_intr_nesting_level?
+ * XXX Protect sched_ithd_hard() call with gd_intr_nesting_level?
* Interrupts aren't enabled, but still...
*/
static __inline void
* allow preemption.
*/
crit_exit_quick(td);
- sched_ithd(intr);
+ sched_ithd_hard(intr);
crit_enter_quick(td);
--td->td_nest_count;
/* We must be in critical section. */
KKASSERT(td->td_critcount);
- info = &intr_info_ary[intr];
+ info = &intr_info_ary[mycpuid][intr];
/*
* If we are not processing any FAST interrupts, just schedule the thing.
* The handler begins execution outside a critical section and no MP lock.
*
* The i_running state starts at 0. When an interrupt occurs, the hardware
- * interrupt is disabled and sched_ithd() The HW interrupt remains disabled
- * until all routines have run. We then call ithread_done() to reenable
- * the HW interrupt and deschedule us until the next interrupt.
+ * interrupt is disabled and sched_ithd_hard() The HW interrupt remains
+ * disabled until all routines have run. We then call ithread_done() to
+ * reenable the HW interrupt and deschedule us until the next interrupt.
*
* We are responsible for atomically checking i_running and ithread_done()
* is responsible for atomically checking for platform-specific delayed
struct intr_info *info;
int use_limit;
__uint32_t lseconds;
- int intr;
+ int intr, cpuid = mycpuid;
int mpheld;
struct intrec **list;
intrec_t rec, nrec;
ill_count = 0;
intr = (int)(intptr_t)arg;
- info = &intr_info_ary[intr];
+ info = &intr_info_ary[cpuid][intr];
list = &info->i_reclist;
/*
info->i_running = 0;
if (*list == NULL)
- report_stray_interrupt(intr, info);
+ report_stray_interrupt(info, "ithread_handler");
for (rec = *list; rec; rec = nrec) {
/* rec may be invalid after call */
* Otherwise we are livelocked. Set up a periodic systimer
* to wake the thread up at the limit frequency.
*/
- kprintf("intr %d at %d/%d hz, livelocked limit engaged!\n",
- intr, ill_count, livelock_limit);
+ kprintf("intr %d on cpu%d at %d/%d hz, livelocked limit engaged!\n",
+ intr, cpuid, ill_count, livelock_limit);
info->i_state = ISTATE_LIVELOCKED;
if ((use_limit = livelock_limit) < 100)
use_limit = 100;
if (ill_count < livelock_lowater) {
info->i_state = ISTATE_NORMAL;
systimer_del(&ill_timer);
- kprintf("intr %d at %d/%d hz, livelock removed\n",
- intr, ill_count, livelock_lowater);
+ kprintf("intr %d on cpu%d at %d/%d hz, livelock removed\n",
+ intr, cpuid, ill_count, livelock_lowater);
} else if (livelock_debug == intr ||
(bootverbose && cold)) {
- kprintf("intr %d at %d/%d hz, in livelock\n",
- intr, ill_count, livelock_lowater);
+ kprintf("intr %d on cpu%d at %d/%d hz, in livelock\n",
+ intr, cpuid, ill_count, livelock_lowater);
}
ill_count = 0;
}
for (;;) {
for (intr = 0; intr < max_installed_hard_intr[cpuid]; ++intr) {
- info = &intr_info_ary[intr];
+ info = &intr_info_ary[cpuid][intr];
for (rec = info->i_reclist; rec; rec = nrec) {
/* rec may be invalid after call */
nrec = rec->next;
int
ithread_cpuid(int intr)
{
- const struct intr_info *info;
-
- KKASSERT(intr >= 0 && intr < MAX_INTS);
- info = &intr_info_ary[intr];
-
- if (info->i_state == ISTATE_NOTHREAD)
- return -1;
- return info->i_thread.td_gd->gd_cpuid;
+ return machintr_intr_cpuid(intr);
}
/*
intrec_t rec;
int error = 0;
int len;
- int intr;
+ int intr, cpuid;
char buf[64];
- for (intr = 0; error == 0 && intr < MAX_INTS; ++intr) {
- info = &intr_info_ary[intr];
+ for (cpuid = 0; cpuid < ncpus; ++cpuid) {
+ for (intr = 0; error == 0 && intr < MAX_INTS; ++intr) {
+ info = &intr_info_ary[cpuid][intr];
- len = 0;
- buf[0] = 0;
- for (rec = info->i_reclist; rec; rec = rec->next) {
- ksnprintf(buf + len, sizeof(buf) - len, "%s%s",
- (len ? "/" : ""), rec->name);
- len += strlen(buf + len);
- }
- if (len == 0) {
- ksnprintf(buf, sizeof(buf), "irq%d", intr);
- len = strlen(buf);
+ len = 0;
+ buf[0] = 0;
+ for (rec = info->i_reclist; rec; rec = rec->next) {
+ ksnprintf(buf + len, sizeof(buf) - len, "%s%s",
+ (len ? "/" : ""), rec->name);
+ len += strlen(buf + len);
+ }
+ if (len == 0) {
+ ksnprintf(buf, sizeof(buf), "irq%d", intr);
+ len = strlen(buf);
+ }
+ error = SYSCTL_OUT(req, buf, len + 1);
}
- error = SYSCTL_OUT(req, buf, len + 1);
}
return (error);
}
-
SYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD,
NULL, 0, sysctl_intrnames, "", "Interrupt Names");
{
struct intr_info *info;
int error = 0;
- int intr;
+ int intr, cpuid;
- for (intr = 0; intr < MAX_INTS; ++intr) {
- info = &intr_info_ary[intr];
+ for (cpuid = 0; cpuid < ncpus; ++cpuid) {
+ for (intr = 0; intr < MAX_INTS; ++intr) {
+ info = &intr_info_ary[cpuid][intr];
- error = SYSCTL_OUT(req, &info->i_count, sizeof(info->i_count));
- if (error)
+ error = SYSCTL_OUT(req, &info->i_count, sizeof(info->i_count));
+ if (error)
goto failed;
+ }
}
failed:
return(error);
if (cpuid != orig_cpuid)
lwkt_migratecpu(orig_cpuid);
}
+
+static void
+intr_init(void *dummy __unused)
+{
+ int cpuid;
+
+ kprintf("Initialize MI interrupts\n");
+
+ for (cpuid = 0; cpuid < ncpus; ++cpuid) {
+ int intr;
+
+ for (intr = 0; intr < MAX_INTS; ++intr) {
+ struct intr_info *info = &intr_info_ary[cpuid][intr];
+
+ info->i_cpuid = cpuid;
+ info->i_intr = intr;
+ }
+ }
+}
+SYSINIT(intr_init, SI_BOOT2_FINISH_PIC, SI_ORDER_ANY, intr_init, NULL);