diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-27 10:54:57 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-02-27 10:54:57 -0500 |
| commit | faf3502a3fed9951ea9f5a696c0bd2c1d056d7b4 (patch) | |
| tree | 05bc5d6ea9601d0b4f491b328eba5ccf1186a463 /kernel | |
| parent | 048cd4e51d24ebf7f3552226d03c769d6ad91658 (diff) | |
| parent | b4bc724e82e80478cba5fe9825b62e71ddf78757 (diff) | |
Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
genirq: Handle pending irqs in irq_startup()
genirq: Unmask oneshot irqs when thread was not woken
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/irq/autoprobe.c | 4 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 42 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 2 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 2 |
4 files changed, 37 insertions, 13 deletions
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c index 342d8f44e401..0119b9d467ae 100644 --- a/kernel/irq/autoprobe.c +++ b/kernel/irq/autoprobe.c | |||
| @@ -53,7 +53,7 @@ unsigned long probe_irq_on(void) | |||
| 53 | if (desc->irq_data.chip->irq_set_type) | 53 | if (desc->irq_data.chip->irq_set_type) |
| 54 | desc->irq_data.chip->irq_set_type(&desc->irq_data, | 54 | desc->irq_data.chip->irq_set_type(&desc->irq_data, |
| 55 | IRQ_TYPE_PROBE); | 55 | IRQ_TYPE_PROBE); |
| 56 | irq_startup(desc); | 56 | irq_startup(desc, false); |
| 57 | } | 57 | } |
| 58 | raw_spin_unlock_irq(&desc->lock); | 58 | raw_spin_unlock_irq(&desc->lock); |
| 59 | } | 59 | } |
| @@ -70,7 +70,7 @@ unsigned long probe_irq_on(void) | |||
| 70 | raw_spin_lock_irq(&desc->lock); | 70 | raw_spin_lock_irq(&desc->lock); |
| 71 | if (!desc->action && irq_settings_can_probe(desc)) { | 71 | if (!desc->action && irq_settings_can_probe(desc)) { |
| 72 | desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; | 72 | desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; |
| 73 | if (irq_startup(desc)) | 73 | if (irq_startup(desc, false)) |
| 74 | desc->istate |= IRQS_PENDING; | 74 | desc->istate |= IRQS_PENDING; |
| 75 | } | 75 | } |
| 76 | raw_spin_unlock_irq(&desc->lock); | 76 | raw_spin_unlock_irq(&desc->lock); |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index f7c543a801d9..fb7db75ee0c8 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -157,19 +157,22 @@ static void irq_state_set_masked(struct irq_desc *desc) | |||
| 157 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); | 157 | irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | int irq_startup(struct irq_desc *desc) | 160 | int irq_startup(struct irq_desc *desc, bool resend) |
| 161 | { | 161 | { |
| 162 | int ret = 0; | ||
| 163 | |||
| 162 | irq_state_clr_disabled(desc); | 164 | irq_state_clr_disabled(desc); |
| 163 | desc->depth = 0; | 165 | desc->depth = 0; |
| 164 | 166 | ||
| 165 | if (desc->irq_data.chip->irq_startup) { | 167 | if (desc->irq_data.chip->irq_startup) { |
| 166 | int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); | 168 | ret = desc->irq_data.chip->irq_startup(&desc->irq_data); |
| 167 | irq_state_clr_masked(desc); | 169 | irq_state_clr_masked(desc); |
| 168 | return ret; | 170 | } else { |
| 171 | irq_enable(desc); | ||
| 169 | } | 172 | } |
| 170 | 173 | if (resend) | |
| 171 | irq_enable(desc); | 174 | check_irq_resend(desc, desc->irq_data.irq); |
| 172 | return 0; | 175 | return ret; |
| 173 | } | 176 | } |
| 174 | 177 | ||
| 175 | void irq_shutdown(struct irq_desc *desc) | 178 | void irq_shutdown(struct irq_desc *desc) |
| @@ -330,6 +333,24 @@ out_unlock: | |||
| 330 | } | 333 | } |
| 331 | EXPORT_SYMBOL_GPL(handle_simple_irq); | 334 | EXPORT_SYMBOL_GPL(handle_simple_irq); |
| 332 | 335 | ||
| 336 | /* | ||
| 337 | * Called unconditionally from handle_level_irq() and only for oneshot | ||
| 338 | * interrupts from handle_fasteoi_irq() | ||
| 339 | */ | ||
| 340 | static void cond_unmask_irq(struct irq_desc *desc) | ||
| 341 | { | ||
| 342 | /* | ||
| 343 | * We need to unmask in the following cases: | ||
| 344 | * - Standard level irq (IRQF_ONESHOT is not set) | ||
| 345 | * - Oneshot irq which did not wake the thread (caused by a | ||
| 346 | * spurious interrupt or a primary handler handling it | ||
| 347 | * completely). | ||
| 348 | */ | ||
| 349 | if (!irqd_irq_disabled(&desc->irq_data) && | ||
| 350 | irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) | ||
| 351 | unmask_irq(desc); | ||
| 352 | } | ||
| 353 | |||
| 333 | /** | 354 | /** |
| 334 | * handle_level_irq - Level type irq handler | 355 | * handle_level_irq - Level type irq handler |
| 335 | * @irq: the interrupt number | 356 | * @irq: the interrupt number |
| @@ -362,8 +383,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
| 362 | 383 | ||
| 363 | handle_irq_event(desc); | 384 | handle_irq_event(desc); |
| 364 | 385 | ||
| 365 | if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) | 386 | cond_unmask_irq(desc); |
| 366 | unmask_irq(desc); | 387 | |
| 367 | out_unlock: | 388 | out_unlock: |
| 368 | raw_spin_unlock(&desc->lock); | 389 | raw_spin_unlock(&desc->lock); |
| 369 | } | 390 | } |
| @@ -417,6 +438,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
| 417 | preflow_handler(desc); | 438 | preflow_handler(desc); |
| 418 | handle_irq_event(desc); | 439 | handle_irq_event(desc); |
| 419 | 440 | ||
| 441 | if (desc->istate & IRQS_ONESHOT) | ||
| 442 | cond_unmask_irq(desc); | ||
| 443 | |||
| 420 | out_eoi: | 444 | out_eoi: |
| 421 | desc->irq_data.chip->irq_eoi(&desc->irq_data); | 445 | desc->irq_data.chip->irq_eoi(&desc->irq_data); |
| 422 | out_unlock: | 446 | out_unlock: |
| @@ -625,7 +649,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, | |||
| 625 | irq_settings_set_noprobe(desc); | 649 | irq_settings_set_noprobe(desc); |
| 626 | irq_settings_set_norequest(desc); | 650 | irq_settings_set_norequest(desc); |
| 627 | irq_settings_set_nothread(desc); | 651 | irq_settings_set_nothread(desc); |
| 628 | irq_startup(desc); | 652 | irq_startup(desc, true); |
| 629 | } | 653 | } |
| 630 | out: | 654 | out: |
| 631 | irq_put_desc_busunlock(desc, flags); | 655 | irq_put_desc_busunlock(desc, flags); |
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index b7952316016a..40378ff877e7 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
| 67 | extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); | 67 | extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); |
| 68 | extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); | 68 | extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); |
| 69 | 69 | ||
| 70 | extern int irq_startup(struct irq_desc *desc); | 70 | extern int irq_startup(struct irq_desc *desc, bool resend); |
| 71 | extern void irq_shutdown(struct irq_desc *desc); | 71 | extern void irq_shutdown(struct irq_desc *desc); |
| 72 | extern void irq_enable(struct irq_desc *desc); | 72 | extern void irq_enable(struct irq_desc *desc); |
| 73 | extern void irq_disable(struct irq_desc *desc); | 73 | extern void irq_disable(struct irq_desc *desc); |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index a9a9dbe49fea..32313c084442 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -1027,7 +1027,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 1027 | desc->istate |= IRQS_ONESHOT; | 1027 | desc->istate |= IRQS_ONESHOT; |
| 1028 | 1028 | ||
| 1029 | if (irq_settings_can_autoenable(desc)) | 1029 | if (irq_settings_can_autoenable(desc)) |
| 1030 | irq_startup(desc); | 1030 | irq_startup(desc, true); |
| 1031 | else | 1031 | else |
| 1032 | /* Undo nested disables: */ | 1032 | /* Undo nested disables: */ |
| 1033 | desc->depth = 1; | 1033 | desc->depth = 1; |
