예제 #1
0
파일: spurious.c 프로젝트: Lyude/linux
/*
 * Recovery handler for misrouted interrupts.
 */
static int try_one_irq(struct irq_desc *desc, bool force)
{
	irqreturn_t ret = IRQ_NONE;
	struct irqaction *action;

	raw_spin_lock(&desc->lock);

	/*
	 * PER_CPU, nested thread interrupts and interrupts explicitely
	 * marked polled are excluded from polling.
	 */
	if (irq_settings_is_per_cpu(desc) ||
	    irq_settings_is_nested_thread(desc) ||
	    irq_settings_is_polled(desc))
		goto out;

	/*
	 * Do not poll disabled interrupts unless the spurious
	 * disabled poller asks explicitely.
	 */
	if (irqd_irq_disabled(&desc->irq_data) && !force)
		goto out;

	/*
	 * All handlers must agree on IRQF_SHARED, so we test just the
	 * first.
	 */
	action = desc->action;
	if (!action || !(action->flags & IRQF_SHARED) ||
	    (action->flags & __IRQF_TIMER))
		goto out;

	/* Already running on another processor */
	if (irqd_irq_inprogress(&desc->irq_data)) {
		/*
		 * Already running: If it is shared get the other
		 * CPU to go looking for our mystery interrupt too
		 */
		desc->istate |= IRQS_PENDING;
		goto out;
	}

	/* Mark it poll in progress */
	desc->istate |= IRQS_POLL_INPROGRESS;
	do {
		if (handle_irq_event(desc) == IRQ_HANDLED)
			ret = IRQ_HANDLED;
		/* Make sure that there is still a valid action */
		action = desc->action;
	} while ((desc->istate & IRQS_PENDING) && action);
	desc->istate &= ~IRQS_POLL_INPROGRESS;
out:
	raw_spin_unlock(&desc->lock);
	return ret == IRQ_HANDLED;
}
예제 #2
0
/*
 * Recovery handler for misrouted interrupts.
 */
static int try_one_irq(int irq, struct irq_desc *desc, bool force)
{
    irqreturn_t ret = IRQ_NONE;
    struct irqaction *action;

    raw_spin_lock(&desc->lock);

    /* PER_CPU and nested thread interrupts are never polled */
    if (irq_settings_is_per_cpu(desc) || irq_settings_is_nested_thread(desc))
        goto out;

    /*
     * Do not poll disabled interrupts unless the spurious
     * disabled poller asks explicitely.
     */
    if ((desc->istate & IRQS_DISABLED) && !force)
        goto out;

    /*
     * All handlers must agree on IRQF_SHARED, so we test just the
     * first. Check for action->next as well.
     */
    action = desc->action;
    if (!action || !(action->flags & IRQF_SHARED) ||
            (action->flags & __IRQF_TIMER) || !action->next)
        goto out;

    /* Already running on another processor */
    if (desc->istate & IRQS_INPROGRESS) {
        /*
         * Already running: If it is shared get the other
         * CPU to go looking for our mystery interrupt too
         */
        irq_compat_set_pending(desc);
        desc->istate |= IRQS_PENDING;
        goto out;
    }

    /* Mark it poll in progress */
    desc->istate |= IRQS_POLL_INPROGRESS;
    do {
        if (handle_irq_event(desc) == IRQ_HANDLED)
            ret = IRQ_HANDLED;
        action = desc->action;
    } while ((desc->istate & IRQS_PENDING) && action);
    desc->istate &= ~IRQS_POLL_INPROGRESS;
out:
    raw_spin_unlock(&desc->lock);
    return ret == IRQ_HANDLED;
}
예제 #3
0
파일: irqdesc.c 프로젝트: avagin/linux
/**
 * kstat_irqs - Get the statistics for an interrupt
 * @irq:	The interrupt number
 *
 * Returns the sum of interrupt counts on all cpus since boot for
 * @irq. The caller must ensure that the interrupt is not removed
 * concurrently.
 */
unsigned int kstat_irqs(unsigned int irq)
{
	struct irq_desc *desc = irq_to_desc(irq);
	unsigned int sum = 0;
	int cpu;

	if (!desc || !desc->kstat_irqs)
		return 0;
	if (!irq_settings_is_per_cpu_devid(desc) &&
	    !irq_settings_is_per_cpu(desc))
	    return desc->tot_count;

	for_each_possible_cpu(cpu)
		sum += *per_cpu_ptr(desc->kstat_irqs, cpu);
	return sum;
}
예제 #4
0
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
    unsigned long flags;
    struct irq_desc *desc = irq_get_desc_lock(irq, &flags);

    if (!desc)
        return;
    irq_settings_clr_and_set(desc, clr, set);

    irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
               IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
    if (irq_settings_has_no_balance_set(desc))
        irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
    if (irq_settings_is_per_cpu(desc))
        irqd_set(&desc->irq_data, IRQD_PER_CPU);
    if (irq_settings_can_move_pcntxt(desc))
        irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);

    irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc));

    irq_put_desc_unlock(desc, flags);
}
예제 #5
0
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
	unsigned long flags, trigger, tmp;
	struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);

	if (!desc)
		return;

	/*
	 * Warn when a driver sets the no autoenable flag on an already
	 * active interrupt.
	 */
	WARN_ON_ONCE(!desc->depth && (set & _IRQ_NOAUTOEN));

	irq_settings_clr_and_set(desc, clr, set);

	trigger = irqd_get_trigger_type(&desc->irq_data);

	irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
		   IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
	if (irq_settings_has_no_balance_set(desc))
		irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
	if (irq_settings_is_per_cpu(desc))
		irqd_set(&desc->irq_data, IRQD_PER_CPU);
	if (irq_settings_can_move_pcntxt(desc))
		irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
	if (irq_settings_is_level(desc))
		irqd_set(&desc->irq_data, IRQD_LEVEL);

	tmp = irq_settings_get_trigger_mask(desc);
	if (tmp != IRQ_TYPE_NONE)
		trigger = tmp;

	irqd_set(&desc->irq_data, trigger);

	irq_put_desc_unlock(desc, flags);
}