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
This commit is contained in:
Axel Dörfler 2006-04-30 13:56:21 +00:00
parent f7a446f46f
commit 77a08c68e8
4 changed files with 43 additions and 52 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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];

View File

@ -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;
}