PERFORCE change 111521 for review
Paolo Pisati
piso at FreeBSD.org
Mon Dec 11 17:47:02 PST 2006
http://perforce.freebsd.org/chv.cgi?CH=111521
Change 111521 by piso at piso_newluxor on 2006/12/12 01:43:55
Turn the main MD interrupt handling function
(i.e. for i386 intr_machdep.c::intr_execute_handlers())
into MI code (kern_intr.c::mi_handle_intr()).
Compiles for: amd64, i386, ia64, powerpc, sparc64.
Tested on: i386.
MIA: arm and sun4v.
Affected files ...
.. //depot/projects/soc2006/intr_filter/amd64/amd64/intr_machdep.c#11 edit
.. //depot/projects/soc2006/intr_filter/arm/arm/intr.c#8 edit
.. //depot/projects/soc2006/intr_filter/i386/i386/intr_machdep.c#17 edit
.. //depot/projects/soc2006/intr_filter/ia64/ia64/interrupt.c#10 edit
.. //depot/projects/soc2006/intr_filter/kern/kern_intr.c#19 edit
.. //depot/projects/soc2006/intr_filter/powerpc/powerpc/intr_machdep.c#13 edit
.. //depot/projects/soc2006/intr_filter/sparc64/sparc64/intr_machdep.c#11 edit
.. //depot/projects/soc2006/intr_filter/sys/interrupt.h#8 edit
Differences ...
==== //depot/projects/soc2006/intr_filter/amd64/amd64/intr_machdep.c#11 (text+ko) ====
@@ -76,6 +76,10 @@
extern struct callout stray_callout_handle;
+static void intr_eoi_src(void *arg);
+static void intr_disab_eoi_src(void *arg);
+void intr_callout_reset(void);
+
#ifdef SMP
static int assign_cpu;
@@ -234,11 +238,20 @@
}
void
+intr_callout_reset(void)
+{
+
+ mtx_lock_spin(&intr_table_lock);
+ callout_reset(&stray_callout_handle, hz, &stray_detection, &walk_intr_src);
+ mtx_unlock_spin(&intr_table_lock);
+}
+
+void
intr_execute_handlers(struct intsrc *isrc, struct trapframe *frame)
{
struct thread *td;
struct intr_event *ie;
- int error, vector, thread;
+ int res, vector;
td = curthread;
@@ -261,11 +274,20 @@
if (vector == 0)
clkintr_pending = 1;
- /*
- * For stray interrupts, mask and EOI the source, bump the
- * stray count, and log the condition.
- */
- if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers)) {
+ res = mi_handle_intr(ie, frame, intr_eoi_src, intr_disab_eoi_src, isrc);
+ switch(res) {
+ case 0:
+ /* FALLTHROUGH */
+ case ECHILD:
+ break;
+ case EFAULT:
+ panic("Bad stray interrupt\n");
+ break;
+ case EINVAL:
+ /*
+ * For stray interrupts, mask and EOI the source, bump the
+ * stray count, and log the condition.
+ */
isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
(*isrc->is_straycount)++;
if (*isrc->is_straycount < MAX_STRAY_LOG)
@@ -274,47 +296,29 @@
log(LOG_CRIT,
"too many stray irq %d's: not logging anymore\n",
vector);
- return;
+ break;
+ default:
+ printf("Ouch! Return code from mi_handle_intr()"
+ "not expected.\n");
}
+}
- /*
- * Execute fast interrupt handlers directly.
- * To support clock handlers, if a handler registers
- * with a NULL argument, then we pass it a pointer to
- * a trapframe as its argument.
- */
- td->td_intr_nesting_level++;
- thread = 0;
- critical_enter();
- thread = intr_filter_loop(ie, frame);
+static void
+intr_eoi_src(void *arg)
+{
+ struct intsrc *isrc;
- /*
- * If the interrupt was fully served, send it an EOI but leave it
- * unmasked. Otherwise, if there are any threaded handlers that need
- * to run or it was a stray interrupt, mask the source as well as
- * sending it an EOI.
- */
- if (thread & FILTER_HANDLED)
- isrc->is_pic->pic_eoi_source(isrc);
- else
- isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
- critical_exit();
+ isrc = arg;
+ isrc->is_pic->pic_eoi_source(isrc);
+}
- /* Interrupt storm logic */
- if (thread & FILTER_STRAY) {
- printf("Interrupt stray detected on \"%s\"; throttling interrupt source\n", ie->ie_name);
- ie->ie_count = INT_MAX;
- mtx_lock_spin(&intr_table_lock);
- callout_reset(&stray_callout_handle, hz, &stray_detection, &walk_intr_src);
- mtx_unlock_spin(&intr_table_lock);
- }
+static void
+intr_disab_eoi_src(void *arg)
+{
+ struct intsrc *isrc;
- /* Schedule the ithread if needed. */
- if (thread & FILTER_SCHEDULE_THREAD) {
- error = intr_event_schedule_thread(ie);
- KASSERT(error == 0, ("bad stray interrupt"));
- }
- td->td_intr_nesting_level--;
+ isrc = arg;
+ isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
}
void
==== //depot/projects/soc2006/intr_filter/arm/arm/intr.c#8 (text+ko) ====
@@ -102,11 +102,11 @@
/* Stray detection MD code */
static struct intr_event *
-walk_intr_events(void) {
+walk_intrs_events(void) {
struct intr_event *ie;
static int i = 0;
- for (; i<NIRQ; ) {
+ for (; i < NIRQ; ) {
int j = i++;
ie = intr_events[j];
if (ie != NULL)
@@ -121,39 +121,37 @@
{
struct intr_event *event;
struct thread *td = curthread;
- int i, thread;
+ int i, thread, res;
PCPU_LAZY_INC(cnt.v_intr);
- td->td_intr_nesting_level++;
while ((i = arm_get_next_irq()) != -1) {
arm_mask_irq(i);
intrcnt[intrcnt_tab[i]]++;
event = intr_events[i];
- if (!event || TAILQ_EMPTY(&event->ie_handlers))
- continue;
-
- /* Execute fast handlers. */
- thread = intr_filter_loop(event, frame);
-
- /* Interrupt storm logic */
- if (thread & FILTER_STRAY) {
- if (event->ie_enable == NULL || event->ie_pending == NULL)
- printf("Interrupt stray detection not ready yet: check ie_enable and ie_pending\n");
- else {
- printf("Interrupt stray detected on \"%s\"; throttling interrupt source\n", event->ie_name);
- event->ie_count = INT_MAX;
- // XXX missing callout_init_mtx(&stray_callout_handle, ...);
- callout_reset(&stray_callout_handle, hz,
- &stray_detection, &walk_intr_events);
- }
- }
-
- // XXX eoi & mask intr not verified.
- /* Schedule thread if needed. */
- if (thread & FILTER_SCHEDULE_THREAD)
- intr_event_schedule_thread(event);
- else
+ res = mi_handle_intr(event, frame, intr_eoi_src_stub,
+ intr_disab_eoi_src_stub, NULL);
+ switch (res) {
+ case 0:
+ break;
+ case ECHILD:
arm_unmask_irq(i);
+ break;
+ case EFAULT:
+ /* FALLTHROUGH */
+ case EINVAL:
+ break;
+ default:
+ printf("Ouch! Return code from mi_handle_intr()"
+ "not expected.\n");
+ }
}
- td->td_intr_nesting_level--;
+}
+
+void
+intr_callout_reset(void)
+{
+
+ // XXX missing callout_init_mtx(&stray_callout_handle, ...);
+ callout_reset(&stray_callout_handle, hz,
+ &stray_detection, &walk_intrs_events);
}
==== //depot/projects/soc2006/intr_filter/i386/i386/intr_machdep.c#17 (text+ko) ====
@@ -67,6 +67,10 @@
extern struct callout stray_callout_handle;
+static void intr_eoi_src(void *arg);
+static void intr_disab_eoi_src(void *arg);
+void intr_callout_reset(void);
+
#ifdef SMP
static int assign_cpu;
@@ -216,11 +220,11 @@
/* Stray detection MD code */
static struct intr_event *
-walk_intr_src(void) {
+walk_intrs_src(void) {
struct intsrc *isrc;
static int i = 0;
- for (; i<NUM_IO_INTS; ) {
+ for (; i < NUM_IO_INTS; ) {
int j = i++;
isrc = interrupt_sources[j];
if (isrc != NULL && isrc->is_event != NULL)
@@ -235,8 +239,7 @@
{
struct thread *td;
struct intr_event *ie;
- struct intr_thread *ithd = NULL;
- int error, vector, thread;
+ int res, vector;
td = curthread;
@@ -259,11 +262,20 @@
if (vector == 0)
clkintr_pending = 1;
- /*
- * For stray interrupts, mask and EOI the source, bump the
- * stray count, and log the condition.
- */
- if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers)) {
+ res = mi_handle_intr(ie, frame, intr_eoi_src, intr_disab_eoi_src, isrc);
+ switch(res) {
+ case 0:
+ /* FALLTHROUGH */
+ case ECHILD:
+ break;
+ case EFAULT:
+ panic("Bad stray interrupt\n");
+ break;
+ case EINVAL:
+ /*
+ * For stray interrupts, mask and EOI the source, bump the
+ * stray count, and log the condition.
+ */
isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
(*isrc->is_straycount)++;
if (*isrc->is_straycount < MAX_STRAY_LOG)
@@ -272,40 +284,39 @@
log(LOG_CRIT,
"too many stray irq %d's: not logging anymore\n",
vector);
- return;
+ break;
+ default:
+ printf("Ouch! Return code from mi_handle_intr()"
+ "not expected.\n");
}
+}
+
+void
+intr_callout_reset(void)
+{
+
+ mtx_lock_spin(&intr_table_lock);
+ callout_reset(&stray_callout_handle, hz,
+ &stray_detection, &walk_intrs_src);
+ mtx_unlock_spin(&intr_table_lock);
+}
- td->td_intr_nesting_level++;
- thread = 0;
- critical_enter();
- thread = intr_filter_loop(ie, frame, &ithd);
-
- /*
- * If the interrupt was fully served, send it an EOI but leave it
- * unmasked. Otherwise, if it was a stray interrupt, mask the source
- * as well as sending it an EOI.
- */
- if (thread & FILTER_HANDLED)
- isrc->is_pic->pic_eoi_source(isrc);
- else
- isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
- critical_exit();
-
- /* Interrupt storm logic */
- if (thread & FILTER_STRAY) {
- printf("Interrupt stray detected on \"%s\"; throttling interrupt source\n", ie->ie_name);
- ie->ie_count = INT_MAX;
- mtx_lock_spin(&intr_table_lock);
- callout_reset(&stray_callout_handle, hz, &stray_detection, &walk_intr_src);
- mtx_unlock_spin(&intr_table_lock);
- }
+static void
+intr_eoi_src(void *arg)
+{
+ struct intsrc *isrc;
+
+ isrc = arg;
+ isrc->is_pic->pic_eoi_source(isrc);
+}
+
+static void
+intr_disab_eoi_src(void *arg)
+{
+ struct intsrc *isrc;
- /* Schedule an ithread if needed. */
- if (thread & FILTER_SCHEDULE_THREAD) {
- error = intr_event_schedule_thread(ie, ithd);
- KASSERT(error == 0, ("bad stray interrupt"));
- }
- td->td_intr_nesting_level--;
+ isrc = arg;
+ isrc->is_pic->pic_disable_source(isrc, PIC_EOI);
}
void
==== //depot/projects/soc2006/intr_filter/ia64/ia64/interrupt.c#10 (text+ko) ====
@@ -262,6 +262,8 @@
extern struct callout stray_callout_handle;
+void intr_callout_reset(void);
+
extern struct sapic *ia64_sapics[];
extern int ia64_sapic_count;
@@ -358,7 +360,7 @@
struct ia64_intr *ia64_i;
static int i = 0;
- for (; i<IA64_NUMI; ) {
+ for (; i < IA64_NUMI; ) {
int j = i++;
ia64_i = ia64_intrs[j];
if (ia64_i != NULL && ia64_i->event != NULL)
@@ -369,11 +371,20 @@
}
void
-ia64_dispatch_intr(void *frame __unused, unsigned long vector)
+intr_callout_reset(void)
+{
+
+ mtx_lock_spin(&ia64_intrs_lock);
+ callout_reset(&stray_callout_handle, hz,
+ &stray_detection, &walk_intr_ia64);
+ mtx_unlock_spin(&ia64_intrs_lock);
+}
+
+void
+ia64_dispatch_intr(void *frame, unsigned long vector)
{
struct ia64_intr *i;
- struct intr_event *ie; /* our interrupt event */
- int error, thread;
+ int res;
/*
* Find the interrupt thread for this vector.
@@ -385,45 +396,24 @@
if (i->cntp)
atomic_add_long(i->cntp, 1);
- ie = i->event;
- KASSERT(ie != NULL, ("interrupt vector without an event"));
-
- /*
- * As an optimization, if an event has no handlers, don't
- * schedule it to run.
- */
- if (TAILQ_EMPTY(&ie->ie_handlers))
- return;
-
- /*
- * Execute all fast interrupt handlers directly without Giant. Note
- * that this means that any fast interrupt handler must be MP safe.
- */
- thread = 0;
- critical_enter();
- thread = intr_filter_loop(ie, NULL);
- critical_exit();
-
- /* Interrupt storm logic */
- if (thread & FILTER_STRAY) {
- if (ie->ie_enable == NULL || ie->ie_pending == NULL)
- printf("Interrupt stray detection not ready yet: check ie_enable and ie_pending\n");
- else {
- printf("Interrupt stray detected on \"%s\"; throttling interrupt source\n", ie->ie_name);
- ie->ie_count = INT_MAX;
- mtx_lock_spin(&ia64_intrs_lock);
- callout_reset(&stray_callout_handle, hz,
- &stray_detection, &walk_intr_ia64);
- mtx_unlock_spin(&ia64_intrs_lock);
- }
- }
-
- // XXX eoi & mask intr not verified.
- if (thread & FILTER_SCHEDULE_THREAD) {
- error = intr_event_schedule_thread(ie);
- KASSERT(error == 0, ("got an impossible stray interrupt"));
- } else
+ res = mi_handle_intr(i->event, frame, intr_eoi_src_stub,
+ intr_disab_eoi_src_stub, NULL);
+ switch (res) {
+ case 0:
+ break;
+ case ECHILD:
ia64_send_eoi(vector);
+ break;
+ case EFAULT:
+ panic("Got an impossible stray interrupt\n");
+ break;
+ case EINVAL:
+ panic("Interrupt vector without an event\n");
+ break;
+ default:
+ printf("Ouch! Return code from mi_handle_intr()"
+ "not expected.\n");
+ }
}
#ifdef DDB
==== //depot/projects/soc2006/intr_filter/kern/kern_intr.c#19 (text+ko) ====
@@ -62,6 +62,9 @@
struct callout stray_callout_handle;
static int backoff = 1;
+/* MD function */
+extern void intr_callout_reset(void);
+
/*
* Describe an interrupt thread. There is one of these per interrupt event.
*/
@@ -877,7 +880,7 @@
}
KASSERT(ret != FILTER_SCHEDULE_THREAD,
- "intr_filter_loop: FILTER_SCHEDULE_THREAD from filter");
+ ("intr_filter_loop: FILTER_SCHEDULE_THREAD from filter"));
if (ret & FILTER_STRAY)
continue;
@@ -939,6 +942,109 @@
}
}
+/*
+ * To avoid code duplication across different archs, use these functions
+ * for interrupt eoiing and disabling when you don't actually need to do
+ * any real action on the interrupt controller.
+ */
+void
+intr_eoi_src_stub(void *arg __unused)
+{
+ ;
+}
+
+void
+intr_disab_eoi_src_stub(void *arg __unused)
+{
+ ;
+}
+
+/*
+ * Main interrupt handling body.
+ *
+ * Input:
+ * o ie: the event connected to this interrupt.
+ * o frame: some archs (i.e. i386) pass a frame to some.
+ * handlers as their main argument.
+ * o intr_eoi_src(): turn off an irq.
+ * o intr_disab_eoi_src(): mask and turn off an irq.
+ * o arg: struct intsrc passed to the 2 previous
+ * intr_*_src() functions or NULL.
+ *
+ * NOTA BENE: i386 and amd64 handle their
+ * interrupt controllers through the
+ * intr_*_src() functions, so they are
+ * defined in the MD code for these archs.
+ * All the other archs (arm, ia64,
+ * powerpc, sparc64, etcetc) that don't
+ * use these facilities, will pass a NULL
+ * pointer for arg, and use the stub
+ * functions intr_eoi_src_stub() for
+ * intr_eoi_src() and
+ * intr_disab_eoi_src_stub() for
+ * intr_disab_eoi_src().
+ *
+ * Return value:
+ * o 0: everything ok.
+ * o EINVAL: stray interrupt.
+ * o ECHILD: no ithread scheduled.
+ * o EFAULT: something went wrong with ithread scheduling.
+ */
+int
+mi_handle_intr(struct intr_event *ie, struct trapframe *frame,
+ void (*intr_eoi_src)(void *),
+ void (*intr_disab_eoi_src)(void *), void *arg)
+{
+ struct intr_thread *ithd;
+ struct thread *td;
+ int error, res, thread;
+
+ ithd = NULL;
+ res = 0;
+ td = curthread;
+
+ if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers))
+ return (EINVAL);
+
+ td->td_intr_nesting_level++;
+ thread = 0;
+ critical_enter();
+ thread = intr_filter_loop(ie, frame, &ithd);
+
+ /*
+ * If the interrupt was fully served, send it an EOI but leave
+ * it unmasked. Otherwise, mask the source as well as sending
+ * it an EOI.
+ */
+ if (thread & FILTER_HANDLED)
+ intr_eoi_src(arg);
+ else
+ intr_disab_eoi_src(arg);
+ critical_exit();
+
+ /* Interrupt storm logic */
+ if (thread & FILTER_STRAY) {
+ if (ie->ie_enable == NULL || ie->ie_pending == NULL)
+ printf("Interrupt stray detection not present:"
+ "check ie_enable and ie_pending\n");
+ else {
+ printf("Interrupt stray detected on \"%s\";"
+ "throttling interrupt source\n", ie->ie_name);
+ ie->ie_count = INT_MAX;
+ intr_callout_reset();
+ }
+ }
+
+ /* Schedule an ithread if needed. */
+ if (thread & FILTER_SCHEDULE_THREAD) {
+ error = intr_event_schedule_thread(ie, ithd);
+ res = (error == 0) ? 0 : EFAULT;
+ } else
+ res = ECHILD;
+ td->td_intr_nesting_level--;
+ return (res);
+}
+
#ifdef DDB
/*
* Dump details about an interrupt handler
==== //depot/projects/soc2006/intr_filter/powerpc/powerpc/intr_machdep.c#13 (text+ko) ====
@@ -91,6 +91,8 @@
extern struct callout stray_callout_handle;
+void intr_callout_reset(void);
+
extern int extint, extsize;
extern u_long extint_call;
@@ -241,45 +243,39 @@
}
void
+intr_callout_reset(void)
+{
+
+ mtx_lock_spin(&intr_table_lock);
+ callout_reset(&stray_callout_handle, hz,
+ &stray_detection, &walk_intr_ppc);
+ mtx_unlock_spin(&intr_table_lock);
+}
+
+void
intr_handle(u_int irq)
{
struct ppc_intr_handler *ppc_ih = &intr_handlers[irq];
struct intr_event *ie = ppc_ih->ih_event;
- int error, thread;
+ int res;
- if (ie == NULL) {
+ res = mi_handle_intr(ie, NULL, intr_eoi_src_stub,
+ intr_disab_eoi_src_stub, NULL);
+ switch (res) {
+ case 0:
+ /* FALLTHROUGH */
+ case ECHILD:
+ atomic_add_long(ppc_ih->ih_count, 1);
+ break;
+ case EFAULT:
+ atomic_add_long(ppc_ih->ih_count, 1);
+ /* FALLTHROUGH */
+ case EINVAL:
intr_stray_handler(ppc_ih);
- return;
- }
-
- atomic_add_long(ppc_ih->ih_count, 1);
-
- critical_enter();
- /* Execute fast interrupt handlers directly. */
- thread = 0;
- thread = intr_filter_loop(ie, NULL);
- critical_exit();
-
- /* Interrupt storm logic */
- if (thread & FILTER_STRAY) {
- if (ie->ie_enable == NULL || ie->ie_pending == NULL)
- printf("Interrupt stray detection not ready yet: check ie_enable and ie_pending\n");
- else {
- printf("Interrupt stray detected on \"%s\"; throttling interrupt source\n", ie->ie_name);
- ie->ie_count = INT_MAX;
- mtx_lock_spin(&intr_table_lock);
- callout_reset(&stray_callout_handle, hz,
- &stray_detection, &walk_intr_ppc);
- mtx_unlock_spin(&intr_table_lock);
- }
- }
-
- // XXX eoi & mask intr not verified.
- /* Schedule a heavyweight interrupt process. */
- if (thread & FILTER_SCHEDULE_THREAD) {
- error = intr_event_schedule_thread(ie);
- if (error == EINVAL)
- intr_stray_handler(ppc_ih);
+ break;
+ default:
+ printf("Ouch! Return code from mi_handle_intr()"
+ "not expected.\n");
}
}
==== //depot/projects/soc2006/intr_filter/sparc64/sparc64/intr_machdep.c#11 (text+ko) ====
@@ -107,6 +107,8 @@
extern struct callout stray_callout_handle;
+void intr_callout_reset(void);
+
static void intr_execute_handlers(void *);
static void intr_stray_level(struct trapframe *);
static void intr_stray_vector(void *);
@@ -251,44 +253,41 @@
return (NULL);
}
+void
+intr_callout_reset(void)
+{
+
+ mtx_lock_spin(&intr_table_lock);
+ callout_reset(&stray_callout_handle, hz,
+ &stray_detection, &walk_intr_sparc64);
+ mtx_unlock_spin(&intr_table_lock);
+}
+
static void
intr_execute_handlers(void *cookie)
{
struct intr_vector *iv;
struct intr_event *ie;
- int error = 0, thread;
+ int res;
iv = cookie;
ie = iv->iv_event;
- if (ie == NULL || TAILQ_EMPTY(&ie->ie_handlers)) {
+ res = mi_handle_intr(ie, NULL, intr_eoi_src_stub, intr_disab_eoi_src_stub,
+ NULL);
+ switch (res) {
+ case 0:
+ /* FALLTHROUGH */
+ case ECHILD:
+ break;
+ case EFAULT:
+ /* FALLTHROUGH */
+ case EINVAL:
intr_stray_vector(iv);
- return;
+ break;
+ default:
+ printf("Ouch! Return code from mi_handle_intr()"
+ "not expected.\n");
}
-
- /* Execute fast interrupt handlers directly. */
- thread = intr_filter_loop(ie, NULL);
-
- /* Interrupt storm logic */
- if (thread & FILTER_STRAY) {
- if (ie->ie_enable == NULL || ie->ie_pending == NULL)
- printf("Interrupt stray detection not ready yet: check ie_enable and ie_pending\n");
- else {
- printf("Interrupt stray detected on \"%s\"; throttling interrupt source\n", ie->ie_name);
- ie->ie_count = INT_MAX;
- mtx_lock_spin(&intr_table_lock);
- callout_reset(&stray_callout_handle, hz,
- &stray_detection, &walk_intr_sparc64);
- mtx_unlock_spin(&intr_table_lock);
- }
- }
-
- // XXX eoi & mask intr not verified.
- /* Schedule a heavyweight interrupt process. */
- if (thread & FILTER_SCHEDULE_THREAD)
- error = intr_event_schedule_thread(ie);
-
- if (error == EINVAL)
- intr_stray_vector(iv);
}
int
==== //depot/projects/soc2006/intr_filter/sys/interrupt.h#8 (text+ko) ====
@@ -119,6 +119,11 @@
int intr_filter_loop(struct intr_event *ie, struct trapframe *frame,
struct intr_thread **ithd);
void stray_detection(void *_arg);
+void intr_eoi_src_stub(void *arg __unused);
+void intr_disab_eoi_src_stub(void *arg __unused);
+int mi_handle_intr(struct intr_event *ie, struct trapframe *frame,
+ void (*intr_eoi_src)(void *),
+ void (*intr_disab_eoi_src)(void *), void *arg);
u_char intr_priority(enum intr_type flags);
int intr_event_add_handler(struct intr_event *ie, const char *name,
driver_filter_t filter, driver_intr_t handler, void *arg, u_char pri, enum intr_type flags,
More information about the p4-projects
mailing list