Exemplo n.º 1
0
/*!	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;
}
Exemplo n.º 2
0
/*!	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;
}
Exemplo n.º 3
0
/*!	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;
}