/*! Remove a previously installed interrupt handler */ status_t remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) { status_t status = B_BAD_VALUE; struct io_handler *io = NULL; struct io_handler *last = NULL; cpu_status state; if (vector < 0 || vector >= NUM_IO_VECTORS) return B_BAD_VALUE; /* lock the structures down so it is not modified while we search */ state = disable_interrupts(); acquire_spinlock(&sVectors[vector].vector_lock); /* loop through the available handlers and try to find a match. * We go forward through the list but this means we start with the * most recently added handlers. */ for (io = sVectors[vector].handler_list; io != NULL; io = io->next) { /* we have to match both function and data */ if (io->func == handler && io->data == data) { if (last != NULL) last->next = io->next; else sVectors[vector].handler_list = io->next; // Check if we need to disable the interrupt if (io->use_enable_counter && --sVectors[vector].enable_count == 0) arch_int_disable_io_interrupt(vector); status = B_OK; break; } last = io; } release_spinlock(&sVectors[vector].vector_lock); restore_interrupts(state); // if the handler could be found and removed, we still have to free it if (status == B_OK) free(io); 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 handled = false; if (!sVectors[vector].no_lock_vector) acquire_spinlock(&sVectors[vector].vector_lock); #if !DEBUG_INTERRUPTS // The list can be empty at this place if (sVectors[vector].handler_list == NULL) { dprintf("unhandled io interrupt %d\n", vector); if (!sVectors[vector].no_lock_vector) release_spinlock(&sVectors[vector].vector_lock); return B_UNHANDLED_INTERRUPT; } #endif // 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. for (io = sVectors[vector].handler_list; io != NULL; io = io->next) { status = io->func(io->data); #if DEBUG_INTERRUPTS if (status != B_UNHANDLED_INTERRUPT) io->handled_count++; #endif if (levelTriggered && status != B_UNHANDLED_INTERRUPT) break; if (status == B_HANDLED_INTERRUPT || status == B_INVOKE_SCHEDULER) handled = true; } #if DEBUG_INTERRUPTS sVectors[vector].trigger_count++; if (status != B_UNHANDLED_INTERRUPT || handled) { 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) { struct io_handler *last = sVectors[vector].handler_list; while (last && last->next) last = last->next; if (last != NULL && last->no_handled_info) { // we have an interrupt handler installed that does not // know whether or not it has actually handled the interrupt, // so this unhandled count is inaccurate and we can't just // disable } else { if (sVectors[vector].handler_list == NULL || sVectors[vector].handler_list->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 (handled) return B_HANDLED_INTERRUPT; return B_UNHANDLED_INTERRUPT; }
/*! Remove a previously installed interrupt handler */ status_t remove_io_interrupt_handler(long vector, interrupt_handler handler, void *data) { status_t status = B_BAD_VALUE; struct io_handler *io = NULL; struct io_handler *last = NULL; cpu_status state; if (vector < 0 || vector >= NUM_IO_VECTORS) return B_BAD_VALUE; /* lock the structures down so it is not modified while we search */ state = disable_interrupts(); acquire_spinlock(&sVectors[vector].vector_lock); /* loop through the available handlers and try to find a match. * We go forward through the list but this means we start with the * most recently added handlers. */ for (io = sVectors[vector].handler_list; io != NULL; io = io->next) { /* we have to match both function and data */ if (io->func == handler && io->data == data) { if (last != NULL) last->next = io->next; else sVectors[vector].handler_list = io->next; // Check if we need to disable the interrupt if (io->use_enable_counter && --sVectors[vector].enable_count == 0) arch_int_disable_io_interrupt(vector); status = B_OK; break; } last = io; } if (sVectors[vector].handler_list == NULL && sVectors[vector].type == INTERRUPT_TYPE_IRQ && sVectors[vector].assigned_cpu != NULL && sVectors[vector].assigned_cpu->handlers_count > 0) { int32 oldHandlersCount = atomic_add(&sVectors[vector].assigned_cpu->handlers_count, -1); if (oldHandlersCount == 1) { int32 oldCPU; SpinLocker locker; cpu_ent* cpu; do { locker.Unlock(); oldCPU = sVectors[vector].assigned_cpu->cpu; ASSERT(oldCPU != -1); cpu = &gCPU[oldCPU]; locker.SetTo(cpu->irqs_lock, false); } while (sVectors[vector].assigned_cpu->cpu != oldCPU); sVectors[vector].assigned_cpu->cpu = -1; list_remove_item(&cpu->irqs, sVectors[vector].assigned_cpu); } } release_spinlock(&sVectors[vector].vector_lock); restore_interrupts(state); // if the handler could be found and removed, we still have to free it if (status == B_OK) free(io); return status; }