diff options
Diffstat (limited to 'kernel/irq/chip.c')
| -rw-r--r-- | kernel/irq/chip.c | 48 |
1 files changed, 40 insertions, 8 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index dc04c166c54d..6397df2d6945 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc) | |||
| 281 | } | 281 | } |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | void unmask_threaded_irq(struct irq_desc *desc) | ||
| 285 | { | ||
| 286 | struct irq_chip *chip = desc->irq_data.chip; | ||
| 287 | |||
| 288 | if (chip->flags & IRQCHIP_EOI_THREADED) | ||
| 289 | chip->irq_eoi(&desc->irq_data); | ||
| 290 | |||
| 291 | if (chip->irq_unmask) { | ||
| 292 | chip->irq_unmask(&desc->irq_data); | ||
| 293 | irq_state_clr_masked(desc); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 284 | /* | 297 | /* |
| 285 | * handle_nested_irq - Handle a nested irq from a irq thread | 298 | * handle_nested_irq - Handle a nested irq from a irq thread |
| 286 | * @irq: the interrupt number | 299 | * @irq: the interrupt number |
| @@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc) | |||
| 435 | static inline void preflow_handler(struct irq_desc *desc) { } | 448 | static inline void preflow_handler(struct irq_desc *desc) { } |
| 436 | #endif | 449 | #endif |
| 437 | 450 | ||
| 451 | static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip) | ||
| 452 | { | ||
| 453 | if (!(desc->istate & IRQS_ONESHOT)) { | ||
| 454 | chip->irq_eoi(&desc->irq_data); | ||
| 455 | return; | ||
| 456 | } | ||
| 457 | /* | ||
| 458 | * We need to unmask in the following cases: | ||
| 459 | * - Oneshot irq which did not wake the thread (caused by a | ||
| 460 | * spurious interrupt or a primary handler handling it | ||
| 461 | * completely). | ||
| 462 | */ | ||
| 463 | if (!irqd_irq_disabled(&desc->irq_data) && | ||
| 464 | irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) { | ||
| 465 | chip->irq_eoi(&desc->irq_data); | ||
| 466 | unmask_irq(desc); | ||
| 467 | } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) { | ||
| 468 | chip->irq_eoi(&desc->irq_data); | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 438 | /** | 472 | /** |
| 439 | * handle_fasteoi_irq - irq handler for transparent controllers | 473 | * handle_fasteoi_irq - irq handler for transparent controllers |
| 440 | * @irq: the interrupt number | 474 | * @irq: the interrupt number |
| @@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { } | |||
| 448 | void | 482 | void |
| 449 | handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | 483 | handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) |
| 450 | { | 484 | { |
| 485 | struct irq_chip *chip = desc->irq_data.chip; | ||
| 486 | |||
| 451 | raw_spin_lock(&desc->lock); | 487 | raw_spin_lock(&desc->lock); |
| 452 | 488 | ||
| 453 | if (unlikely(irqd_irq_inprogress(&desc->irq_data))) | 489 | if (unlikely(irqd_irq_inprogress(&desc->irq_data))) |
| @@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) | |||
| 473 | preflow_handler(desc); | 509 | preflow_handler(desc); |
| 474 | handle_irq_event(desc); | 510 | handle_irq_event(desc); |
| 475 | 511 | ||
| 476 | if (desc->istate & IRQS_ONESHOT) | 512 | cond_unmask_eoi_irq(desc, chip); |
| 477 | cond_unmask_irq(desc); | ||
| 478 | 513 | ||
| 479 | out_eoi: | ||
| 480 | desc->irq_data.chip->irq_eoi(&desc->irq_data); | ||
| 481 | out_unlock: | ||
| 482 | raw_spin_unlock(&desc->lock); | 514 | raw_spin_unlock(&desc->lock); |
| 483 | return; | 515 | return; |
| 484 | out: | 516 | out: |
| 485 | if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED)) | 517 | if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) |
| 486 | goto out_eoi; | 518 | chip->irq_eoi(&desc->irq_data); |
| 487 | goto out_unlock; | 519 | raw_spin_unlock(&desc->lock); |
| 488 | } | 520 | } |
| 489 | 521 | ||
| 490 | /** | 522 | /** |
