From owner-p4-projects@FreeBSD.ORG Tue Dec 12 01:47:02 2006 Return-Path: X-Original-To: p4-projects@freebsd.org Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 4726A16A47B; Tue, 12 Dec 2006 01:47:02 +0000 (UTC) X-Original-To: perforce@freebsd.org Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 1BF0816A412 for ; Tue, 12 Dec 2006 01:47:02 +0000 (UTC) (envelope-from piso@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [69.147.83.41]) by mx1.FreeBSD.org (Postfix) with ESMTP id 66D8E43CFA for ; Tue, 12 Dec 2006 01:43:07 +0000 (GMT) (envelope-from piso@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.13.6/8.13.6) with ESMTP id kBC1iICO062521 for ; Tue, 12 Dec 2006 01:44:18 GMT (envelope-from piso@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.13.6/8.13.4/Submit) id kBC1iI7A062518 for perforce@freebsd.org; Tue, 12 Dec 2006 01:44:18 GMT (envelope-from piso@freebsd.org) Date: Tue, 12 Dec 2006 01:44:18 GMT Message-Id: <200612120144.kBC1iI7A062518@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to piso@freebsd.org using -f From: Paolo Pisati To: Perforce Change Reviews Cc: Subject: PERFORCE change 111521 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Dec 2006 01:47:02 -0000 http://perforce.freebsd.org/chv.cgi?CH=111521 Change 111521 by piso@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 (; itd_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 (; iis_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 (; ievent != 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,