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, |