1/* 2 * linux/kernel/irq/resend.c 3 * 4 * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar 5 * Copyright (C) 2005-2006, Thomas Gleixner 6 * 7 * This file contains the IRQ-resend code 8 * 9 * If the interrupt is waiting to be processed, we try to re-run it. 10 * We can't directly run it from here since the caller might be in an 11 * interrupt-protected region. Not all irq controller chips can 12 * retrigger interrupts at the hardware level, so in those cases 13 * we allow the resending of IRQs via a tasklet. 14 */ 15 16#include <linux/irq.h> 17#include <linux/module.h> 18#include <linux/random.h> 19#include <linux/interrupt.h> 20 21#include "internals.h" 22 23#ifdef CONFIG_HARDIRQS_SW_RESEND 24 25/* Bitmap to handle software resend of interrupts: */ 26static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS); 27 28/* 29 * Run software resends of IRQ's 30 */ 31static void resend_irqs(unsigned long arg) 32{ 33 struct irq_desc *desc; 34 int irq; 35 36 while (!bitmap_empty(irqs_resend, nr_irqs)) { 37 irq = find_first_bit(irqs_resend, nr_irqs); 38 clear_bit(irq, irqs_resend); 39 desc = irq_to_desc(irq); 40 local_irq_disable(); 41 desc->handle_irq(irq, desc); 42 local_irq_enable(); 43 } 44} 45 46/* Tasklet to handle resend: */ 47static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); 48 49#endif 50 51/* 52 * IRQ resend 53 * 54 * Is called with interrupts disabled and desc->lock held. 55 */ 56void check_irq_resend(struct irq_desc *desc, unsigned int irq) 57{ 58 /* 59 * We do not resend level type interrupts. Level type 60 * interrupts are resent by hardware when they are still 61 * active. 62 */ 63 if (irq_settings_is_level(desc)) 64 return; 65 if (desc->istate & IRQS_REPLAY) 66 return; 67 if (desc->istate & IRQS_PENDING) { 68 desc->istate &= ~IRQS_PENDING; 69 desc->istate |= IRQS_REPLAY; 70 71 if (!desc->irq_data.chip->irq_retrigger || 72 !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { 73#ifdef CONFIG_HARDIRQS_SW_RESEND 74 /* Set it pending and activate the softirq: */ 75 set_bit(irq, irqs_resend); 76 tasklet_schedule(&resend_tasklet); 77#endif 78 } 79 } 80} 81