aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-02-23 18:52:13 -0500
committerThomas Gleixner <tglx@linutronix.de>2011-02-25 14:24:21 -0500
commitb5faba21a6805c33b40e258d36f57997ee1de131 (patch)
treec84ef3357ecd6e1b1cfda623136529db0e5fab6f
parent1204e95689f9fbd245a4ce5c1b0cd0a9b77f8d25 (diff)
genirq: Prepare the handling of shared oneshot interrupts
For level type interrupts we need to track how many threads are on flight to avoid useless interrupt storms when not all thread handlers have finished yet. Keep track of the woken threads and only unmask when there are no more threads in flight. Yes, I'm lazy and using a bitfield. But not only because I'm lazy, the main reason is that it's way simpler than using a refcount. A refcount based solution would need to keep track of various things like crashing the irq thread, spurious interrupts coming in, disables/enables, free_irq() and some more. The bitfield keeps the tracking simple and makes things just work. It's also nicely confined to the thread code pathes and does not require additional checks all over the place. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> LKML-Reference: <20110223234956.388095876@linutronix.de>
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/irqdesc.h2
-rw-r--r--kernel/irq/handle.c76
-rw-r--r--kernel/irq/manage.c54
4 files changed, 115 insertions, 19 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 8da6643e39a6..e116fef274cd 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -99,6 +99,7 @@ typedef irqreturn_t (*irq_handler_t)(int, void *);
99 * @thread_fn: interupt handler function for threaded interrupts 99 * @thread_fn: interupt handler function for threaded interrupts
100 * @thread: thread pointer for threaded interrupts 100 * @thread: thread pointer for threaded interrupts
101 * @thread_flags: flags related to @thread 101 * @thread_flags: flags related to @thread
102 * @thread_mask: bitmask for keeping track of @thread activity
102 */ 103 */
103struct irqaction { 104struct irqaction {
104 irq_handler_t handler; 105 irq_handler_t handler;
@@ -109,6 +110,7 @@ struct irqaction {
109 irq_handler_t thread_fn; 110 irq_handler_t thread_fn;
110 struct task_struct *thread; 111 struct task_struct *thread;
111 unsigned long thread_flags; 112 unsigned long thread_flags;
113 unsigned long thread_mask;
112 const char *name; 114 const char *name;
113 struct proc_dir_entry *dir; 115 struct proc_dir_entry *dir;
114} ____cacheline_internodealigned_in_smp; 116} ____cacheline_internodealigned_in_smp;
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 2f87d6441302..9eb9cd313052 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -28,6 +28,7 @@ struct timer_rand_state;
28 * @lock: locking for SMP 28 * @lock: locking for SMP
29 * @affinity_notify: context for notification of affinity changes 29 * @affinity_notify: context for notification of affinity changes
30 * @pending_mask: pending rebalanced interrupts 30 * @pending_mask: pending rebalanced interrupts
31 * @threads_oneshot: bitfield to handle shared oneshot threads
31 * @threads_active: number of irqaction threads currently running 32 * @threads_active: number of irqaction threads currently running
32 * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers 33 * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers
33 * @dir: /proc/irq/ procfs entry 34 * @dir: /proc/irq/ procfs entry
@@ -86,6 +87,7 @@ struct irq_desc {
86 cpumask_var_t pending_mask; 87 cpumask_var_t pending_mask;
87#endif 88#endif
88#endif 89#endif
90 unsigned long threads_oneshot;
89 atomic_t threads_active; 91 atomic_t threads_active;
90 wait_queue_head_t wait_for_threads; 92 wait_queue_head_t wait_for_threads;
91#ifdef CONFIG_PROC_FS 93#ifdef CONFIG_PROC_FS
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index b110c835e070..517561fc7317 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -51,6 +51,68 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
51 "but no thread function available.", irq, action->name); 51 "but no thread function available.", irq, action->name);
52} 52}
53 53
54static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action)
55{
56 /*
57 * Wake up the handler thread for this action. In case the
58 * thread crashed and was killed we just pretend that we
59 * handled the interrupt. The hardirq handler has disabled the
60 * device interrupt, so no irq storm is lurking. If the
61 * RUNTHREAD bit is already set, nothing to do.
62 */
63 if (test_bit(IRQTF_DIED, &action->thread_flags) ||
64 test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags))
65 return;
66
67 /*
68 * It's safe to OR the mask lockless here. We have only two
69 * places which write to threads_oneshot: This code and the
70 * irq thread.
71 *
72 * This code is the hard irq context and can never run on two
73 * cpus in parallel. If it ever does we have more serious
74 * problems than this bitmask.
75 *
76 * The irq threads of this irq which clear their "running" bit
77 * in threads_oneshot are serialized via desc->lock against
78 * each other and they are serialized against this code by
79 * IRQS_INPROGRESS.
80 *
81 * Hard irq handler:
82 *
83 * spin_lock(desc->lock);
84 * desc->state |= IRQS_INPROGRESS;
85 * spin_unlock(desc->lock);
86 * set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
87 * desc->threads_oneshot |= mask;
88 * spin_lock(desc->lock);
89 * desc->state &= ~IRQS_INPROGRESS;
90 * spin_unlock(desc->lock);
91 *
92 * irq thread:
93 *
94 * again:
95 * spin_lock(desc->lock);
96 * if (desc->state & IRQS_INPROGRESS) {
97 * spin_unlock(desc->lock);
98 * while(desc->state & IRQS_INPROGRESS)
99 * cpu_relax();
100 * goto again;
101 * }
102 * if (!test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
103 * desc->threads_oneshot &= ~mask;
104 * spin_unlock(desc->lock);
105 *
106 * So either the thread waits for us to clear IRQS_INPROGRESS
107 * or we are waiting in the flow handler for desc->lock to be
108 * released before we reach this point. The thread also checks
109 * IRQTF_RUNTHREAD under desc->lock. If set it leaves
110 * threads_oneshot untouched and runs the thread another time.
111 */
112 desc->threads_oneshot |= action->thread_mask;
113 wake_up_process(action->thread);
114}
115
54irqreturn_t 116irqreturn_t
55handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) 117handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
56{ 118{
@@ -85,19 +147,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
85 break; 147 break;
86 } 148 }
87 149
88 /* 150 irq_wake_thread(desc, action);
89 * Wake up the handler thread for this
90 * action. In case the thread crashed and was
91 * killed we just pretend that we handled the
92 * interrupt. The hardirq handler above has
93 * disabled the device interrupt, so no irq
94 * storm is lurking.
95 */
96 if (likely(!test_bit(IRQTF_DIED,
97 &action->thread_flags))) {
98 set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
99 wake_up_process(action->thread);
100 }
101 151
102 /* Fall through to add to randomness */ 152 /* Fall through to add to randomness */
103 case IRQ_HANDLED: 153 case IRQ_HANDLED:
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 01f8a9519e63..2301de19ac7d 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -617,8 +617,11 @@ static int irq_wait_for_interrupt(struct irqaction *action)
617 * handler finished. unmask if the interrupt has not been disabled and 617 * handler finished. unmask if the interrupt has not been disabled and
618 * is marked MASKED. 618 * is marked MASKED.
619 */ 619 */
620static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc) 620static void irq_finalize_oneshot(struct irq_desc *desc,
621 struct irqaction *action, bool force)
621{ 622{
623 if (!(desc->istate & IRQS_ONESHOT))
624 return;
622again: 625again:
623 chip_bus_lock(desc); 626 chip_bus_lock(desc);
624 raw_spin_lock_irq(&desc->lock); 627 raw_spin_lock_irq(&desc->lock);
@@ -631,6 +634,11 @@ again:
631 * on the other CPU. If we unmask the irq line then the 634 * on the other CPU. If we unmask the irq line then the
632 * interrupt can come in again and masks the line, leaves due 635 * interrupt can come in again and masks the line, leaves due
633 * to IRQS_INPROGRESS and the irq line is masked forever. 636 * to IRQS_INPROGRESS and the irq line is masked forever.
637 *
638 * This also serializes the state of shared oneshot handlers
639 * versus "desc->threads_onehsot |= action->thread_mask;" in
640 * irq_wake_thread(). See the comment there which explains the
641 * serialization.
634 */ 642 */
635 if (unlikely(desc->istate & IRQS_INPROGRESS)) { 643 if (unlikely(desc->istate & IRQS_INPROGRESS)) {
636 raw_spin_unlock_irq(&desc->lock); 644 raw_spin_unlock_irq(&desc->lock);
@@ -639,11 +647,23 @@ again:
639 goto again; 647 goto again;
640 } 648 }
641 649
642 if (!(desc->istate & IRQS_DISABLED) && (desc->istate & IRQS_MASKED)) { 650 /*
651 * Now check again, whether the thread should run. Otherwise
652 * we would clear the threads_oneshot bit of this thread which
653 * was just set.
654 */
655 if (!force && test_bit(IRQTF_RUNTHREAD, &action->thread_flags))
656 goto out_unlock;
657
658 desc->threads_oneshot &= ~action->thread_mask;
659
660 if (!desc->threads_oneshot && !(desc->istate & IRQS_DISABLED) &&
661 (desc->istate & IRQS_MASKED)) {
643 irq_compat_clr_masked(desc); 662 irq_compat_clr_masked(desc);
644 desc->istate &= ~IRQS_MASKED; 663 desc->istate &= ~IRQS_MASKED;
645 desc->irq_data.chip->irq_unmask(&desc->irq_data); 664 desc->irq_data.chip->irq_unmask(&desc->irq_data);
646 } 665 }
666out_unlock:
647 raw_spin_unlock_irq(&desc->lock); 667 raw_spin_unlock_irq(&desc->lock);
648 chip_bus_sync_unlock(desc); 668 chip_bus_sync_unlock(desc);
649} 669}
@@ -691,7 +711,7 @@ static int irq_thread(void *data)
691 }; 711 };
692 struct irqaction *action = data; 712 struct irqaction *action = data;
693 struct irq_desc *desc = irq_to_desc(action->irq); 713 struct irq_desc *desc = irq_to_desc(action->irq);
694 int wake, oneshot = desc->istate & IRQS_ONESHOT; 714 int wake;
695 715
696 sched_setscheduler(current, SCHED_FIFO, &param); 716 sched_setscheduler(current, SCHED_FIFO, &param);
697 current->irqaction = action; 717 current->irqaction = action;
@@ -719,8 +739,7 @@ static int irq_thread(void *data)
719 739
720 action->thread_fn(action->irq, action->dev_id); 740 action->thread_fn(action->irq, action->dev_id);
721 741
722 if (oneshot) 742 irq_finalize_oneshot(desc, action, false);
723 irq_finalize_oneshot(action->irq, desc);
724 } 743 }
725 744
726 wake = atomic_dec_and_test(&desc->threads_active); 745 wake = atomic_dec_and_test(&desc->threads_active);
@@ -729,6 +748,9 @@ static int irq_thread(void *data)
729 wake_up(&desc->wait_for_threads); 748 wake_up(&desc->wait_for_threads);
730 } 749 }
731 750
751 /* Prevent a stale desc->threads_oneshot */
752 irq_finalize_oneshot(desc, action, true);
753
732 /* 754 /*
733 * Clear irqaction. Otherwise exit_irq_thread() would make 755 * Clear irqaction. Otherwise exit_irq_thread() would make
734 * fuzz about an active irq thread going into nirvana. 756 * fuzz about an active irq thread going into nirvana.
@@ -743,6 +765,7 @@ static int irq_thread(void *data)
743void exit_irq_thread(void) 765void exit_irq_thread(void)
744{ 766{
745 struct task_struct *tsk = current; 767 struct task_struct *tsk = current;
768 struct irq_desc *desc;
746 769
747 if (!tsk->irqaction) 770 if (!tsk->irqaction)
748 return; 771 return;
@@ -751,6 +774,14 @@ void exit_irq_thread(void)
751 "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", 774 "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n",
752 tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq); 775 tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq);
753 776
777 desc = irq_to_desc(tsk->irqaction->irq);
778
779 /*
780 * Prevent a stale desc->threads_oneshot. Must be called
781 * before setting the IRQTF_DIED flag.
782 */
783 irq_finalize_oneshot(desc, tsk->irqaction, true);
784
754 /* 785 /*
755 * Set the THREAD DIED flag to prevent further wakeups of the 786 * Set the THREAD DIED flag to prevent further wakeups of the
756 * soon to be gone threaded handler. 787 * soon to be gone threaded handler.
@@ -767,7 +798,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
767{ 798{
768 struct irqaction *old, **old_ptr; 799 struct irqaction *old, **old_ptr;
769 const char *old_name = NULL; 800 const char *old_name = NULL;
770 unsigned long flags; 801 unsigned long flags, thread_mask = 0;
771 int ret, nested, shared = 0; 802 int ret, nested, shared = 0;
772 cpumask_var_t mask; 803 cpumask_var_t mask;
773 804
@@ -865,12 +896,23 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
865 896
866 /* add new interrupt at end of irq queue */ 897 /* add new interrupt at end of irq queue */
867 do { 898 do {
899 thread_mask |= old->thread_mask;
868 old_ptr = &old->next; 900 old_ptr = &old->next;
869 old = *old_ptr; 901 old = *old_ptr;
870 } while (old); 902 } while (old);
871 shared = 1; 903 shared = 1;
872 } 904 }
873 905
906 /*
907 * Setup the thread mask for this irqaction. Unlikely to have
908 * 32 resp 64 irqs sharing one line, but who knows.
909 */
910 if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) {
911 ret = -EBUSY;
912 goto out_mask;
913 }
914 new->thread_mask = 1 << ffz(thread_mask);
915
874 if (!shared) { 916 if (!shared) {
875 irq_chip_set_defaults(desc->irq_data.chip); 917 irq_chip_set_defaults(desc->irq_data.chip);
876 918