/* * linux/kernel/irq/resend.c * * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar * Copyright (C) 2005-2006, Thomas Gleixner * * This file contains the IRQ-resend code * * If the interrupt is waiting to be processed, we try to re-run it. * We can't directly run it from here since the caller might be in an * interrupt-protected region. Not all irq controller chips can * retrigger interrupts at the hardware level, so in those cases * we allow the resending of IRQs via a tasklet. */ #include <linux/irq.h> #include <linux/module.h> #include <linux/random.h> #include <linux/interrupt.h> #include "internals.h" #ifdef CONFIG_HARDIRQS_SW_RESEND /* Bitmap to handle software resend of interrupts: */ static DECLARE_BITMAP(irqs_resend, NR_IRQS); /* * Run software resends of IRQ's */ static void resend_irqs(unsigned long arg) { struct irq_desc *desc; int irq; while (!bitmap_empty(irqs_resend, NR_IRQS)) { irq = find_first_bit(irqs_resend, NR_IRQS); clear_bit(irq, irqs_resend); desc = irq_desc + irq; local_irq_disable(); desc->handle_irq(irq, desc, NULL); local_irq_enable(); } } /* Tasklet to handle resend: */ static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); #endif /* * IRQ resend * * Is called with interrupts disabled and desc->lock held. */ void check_irq_resend(struct irq_desc *desc, unsigned int irq) { unsigned int status = desc->status; /* * Make sure the interrupt is enabled, before resending it: */ desc->chip->enable(irq); if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { desc->status &= ~IRQ_PENDING; desc->status = status | IRQ_REPLAY; if (!desc->chip || !desc->chip->retrigger || !desc->chip->retrigger(irq)) { #ifdef CONFIG_HARDIRQS_SW_RESEND /* Set it pending and activate the softirq: */ set_bit(irq, irqs_resend); tasklet_schedule(&resend_tasklet); #endif } } }