diff options
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r-- | kernel/irq/manage.c | 50 |
1 files changed, 33 insertions, 17 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 438a01464287..46d6611a33bb 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/random.h> | 12 | #include <linux/random.h> |
13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
14 | #include <linux/slab.h> | ||
14 | 15 | ||
15 | #include "internals.h" | 16 | #include "internals.h" |
16 | 17 | ||
@@ -149,6 +150,26 @@ void disable_irq(unsigned int irq) | |||
149 | } | 150 | } |
150 | EXPORT_SYMBOL(disable_irq); | 151 | EXPORT_SYMBOL(disable_irq); |
151 | 152 | ||
153 | static void __enable_irq(struct irq_desc *desc, unsigned int irq) | ||
154 | { | ||
155 | switch (desc->depth) { | ||
156 | case 0: | ||
157 | printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); | ||
158 | WARN_ON(1); | ||
159 | break; | ||
160 | case 1: { | ||
161 | unsigned int status = desc->status & ~IRQ_DISABLED; | ||
162 | |||
163 | /* Prevent probing on this irq: */ | ||
164 | desc->status = status | IRQ_NOPROBE; | ||
165 | check_irq_resend(desc, irq); | ||
166 | /* fall-through */ | ||
167 | } | ||
168 | default: | ||
169 | desc->depth--; | ||
170 | } | ||
171 | } | ||
172 | |||
152 | /** | 173 | /** |
153 | * enable_irq - enable handling of an irq | 174 | * enable_irq - enable handling of an irq |
154 | * @irq: Interrupt to enable | 175 | * @irq: Interrupt to enable |
@@ -168,22 +189,7 @@ void enable_irq(unsigned int irq) | |||
168 | return; | 189 | return; |
169 | 190 | ||
170 | spin_lock_irqsave(&desc->lock, flags); | 191 | spin_lock_irqsave(&desc->lock, flags); |
171 | switch (desc->depth) { | 192 | __enable_irq(desc, irq); |
172 | case 0: | ||
173 | printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); | ||
174 | WARN_ON(1); | ||
175 | break; | ||
176 | case 1: { | ||
177 | unsigned int status = desc->status & ~IRQ_DISABLED; | ||
178 | |||
179 | /* Prevent probing on this irq: */ | ||
180 | desc->status = status | IRQ_NOPROBE; | ||
181 | check_irq_resend(desc, irq); | ||
182 | /* fall-through */ | ||
183 | } | ||
184 | default: | ||
185 | desc->depth--; | ||
186 | } | ||
187 | spin_unlock_irqrestore(&desc->lock, flags); | 193 | spin_unlock_irqrestore(&desc->lock, flags); |
188 | } | 194 | } |
189 | EXPORT_SYMBOL(enable_irq); | 195 | EXPORT_SYMBOL(enable_irq); |
@@ -364,7 +370,7 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
364 | compat_irq_chip_set_default_handler(desc); | 370 | compat_irq_chip_set_default_handler(desc); |
365 | 371 | ||
366 | desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | | 372 | desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | |
367 | IRQ_INPROGRESS); | 373 | IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED); |
368 | 374 | ||
369 | if (!(desc->status & IRQ_NOAUTOEN)) { | 375 | if (!(desc->status & IRQ_NOAUTOEN)) { |
370 | desc->depth = 0; | 376 | desc->depth = 0; |
@@ -380,6 +386,16 @@ int setup_irq(unsigned int irq, struct irqaction *new) | |||
380 | /* Reset broken irq detection when installing new handler */ | 386 | /* Reset broken irq detection when installing new handler */ |
381 | desc->irq_count = 0; | 387 | desc->irq_count = 0; |
382 | desc->irqs_unhandled = 0; | 388 | desc->irqs_unhandled = 0; |
389 | |||
390 | /* | ||
391 | * Check whether we disabled the irq via the spurious handler | ||
392 | * before. Reenable it and give it another chance. | ||
393 | */ | ||
394 | if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) { | ||
395 | desc->status &= ~IRQ_SPURIOUS_DISABLED; | ||
396 | __enable_irq(desc, irq); | ||
397 | } | ||
398 | |||
383 | spin_unlock_irqrestore(&desc->lock, flags); | 399 | spin_unlock_irqrestore(&desc->lock, flags); |
384 | 400 | ||
385 | new->irq = irq; | 401 | new->irq = irq; |