aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/chip.c2
-rw-r--r--kernel/irq/handle.c2
-rw-r--r--kernel/irq/manage.c22
-rw-r--r--kernel/irq/spurious.c146
4 files changed, 103 insertions, 69 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 3cd441ebf5d2..d663338cb4a8 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -583,7 +583,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
583 desc->status &= ~IRQ_DISABLED; 583 desc->status &= ~IRQ_DISABLED;
584 desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; 584 desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
585 desc->depth = 0; 585 desc->depth = 0;
586 desc->chip->unmask(irq); 586 desc->chip->startup(irq);
587 } 587 }
588 spin_unlock_irqrestore(&desc->lock, flags); 588 spin_unlock_irqrestore(&desc->lock, flags);
589} 589}
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 5fa6198e9139..f4c8a03a9fbb 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -131,8 +131,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
131 irqreturn_t ret, retval = IRQ_NONE; 131 irqreturn_t ret, retval = IRQ_NONE;
132 unsigned int status = 0; 132 unsigned int status = 0;
133 133
134 handle_dynamic_tick(action);
135
136 if (!(action->flags & IRQF_DISABLED)) 134 if (!(action->flags & IRQF_DISABLED))
137 local_irq_enable_in_hardirq(); 135 local_irq_enable_in_hardirq();
138 136
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0314074fa232..d62f69ba7453 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -423,10 +423,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
423 if (!(desc->status & IRQ_NOAUTOEN)) { 423 if (!(desc->status & IRQ_NOAUTOEN)) {
424 desc->depth = 0; 424 desc->depth = 0;
425 desc->status &= ~IRQ_DISABLED; 425 desc->status &= ~IRQ_DISABLED;
426 if (desc->chip->startup) 426 desc->chip->startup(irq);
427 desc->chip->startup(irq);
428 else
429 desc->chip->enable(irq);
430 } else 427 } else
431 /* Undo nested disables: */ 428 /* Undo nested disables: */
432 desc->depth = 1; 429 desc->depth = 1;
@@ -629,26 +626,29 @@ int request_irq(unsigned int irq, irq_handler_t handler,
629 action->next = NULL; 626 action->next = NULL;
630 action->dev_id = dev_id; 627 action->dev_id = dev_id;
631 628
629 retval = setup_irq(irq, action);
630 if (retval)
631 kfree(action);
632
632#ifdef CONFIG_DEBUG_SHIRQ 633#ifdef CONFIG_DEBUG_SHIRQ
633 if (irqflags & IRQF_SHARED) { 634 if (irqflags & IRQF_SHARED) {
634 /* 635 /*
635 * It's a shared IRQ -- the driver ought to be prepared for it 636 * It's a shared IRQ -- the driver ought to be prepared for it
636 * to happen immediately, so let's make sure.... 637 * to happen immediately, so let's make sure....
637 * We do this before actually registering it, to make sure that 638 * We disable the irq to make sure that a 'real' IRQ doesn't
638 * a 'real' IRQ doesn't run in parallel with our fake 639 * run in parallel with our fake.
639 */ 640 */
640 unsigned long flags; 641 unsigned long flags;
641 642
643 disable_irq(irq);
642 local_irq_save(flags); 644 local_irq_save(flags);
645
643 handler(irq, dev_id); 646 handler(irq, dev_id);
647
644 local_irq_restore(flags); 648 local_irq_restore(flags);
649 enable_irq(irq);
645 } 650 }
646#endif 651#endif
647
648 retval = setup_irq(irq, action);
649 if (retval)
650 kfree(action);
651
652 return retval; 652 return retval;
653} 653}
654EXPORT_SYMBOL(request_irq); 654EXPORT_SYMBOL(request_irq);
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index c66d3f10e853..19fe9d6ebfe8 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -12,83 +12,117 @@
12#include <linux/kallsyms.h> 12#include <linux/kallsyms.h>
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/moduleparam.h> 14#include <linux/moduleparam.h>
15#include <linux/timer.h>
15 16
16static int irqfixup __read_mostly; 17static int irqfixup __read_mostly;
17 18
19#define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10)
20static void poll_spurious_irqs(unsigned long dummy);
21static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0);
22
18/* 23/*
19 * Recovery handler for misrouted interrupts. 24 * Recovery handler for misrouted interrupts.
20 */ 25 */
21static int misrouted_irq(int irq) 26static int try_one_irq(int irq, struct irq_desc *desc)
22{ 27{
23 int i; 28 struct irqaction *action;
24 int ok = 0; 29 int ok = 0;
25 int work = 0; /* Did we do work for a real IRQ */ 30 int work = 0; /* Did we do work for a real IRQ */
26 31
27 for (i = 1; i < NR_IRQS; i++) { 32 spin_lock(&desc->lock);
28 struct irq_desc *desc = irq_desc + i; 33 /* Already running on another processor */
29 struct irqaction *action; 34 if (desc->status & IRQ_INPROGRESS) {
30 35 /*
31 if (i == irq) /* Already tried */ 36 * Already running: If it is shared get the other
32 continue; 37 * CPU to go looking for our mystery interrupt too
33 38 */
34 spin_lock(&desc->lock); 39 if (desc->action && (desc->action->flags & IRQF_SHARED))
35 /* Already running on another processor */ 40 desc->status |= IRQ_PENDING;
36 if (desc->status & IRQ_INPROGRESS) {
37 /*
38 * Already running: If it is shared get the other
39 * CPU to go looking for our mystery interrupt too
40 */
41 if (desc->action && (desc->action->flags & IRQF_SHARED))
42 desc->status |= IRQ_PENDING;
43 spin_unlock(&desc->lock);
44 continue;
45 }
46 /* Honour the normal IRQ locking */
47 desc->status |= IRQ_INPROGRESS;
48 action = desc->action;
49 spin_unlock(&desc->lock); 41 spin_unlock(&desc->lock);
42 return ok;
43 }
44 /* Honour the normal IRQ locking */
45 desc->status |= IRQ_INPROGRESS;
46 action = desc->action;
47 spin_unlock(&desc->lock);
50 48
51 while (action) { 49 while (action) {
52 /* Only shared IRQ handlers are safe to call */ 50 /* Only shared IRQ handlers are safe to call */
53 if (action->flags & IRQF_SHARED) { 51 if (action->flags & IRQF_SHARED) {
54 if (action->handler(i, action->dev_id) == 52 if (action->handler(irq, action->dev_id) ==
55 IRQ_HANDLED) 53 IRQ_HANDLED)
56 ok = 1; 54 ok = 1;
57 }
58 action = action->next;
59 } 55 }
60 local_irq_disable(); 56 action = action->next;
61 /* Now clean up the flags */ 57 }
62 spin_lock(&desc->lock); 58 local_irq_disable();
63 action = desc->action; 59 /* Now clean up the flags */
60 spin_lock(&desc->lock);
61 action = desc->action;
64 62
63 /*
64 * While we were looking for a fixup someone queued a real
65 * IRQ clashing with our walk:
66 */
67 while ((desc->status & IRQ_PENDING) && action) {
65 /* 68 /*
66 * While we were looking for a fixup someone queued a real 69 * Perform real IRQ processing for the IRQ we deferred
67 * IRQ clashing with our walk:
68 */
69 while ((desc->status & IRQ_PENDING) && action) {
70 /*
71 * Perform real IRQ processing for the IRQ we deferred
72 */
73 work = 1;
74 spin_unlock(&desc->lock);
75 handle_IRQ_event(i, action);
76 spin_lock(&desc->lock);
77 desc->status &= ~IRQ_PENDING;
78 }
79 desc->status &= ~IRQ_INPROGRESS;
80 /*
81 * If we did actual work for the real IRQ line we must let the
82 * IRQ controller clean up too
83 */ 70 */
84 if (work && desc->chip && desc->chip->end) 71 work = 1;
85 desc->chip->end(i);
86 spin_unlock(&desc->lock); 72 spin_unlock(&desc->lock);
73 handle_IRQ_event(irq, action);
74 spin_lock(&desc->lock);
75 desc->status &= ~IRQ_PENDING;
76 }
77 desc->status &= ~IRQ_INPROGRESS;
78 /*
79 * If we did actual work for the real IRQ line we must let the
80 * IRQ controller clean up too
81 */
82 if (work && desc->chip && desc->chip->end)
83 desc->chip->end(irq);
84 spin_unlock(&desc->lock);
85
86 return ok;
87}
88
89static int misrouted_irq(int irq)
90{
91 int i;
92 int ok = 0;
93
94 for (i = 1; i < NR_IRQS; i++) {
95 struct irq_desc *desc = irq_desc + i;
96
97 if (i == irq) /* Already tried */
98 continue;
99
100 if (try_one_irq(i, desc))
101 ok = 1;
87 } 102 }
88 /* So the caller can adjust the irq error counts */ 103 /* So the caller can adjust the irq error counts */
89 return ok; 104 return ok;
90} 105}
91 106
107static void poll_spurious_irqs(unsigned long dummy)
108{
109 int i;
110 for (i = 1; i < NR_IRQS; i++) {
111 struct irq_desc *desc = irq_desc + i;
112 unsigned int status;
113
114 /* Racy but it doesn't matter */
115 status = desc->status;
116 barrier();
117 if (!(status & IRQ_SPURIOUS_DISABLED))
118 continue;
119
120 try_one_irq(i, desc);
121 }
122
123 mod_timer(&poll_spurious_irq_timer, jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
124}
125
92/* 126/*
93 * If 99,900 of the previous 100,000 interrupts have not been handled 127 * If 99,900 of the previous 100,000 interrupts have not been handled
94 * then assume that the IRQ is stuck in some manner. Drop a diagnostic 128 * then assume that the IRQ is stuck in some manner. Drop a diagnostic
@@ -212,6 +246,8 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
212 desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED; 246 desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
213 desc->depth++; 247 desc->depth++;
214 desc->chip->disable(irq); 248 desc->chip->disable(irq);
249
250 mod_timer(&poll_spurious_irq_timer, jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
215 } 251 }
216 desc->irqs_unhandled = 0; 252 desc->irqs_unhandled = 0;
217} 253}