From 77a08c68e82ceac8facad0be7cbd59ab471ecb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 30 Apr 2006 13:56:21 +0000 Subject: [PATCH] Changed the way handlers for edge triggered interrupt are called: now, we always call all handlers in this case, but we still try to return the correct return code (ie. B_HANDLED_INTERRUPT and B_INVOKE_SCHEDULER). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17278 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/int.h | 4 +- src/system/kernel/arch/ppc/arch_int.cpp | 6 +- src/system/kernel/arch/x86/arch_int.c | 9 ++- src/system/kernel/int.c | 76 ++++++++++--------------- 4 files changed, 43 insertions(+), 52 deletions(-) diff --git a/headers/private/kernel/int.h b/headers/private/kernel/int.h index 133b5dd68c..5d19166cf0 100644 --- a/headers/private/kernel/int.h +++ b/headers/private/kernel/int.h @@ -1,5 +1,5 @@ /* - * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2003-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -22,7 +22,7 @@ extern "C" { status_t int_init(struct kernel_args *args); status_t int_init_post_vm(struct kernel_args *args); status_t int_init_post_device_manager(struct kernel_args *args); -int int_io_interrupt_handler(int vector); +int int_io_interrupt_handler(int vector, bool levelTriggered); bool interrupts_enabled(void); diff --git a/src/system/kernel/arch/ppc/arch_int.cpp b/src/system/kernel/arch/ppc/arch_int.cpp index aeb7daf219..dccd581299 100644 --- a/src/system/kernel/arch/ppc/arch_int.cpp +++ b/src/system/kernel/arch/ppc/arch_int.cpp @@ -177,8 +177,10 @@ ppc_exception_entry(int vector, struct iframe *iframe) dprintf("handling I/O interrupts...\n"); int irq; - while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) - ret = int_io_interrupt_handler(irq); + while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) { +// TODO: correctly pass level-triggered vs. edge-triggered to the handler! + ret = int_io_interrupt_handler(irq, true); + } dprintf("handling I/O interrupts done\n"); break; } diff --git a/src/system/kernel/arch/x86/arch_int.c b/src/system/kernel/arch/x86/arch_int.c index 267a732950..a9d677f4c9 100644 --- a/src/system/kernel/arch/x86/arch_int.c +++ b/src/system/kernel/arch/x86/arch_int.c @@ -523,6 +523,8 @@ i386_handle_trap(struct iframe frame) default: if (frame.vector >= ARCH_INTERRUPT_BASE) { + bool levelTriggered = pic_is_level_triggered(frame.vector); + // This is a workaround for spurious assertions of interrupts 7/15 // which seems to be an often seen problem on the PC platform if (pic_is_spurious_interrupt(frame.vector - ARCH_INTERRUPT_BASE)) { @@ -530,12 +532,13 @@ i386_handle_trap(struct iframe frame) break; } - if (!pic_is_level_triggered(frame.vector)) + if (!levelTriggered) pic_end_of_interrupt(frame.vector); - ret = int_io_interrupt_handler(frame.vector - ARCH_INTERRUPT_BASE); + ret = int_io_interrupt_handler(frame.vector - ARCH_INTERRUPT_BASE, + levelTriggered); - if (pic_is_level_triggered(frame.vector)) + if (levelTriggered) pic_end_of_interrupt(frame.vector); } else { char name[32]; diff --git a/src/system/kernel/int.c b/src/system/kernel/int.c index 608b9fa572..f01eaf0a7c 100644 --- a/src/system/kernel/int.c +++ b/src/system/kernel/int.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -227,27 +227,12 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) */ int -int_io_interrupt_handler(int vector) +int_io_interrupt_handler(int vector, bool levelTriggered) { int status = B_UNHANDLED_INTERRUPT; struct io_handler *io; + bool invokeScheduler = false, handled = false; -#if 0 -{ - static int low[2]; - static int high[2]; - static int counter; - int32 cpu = smp_get_current_cpu(); - - if (vector > 0xf0 - 32) - high[cpu]++; - else - low[cpu]++; - dprintf("got vector %d at CPU %ld\n", vector, cpu); - //if ((counter++ % 10) == 0) - dprintf("ints: %d/%d (high: %d/%d)\n", low[0], low[1], high[0], high[1]); -} -#endif acquire_spinlock(&io_vectors[vector].vector_lock); // The list can be empty at this place @@ -257,36 +242,27 @@ int_io_interrupt_handler(int vector) return B_UNHANDLED_INTERRUPT; } - /* Loop through the list of handlers. - * each handler returns as follows... - * - B_UNHANDLED_INTERRUPT, the interrupt wasn't processed by the - * fucntion, so try the next available. - * - B_HANDLED_INTERRUPT, the interrupt has been handled and no further - * attention is required - * - B_INVOKE_SCHEDULER, the interrupt has been handled, but the function wants - * the scheduler to be invoked - * - * This is a change of behaviour from newos where every handler registered - * be called, even if the interrupt had been "handled" by a previous - * function. - * The logic now is that if there are no handlers then we return - * B_UNHANDLED_INTERRUPT and let the system do as it will. - * When we have the first function that claims to have "handled" the - * interrupt, by returning B_HANDLED_... or B_INVOKE_SCHEDULER we simply - * stop calling further handlers and return the value from that - * handler. - * This may not be correct but appears to be what BeOS did and seems - * right. - * - * ToDo: we might want to reenable calling all registered handlers depending - * on a flag somewhere, so that we can deal with buggy drivers + /* For level-triggered interrupts, we actually handle the return + * value (ie. B_HANDLED_INTERRUPT) to decide wether or not we + * want to call another interrupt handler. + * For edge-triggered interrupts, however, we always need to call + * all handlers, as multiple interrupts cannot be identified. We + * still make sure the return code of this function will issue + * whatever the driver thought would be useful (ie. B_INVOKE_SCHEDULER) */ for (io = io_vectors[vector].handler_list.next; - io != &io_vectors[vector].handler_list; // Are we already at the end of the list? - io = io->next) { - if ((status = io->func(io->data)) != B_UNHANDLED_INTERRUPT) + io != &io_vectors[vector].handler_list; // Are we already at the end of the list? + io = io->next) { + status = io->func(io->data); + + if (levelTriggered && status != B_UNHANDLED_INTERRUPT) break; + + if (status == B_HANDLED_INTERRUPT) + handled = true; + else if (status == B_INVOKE_SCHEDULER) + invokeScheduler = true; } #ifdef DEBUG_INT @@ -298,6 +274,16 @@ int_io_interrupt_handler(int vector) release_spinlock(&io_vectors[vector].vector_lock); - return status; + if (levelTriggered) + return status; + + // edge triggered return value + + if (invokeScheduler) + return B_INVOKE_SCHEDULER; + if (handled) + return B_HANDLED_INTERRUPT; + + return B_UNHANDLED_INTERRUPT; }