* Applied patch by Vasilis that updates the doxygen comment style.

* Shuffled functions around to separate the private from the public API.
* Renamed global static io_vectors to sVectors.
* Rearranged includes, replaced deprecated malloc.h with stdlib.h.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24640 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-03-29 12:01:57 +00:00
parent 76a9318758
commit a7f6ff0ff8
+161 -154
View File
@@ -8,16 +8,17 @@
#include <int.h> #include <int.h>
#include <smp.h>
#include <util/kqueue.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arch/debug_console.h> #include <arch/debug_console.h>
#include <arch/int.h> #include <arch/int.h>
#include <boot/kernel_args.h> #include <boot/kernel_args.h>
#include <util/kqueue.h>
#include <smp.h>
#include <string.h>
#include <stdio.h>
#include <malloc.h>
//#define TRACE_INT //#define TRACE_INT
#ifdef TRACE_INT #ifdef TRACE_INT
@@ -27,6 +28,7 @@
#endif #endif
#define DEBUG_INT #define DEBUG_INT
// adds statistics and unhandled counter
struct io_handler { struct io_handler {
struct io_handler *next; struct io_handler *next;
@@ -49,28 +51,7 @@ struct io_vector {
#endif #endif
}; };
static struct io_vector io_vectors[NUM_IO_VECTORS]; static struct io_vector sVectors[NUM_IO_VECTORS];
cpu_status
disable_interrupts(void)
{
return arch_int_disable_interrupts();
}
void
restore_interrupts(cpu_status status)
{
arch_int_restore_interrupts(status);
}
bool
interrupts_enabled(void)
{
return arch_int_are_interrupts_enabled();
}
#ifdef DEBUG_INT #ifdef DEBUG_INT
@@ -81,25 +62,25 @@ dump_int_statistics(int argc, char **argv)
for (i = 0; i < NUM_IO_VECTORS; i++) { for (i = 0; i < NUM_IO_VECTORS; i++) {
struct io_handler *io; struct io_handler *io;
if (io_vectors[i].vector_lock == 0 if (sVectors[i].vector_lock == 0
&& io_vectors[i].enable_count == 0 && sVectors[i].enable_count == 0
&& io_vectors[i].handled_count == 0 && sVectors[i].handled_count == 0
&& io_vectors[i].unhandled_count == 0 && sVectors[i].unhandled_count == 0
&& io_vectors[i].handler_list.next == &io_vectors[i].handler_list) && sVectors[i].handler_list.next == &sVectors[i].handler_list)
continue; continue;
kprintf("int %3d, enabled %ld, handled %8lld, unhandled %8lld%s%s\n", kprintf("int %3d, enabled %ld, handled %8lld, unhandled %8lld%s%s\n",
i, io_vectors[i].enable_count, io_vectors[i].handled_count, i, sVectors[i].enable_count, sVectors[i].handled_count,
io_vectors[i].unhandled_count, sVectors[i].unhandled_count,
io_vectors[i].vector_lock != 0 ? ", ACTIVE" : "", sVectors[i].vector_lock != 0 ? ", ACTIVE" : "",
io_vectors[i].handler_list.next == &io_vectors[i].handler_list sVectors[i].handler_list.next == &sVectors[i].handler_list
? ", no handler" : ""); ? ", no handler" : "");
for (io = io_vectors[i].handler_list.next; for (io = sVectors[i].handler_list.next;
io != &io_vectors[i].handler_list; io = io->next) { io != &sVectors[i].handler_list; io = io->next) {
kprintf("\t%p", io->func); kprintf("\t%p", io->func);
} }
if (io_vectors[i].handler_list.next != &io_vectors[i].handler_list) if (sVectors[i].handler_list.next != &sVectors[i].handler_list)
kprintf("\n"); kprintf("\n");
} }
return 0; return 0;
@@ -107,6 +88,16 @@ dump_int_statistics(int argc, char **argv)
#endif #endif
// #pragma mark - private kernel API
bool
interrupts_enabled(void)
{
return arch_int_are_interrupts_enabled();
}
status_t status_t
int_init(kernel_args *args) int_init(kernel_args *args)
{ {
@@ -123,20 +114,21 @@ int_init_post_vm(kernel_args *args)
/* initialize the vector list */ /* initialize the vector list */
for (i = 0; i < NUM_IO_VECTORS; i++) { for (i = 0; i < NUM_IO_VECTORS; i++) {
io_vectors[i].vector_lock = 0; /* initialize spinlock */ sVectors[i].vector_lock = 0; /* initialize spinlock */
io_vectors[i].enable_count = 0; sVectors[i].enable_count = 0;
io_vectors[i].no_lock_vector = false; sVectors[i].no_lock_vector = false;
#ifdef DEBUG_INT #ifdef DEBUG_INT
io_vectors[i].handled_count = 0; sVectors[i].handled_count = 0;
io_vectors[i].unhandled_count = 0; sVectors[i].unhandled_count = 0;
io_vectors[i].trigger_count = 0; sVectors[i].trigger_count = 0;
io_vectors[i].ignored_count = 0; sVectors[i].ignored_count = 0;
#endif #endif
initque(&io_vectors[i].handler_list); /* initialize handler queue */ initque(&sVectors[i].handler_list); /* initialize handler queue */
} }
#ifdef DEBUG_INT #ifdef DEBUG_INT
add_debugger_command("ints", &dump_int_statistics, "list interrupt statistics"); add_debugger_command("ints", &dump_int_statistics,
"list interrupt statistics");
#endif #endif
return arch_int_init_post_vm(args); return arch_int_init_post_vm(args);
@@ -152,12 +144,119 @@ int_init_post_device_manager(kernel_args *args)
} }
/** Install a handler to be called when an interrupt is triggered /*! Actually process an interrupt via the handlers registered for that
* for the given interrupt number with \a data as the argument. vector (IRQ).
*/
int
int_io_interrupt_handler(int vector, bool levelTriggered)
{
int status = B_UNHANDLED_INTERRUPT;
struct io_handler *io;
bool invokeScheduler = false, handled = false;
if (!sVectors[vector].no_lock_vector)
acquire_spinlock(&sVectors[vector].vector_lock);
// The list can be empty at this place
if (sVectors[vector].handler_list.next == &sVectors[vector].handler_list) {
dprintf("unhandled io interrupt %d\n", vector);
if (!sVectors[vector].no_lock_vector)
release_spinlock(&sVectors[vector].vector_lock);
return B_UNHANDLED_INTERRUPT;
}
/* 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 = sVectors[vector].handler_list.next;
io != &sVectors[vector].handler_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
sVectors[vector].trigger_count++;
if (status != B_UNHANDLED_INTERRUPT || handled || invokeScheduler) {
sVectors[vector].handled_count++;
} else {
sVectors[vector].unhandled_count++;
sVectors[vector].ignored_count++;
}
if (sVectors[vector].trigger_count > 10000) {
if (sVectors[vector].ignored_count > 9900) {
if (sVectors[vector].handler_list.next == NULL
|| sVectors[vector].handler_list.next->next == NULL) {
// this interrupt vector is not shared, disable it
sVectors[vector].enable_count = -100;
arch_int_disable_io_interrupt(vector);
dprintf("Disabling unhandled io interrupt %d\n", vector);
} else {
// this is a shared interrupt vector, we cannot just disable it
dprintf("More than 99%% interrupts of vector %d are unhandled\n",
vector);
}
}
sVectors[vector].trigger_count = 0;
sVectors[vector].ignored_count = 0;
}
#endif
if (!sVectors[vector].no_lock_vector)
release_spinlock(&sVectors[vector].vector_lock);
if (levelTriggered)
return status;
// edge triggered return value
if (invokeScheduler)
return B_INVOKE_SCHEDULER;
if (handled)
return B_HANDLED_INTERRUPT;
return B_UNHANDLED_INTERRUPT;
}
// #pragma mark - public API
cpu_status
disable_interrupts(void)
{
return arch_int_disable_interrupts();
}
void
restore_interrupts(cpu_status status)
{
arch_int_restore_interrupts(status);
}
/*! Install a handler to be called when an interrupt is triggered
for the given interrupt number with \a data as the argument.
*/
status_t status_t
install_io_interrupt_handler(long vector, interrupt_handler handler, void *data, ulong flags) install_io_interrupt_handler(long vector, interrupt_handler handler, void *data,
ulong flags)
{ {
struct io_handler *io = NULL; struct io_handler *io = NULL;
cpu_status state; cpu_status state;
@@ -180,14 +279,14 @@ install_io_interrupt_handler(long vector, interrupt_handler handler, void *data,
// Disable the interrupts, get the spinlock for this irq only // Disable the interrupts, get the spinlock for this irq only
// and then insert the handler // and then insert the handler
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&io_vectors[vector].vector_lock); acquire_spinlock(&sVectors[vector].vector_lock);
insque(io, &io_vectors[vector].handler_list); insque(io, &sVectors[vector].handler_list);
// If B_NO_ENABLE_COUNTER is set, we're being asked to not alter // If B_NO_ENABLE_COUNTER is set, we're being asked to not alter
// whether the interrupt should be enabled or not // whether the interrupt should be enabled or not
if (io->use_enable_counter) { if (io->use_enable_counter) {
if (io_vectors[vector].enable_count++ == 0) if (sVectors[vector].enable_count++ == 0)
arch_int_enable_io_interrupt(vector); arch_int_enable_io_interrupt(vector);
} }
@@ -199,17 +298,16 @@ install_io_interrupt_handler(long vector, interrupt_handler handler, void *data,
// would in that case defeat the purpose as it would serialize calling the // would in that case defeat the purpose as it would serialize calling the
// handlers in parallel on different CPUs. // handlers in parallel on different CPUs.
if (flags & B_NO_LOCK_VECTOR) if (flags & B_NO_LOCK_VECTOR)
io_vectors[vector].no_lock_vector = true; sVectors[vector].no_lock_vector = true;
release_spinlock(&io_vectors[vector].vector_lock); release_spinlock(&sVectors[vector].vector_lock);
restore_interrupts(state); restore_interrupts(state);
return B_OK; return B_OK;
} }
/** Remove a previously installed interrupt handler */ /*! Remove a previously installed interrupt handler */
status_t status_t
remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data)
{ {
@@ -222,21 +320,21 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data)
/* lock the structures down so it is not modified while we search */ /* lock the structures down so it is not modified while we search */
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&io_vectors[vector].vector_lock); acquire_spinlock(&sVectors[vector].vector_lock);
/* loop through the available handlers and try to find a match. /* loop through the available handlers and try to find a match.
* We go forward through the list but this means we start with the * We go forward through the list but this means we start with the
* most recently added handlers. * most recently added handlers.
*/ */
for (io = io_vectors[vector].handler_list.next; for (io = sVectors[vector].handler_list.next;
io != &io_vectors[vector].handler_list; io != &sVectors[vector].handler_list;
io = io->next) { io = io->next) {
/* we have to match both function and data */ /* we have to match both function and data */
if (io->func == handler && io->data == data) { if (io->func == handler && io->data == data) {
remque(io); remque(io);
// Check if we need to disable the interrupt // Check if we need to disable the interrupt
if (io->use_enable_counter && --io_vectors[vector].enable_count == 0) if (io->use_enable_counter && --sVectors[vector].enable_count == 0)
arch_int_disable_io_interrupt(vector); arch_int_disable_io_interrupt(vector);
status = B_OK; status = B_OK;
@@ -244,7 +342,7 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data)
} }
} }
release_spinlock(&io_vectors[vector].vector_lock); release_spinlock(&sVectors[vector].vector_lock);
restore_interrupts(state); restore_interrupts(state);
// if the handler could be found and removed, we still have to free it // if the handler could be found and removed, we still have to free it
@@ -254,94 +352,3 @@ remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data)
return status; return status;
} }
/** actually process an interrupt via the handlers registered for that
* vector (irq)
*/
int
int_io_interrupt_handler(int vector, bool levelTriggered)
{
int status = B_UNHANDLED_INTERRUPT;
struct io_handler *io;
bool invokeScheduler = false, handled = false;
if (!io_vectors[vector].no_lock_vector)
acquire_spinlock(&io_vectors[vector].vector_lock);
// The list can be empty at this place
if (io_vectors[vector].handler_list.next == &io_vectors[vector].handler_list) {
dprintf("unhandled io interrupt %d\n", vector);
if (!io_vectors[vector].no_lock_vector)
release_spinlock(&io_vectors[vector].vector_lock);
return B_UNHANDLED_INTERRUPT;
}
/* 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) {
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
io_vectors[vector].trigger_count++;
if (status != B_UNHANDLED_INTERRUPT || handled || invokeScheduler) {
io_vectors[vector].handled_count++;
} else {
io_vectors[vector].unhandled_count++;
io_vectors[vector].ignored_count++;
}
if (io_vectors[vector].trigger_count > 10000) {
if (io_vectors[vector].ignored_count > 9900) {
if (io_vectors[vector].handler_list.next == NULL
|| io_vectors[vector].handler_list.next->next == NULL) {
// this interrupt vector is not shared, disable it
io_vectors[vector].enable_count = -100;
arch_int_disable_io_interrupt(vector);
dprintf("Disabling unhandled io interrupt %d\n", vector);
} else {
// this is a shared interrupt vector, we cannot just disable it
dprintf("More than 99%% interrupts of vector %d are unhandled\n",
vector);
}
}
io_vectors[vector].trigger_count = 0;
io_vectors[vector].ignored_count = 0;
}
#endif
if (!io_vectors[vector].no_lock_vector)
release_spinlock(&io_vectors[vector].vector_lock);
if (levelTriggered)
return status;
// edge triggered return value
if (invokeScheduler)
return B_INVOKE_SCHEDULER;
if (handled)
return B_HANDLED_INTERRUPT;
return B_UNHANDLED_INTERRUPT;
}