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: */ 26 static DECLARE_BITMAP(irqs_resend, NR_IRQS); 27 28 /* 29 * Run software resends of IRQ's 30 */ 31 static 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: */ 47 static 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 */ 56 void check_irq_resend(struct irq_desc *desc, unsigned int irq) 57 { 58 unsigned int status = desc->status; 59 60 /* 61 * Make sure the interrupt is enabled, before resending it: 62 */ 63 desc->chip->enable(irq); 64 65 /* 66 * We do not resend level type interrupts. Level type 67 * interrupts are resent by hardware when they are still 68 * active. 69 */ 70 if ((status & (IRQ_LEVEL | IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { 71 desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY; 72 73 if (!desc->chip || !desc->chip->retrigger || 74 !desc->chip->retrigger(irq)) { 75 #ifdef CONFIG_HARDIRQS_SW_RESEND 76 /* Set it pending and activate the softirq: */ 77 set_bit(irq, irqs_resend); 78 tasklet_schedule(&resend_tasklet); 79 #endif 80 } 81 } 82 } 83