Commit | Line | Data |
---|---|---|
a4633adc TG |
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 | ||
85c0f909 YL |
36 | while (!bitmap_empty(irqs_resend, nr_irqs)) { |
37 | irq = find_first_bit(irqs_resend, nr_irqs); | |
a4633adc | 38 | clear_bit(irq, irqs_resend); |
08678b08 | 39 | desc = irq_to_desc(irq); |
6a6de9ef | 40 | local_irq_disable(); |
e317c8cc | 41 | desc->handle_irq(irq, desc); |
6a6de9ef | 42 | local_irq_enable(); |
a4633adc TG |
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 | ||
2464286a TG |
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) { | |
e1ed7ac7 | 71 | desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY; |
a4633adc TG |
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 | } |