diff options
Diffstat (limited to 'kernel/irq/manage.c')
| -rw-r--r-- | kernel/irq/manage.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a3fd5b524c9..e485cea04bf1 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -451,6 +451,16 @@ static irqreturn_t irq_default_primary_handler(int irq, void *dev_id) | |||
| 451 | return IRQ_WAKE_THREAD; | 451 | return IRQ_WAKE_THREAD; |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | /* | ||
| 455 | * Primary handler for nested threaded interrupts. Should never be | ||
| 456 | * called. | ||
| 457 | */ | ||
| 458 | static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id) | ||
| 459 | { | ||
| 460 | WARN(1, "Primary handler called for nested irq %d\n", irq); | ||
| 461 | return IRQ_NONE; | ||
| 462 | } | ||
| 463 | |||
| 454 | static int irq_wait_for_interrupt(struct irqaction *action) | 464 | static int irq_wait_for_interrupt(struct irqaction *action) |
| 455 | { | 465 | { |
| 456 | while (!kthread_should_stop()) { | 466 | while (!kthread_should_stop()) { |
| @@ -600,7 +610,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 600 | struct irqaction *old, **old_ptr; | 610 | struct irqaction *old, **old_ptr; |
| 601 | const char *old_name = NULL; | 611 | const char *old_name = NULL; |
| 602 | unsigned long flags; | 612 | unsigned long flags; |
| 603 | int shared = 0; | 613 | int nested, shared = 0; |
| 604 | int ret; | 614 | int ret; |
| 605 | 615 | ||
| 606 | if (!desc) | 616 | if (!desc) |
| @@ -630,9 +640,27 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
| 630 | return -EINVAL; | 640 | return -EINVAL; |
| 631 | 641 | ||
| 632 | /* | 642 | /* |
| 633 | * Threaded handler ? | 643 | * Check whether the interrupt nests into another interrupt |
| 644 | * thread. | ||
| 645 | */ | ||
| 646 | nested = desc->status & IRQ_NESTED_THREAD; | ||
| 647 | if (nested) { | ||
| 648 | if (!new->thread_fn) | ||
| 649 | return -EINVAL; | ||
| 650 | /* | ||
| 651 | * Replace the primary handler which was provided from | ||
| 652 | * the driver for non nested interrupt handling by the | ||
| 653 | * dummy function which warns when called. | ||
| 654 | */ | ||
| 655 | new->handler = irq_nested_primary_handler; | ||
| 656 | } | ||
| 657 | |||
| 658 | /* | ||
| 659 | * Create a handler thread when a thread function is supplied | ||
| 660 | * and the interrupt does not nest into another interrupt | ||
| 661 | * thread. | ||
| 634 | */ | 662 | */ |
| 635 | if (new->thread_fn) { | 663 | if (new->thread_fn && !nested) { |
| 636 | struct task_struct *t; | 664 | struct task_struct *t; |
| 637 | 665 | ||
| 638 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, | 666 | t = kthread_create(irq_thread, new, "irq/%d-%s", irq, |
