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:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2005, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2003-2006, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* 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(struct kernel_args *args);
|
||||||
status_t int_init_post_vm(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);
|
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);
|
bool interrupts_enabled(void);
|
||||||
|
|
||||||
|
|||||||
@@ -177,8 +177,10 @@ ppc_exception_entry(int vector, struct iframe *iframe)
|
|||||||
|
|
||||||
dprintf("handling I/O interrupts...\n");
|
dprintf("handling I/O interrupts...\n");
|
||||||
int irq;
|
int irq;
|
||||||
while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0)
|
while ((irq = sPIC->acknowledge_io_interrupt(sPICCookie)) >= 0) {
|
||||||
ret = int_io_interrupt_handler(irq);
|
// 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");
|
dprintf("handling I/O interrupts done\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -523,6 +523,8 @@ i386_handle_trap(struct iframe frame)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
if (frame.vector >= ARCH_INTERRUPT_BASE) {
|
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
|
// This is a workaround for spurious assertions of interrupts 7/15
|
||||||
// which seems to be an often seen problem on the PC platform
|
// which seems to be an often seen problem on the PC platform
|
||||||
if (pic_is_spurious_interrupt(frame.vector - ARCH_INTERRUPT_BASE)) {
|
if (pic_is_spurious_interrupt(frame.vector - ARCH_INTERRUPT_BASE)) {
|
||||||
@@ -530,12 +532,13 @@ i386_handle_trap(struct iframe frame)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pic_is_level_triggered(frame.vector))
|
if (!levelTriggered)
|
||||||
pic_end_of_interrupt(frame.vector);
|
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);
|
pic_end_of_interrupt(frame.vector);
|
||||||
} else {
|
} else {
|
||||||
char name[32];
|
char name[32];
|
||||||
|
|||||||
+31
-45
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2005, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2002-2006, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* 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
|
||||||
int_io_interrupt_handler(int vector)
|
int_io_interrupt_handler(int vector, bool levelTriggered)
|
||||||
{
|
{
|
||||||
int status = B_UNHANDLED_INTERRUPT;
|
int status = B_UNHANDLED_INTERRUPT;
|
||||||
struct io_handler *io;
|
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);
|
acquire_spinlock(&io_vectors[vector].vector_lock);
|
||||||
|
|
||||||
// The list can be empty at this place
|
// The list can be empty at this place
|
||||||
@@ -257,36 +242,27 @@ int_io_interrupt_handler(int vector)
|
|||||||
return B_UNHANDLED_INTERRUPT;
|
return B_UNHANDLED_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop through the list of handlers.
|
/* For level-triggered interrupts, we actually handle the return
|
||||||
* each handler returns as follows...
|
* value (ie. B_HANDLED_INTERRUPT) to decide wether or not we
|
||||||
* - B_UNHANDLED_INTERRUPT, the interrupt wasn't processed by the
|
* want to call another interrupt handler.
|
||||||
* fucntion, so try the next available.
|
* For edge-triggered interrupts, however, we always need to call
|
||||||
* - B_HANDLED_INTERRUPT, the interrupt has been handled and no further
|
* all handlers, as multiple interrupts cannot be identified. We
|
||||||
* attention is required
|
* still make sure the return code of this function will issue
|
||||||
* - B_INVOKE_SCHEDULER, the interrupt has been handled, but the function wants
|
* whatever the driver thought would be useful (ie. B_INVOKE_SCHEDULER)
|
||||||
* 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 (io = io_vectors[vector].handler_list.next;
|
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_vectors[vector].handler_list; // Are we already at the end of the list?
|
||||||
io = io->next) {
|
io = io->next) {
|
||||||
if ((status = io->func(io->data)) != B_UNHANDLED_INTERRUPT)
|
status = io->func(io->data);
|
||||||
|
|
||||||
|
if (levelTriggered && status != B_UNHANDLED_INTERRUPT)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if (status == B_HANDLED_INTERRUPT)
|
||||||
|
handled = true;
|
||||||
|
else if (status == B_INVOKE_SCHEDULER)
|
||||||
|
invokeScheduler = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_INT
|
#ifdef DEBUG_INT
|
||||||
@@ -298,6 +274,16 @@ int_io_interrupt_handler(int vector)
|
|||||||
|
|
||||||
release_spinlock(&io_vectors[vector].vector_lock);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user