diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 13:28:56 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 13:28:56 -0400 |
| commit | 0bbfcaff9b2a69c71a95e6902253487ab30cb498 (patch) | |
| tree | f422bbfb8ba57909bf6e43f1d560b3f056cc3c61 /kernel | |
| parent | 5928a2b60cfdbad730f93696acab142d0b607280 (diff) | |
| parent | e04268b0effc0ceea366c50b3107baad9edadafa (diff) | |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq/core changes for v3.4 from Ingo Molnar
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
genirq: Remove paranoid warnons and bogus fixups
genirq: Flush the irq thread on synchronization
genirq: Get rid of unnecessary IRQTF_DIED flag
genirq: No need to check IRQTF_DIED before stopping a thread handler
genirq: Get rid of unnecessary irqaction field in task_struct
genirq: Fix incorrect check for forced IRQ thread handler
softirq: Reduce invoke_softirq() code duplication
genirq: Fix long-term regression in genirq irq_set_irq_type() handling
x86-32/irq: Don't switch to irq stack for a user-mode irq
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/exit.c | 4 | ||||
| -rw-r--r-- | kernel/irq/chip.c | 3 | ||||
| -rw-r--r-- | kernel/irq/handle.c | 14 | ||||
| -rw-r--r-- | kernel/irq/internals.h | 2 | ||||
| -rw-r--r-- | kernel/irq/manage.c | 86 | ||||
| -rw-r--r-- | kernel/softirq.c | 18 |
6 files changed, 58 insertions, 69 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 4b4042f9bc6a..752d2c0abd19 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -935,8 +935,6 @@ void do_exit(long code) | |||
| 935 | schedule(); | 935 | schedule(); |
| 936 | } | 936 | } |
| 937 | 937 | ||
| 938 | exit_irq_thread(); | ||
| 939 | |||
| 940 | exit_signals(tsk); /* sets PF_EXITING */ | 938 | exit_signals(tsk); /* sets PF_EXITING */ |
| 941 | /* | 939 | /* |
| 942 | * tsk->flags are checked in the futex code to protect against | 940 | * tsk->flags are checked in the futex code to protect against |
| @@ -945,6 +943,8 @@ void do_exit(long code) | |||
| 945 | smp_mb(); | 943 | smp_mb(); |
| 946 | raw_spin_unlock_wait(&tsk->pi_lock); | 944 | raw_spin_unlock_wait(&tsk->pi_lock); |
| 947 | 945 | ||
| 946 | exit_irq_thread(); | ||
| 947 | |||
| 948 | if (unlikely(in_atomic())) | 948 | if (unlikely(in_atomic())) |
| 949 | printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", | 949 | printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", |
| 950 | current->comm, task_pid_nr(current), | 950 | current->comm, task_pid_nr(current), |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index fb7db75ee0c8..25784d630a12 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
| @@ -61,8 +61,7 @@ int irq_set_irq_type(unsigned int irq, unsigned int type) | |||
| 61 | return -EINVAL; | 61 | return -EINVAL; |
| 62 | 62 | ||
| 63 | type &= IRQ_TYPE_SENSE_MASK; | 63 | type &= IRQ_TYPE_SENSE_MASK; |
| 64 | if (type != IRQ_TYPE_NONE) | 64 | ret = __irq_set_trigger(desc, irq, type); |
| 65 | ret = __irq_set_trigger(desc, irq, type); | ||
| 66 | irq_put_desc_busunlock(desc, flags); | 65 | irq_put_desc_busunlock(desc, flags); |
| 67 | return ret; | 66 | return ret; |
| 68 | } | 67 | } |
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 470d08c82bbe..6ff84e6a954c 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
| @@ -60,7 +60,7 @@ static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action) | |||
| 60 | * device interrupt, so no irq storm is lurking. If the | 60 | * device interrupt, so no irq storm is lurking. If the |
| 61 | * RUNTHREAD bit is already set, nothing to do. | 61 | * RUNTHREAD bit is already set, nothing to do. |
| 62 | */ | 62 | */ |
| 63 | if (test_bit(IRQTF_DIED, &action->thread_flags) || | 63 | if ((action->thread->flags & PF_EXITING) || |
| 64 | test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)) | 64 | test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)) |
| 65 | return; | 65 | return; |
| 66 | 66 | ||
| @@ -110,6 +110,18 @@ static void irq_wake_thread(struct irq_desc *desc, struct irqaction *action) | |||
| 110 | * threads_oneshot untouched and runs the thread another time. | 110 | * threads_oneshot untouched and runs the thread another time. |
| 111 | */ | 111 | */ |
| 112 | desc->threads_oneshot |= action->thread_mask; | 112 | desc->threads_oneshot |= action->thread_mask; |
| 113 | |||
| 114 | /* | ||
| 115 | * We increment the threads_active counter in case we wake up | ||
| 116 | * the irq thread. The irq thread decrements the counter when | ||
| 117 | * it returns from the handler or in the exit path and wakes | ||
| 118 | * up waiters which are stuck in synchronize_irq() when the | ||
| 119 | * active count becomes zero. synchronize_irq() is serialized | ||
| 120 | * against this code (hard irq handler) via IRQS_INPROGRESS | ||
| 121 | * like the finalize_oneshot() code. See comment above. | ||
| 122 | */ | ||
| 123 | atomic_inc(&desc->threads_active); | ||
| 124 | |||
| 113 | wake_up_process(action->thread); | 125 | wake_up_process(action->thread); |
| 114 | } | 126 | } |
| 115 | 127 | ||
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 40378ff877e7..8e5c56b3b7d9 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
| @@ -20,14 +20,12 @@ extern bool noirqdebug; | |||
| 20 | /* | 20 | /* |
| 21 | * Bits used by threaded handlers: | 21 | * Bits used by threaded handlers: |
| 22 | * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run | 22 | * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run |
| 23 | * IRQTF_DIED - handler thread died | ||
| 24 | * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed | 23 | * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed |
| 25 | * IRQTF_AFFINITY - irq thread is requested to adjust affinity | 24 | * IRQTF_AFFINITY - irq thread is requested to adjust affinity |
| 26 | * IRQTF_FORCED_THREAD - irq action is force threaded | 25 | * IRQTF_FORCED_THREAD - irq action is force threaded |
| 27 | */ | 26 | */ |
| 28 | enum { | 27 | enum { |
| 29 | IRQTF_RUNTHREAD, | 28 | IRQTF_RUNTHREAD, |
| 30 | IRQTF_DIED, | ||
| 31 | IRQTF_WARNED, | 29 | IRQTF_WARNED, |
| 32 | IRQTF_AFFINITY, | 30 | IRQTF_AFFINITY, |
| 33 | IRQTF_FORCED_THREAD, | 31 | IRQTF_FORCED_THREAD, |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0f0d4704ddd8..b0ccd1ac2d6a 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
| @@ -759,6 +759,13 @@ static irqreturn_t irq_thread_fn(struct irq_desc *desc, | |||
| 759 | return ret; | 759 | return ret; |
| 760 | } | 760 | } |
| 761 | 761 | ||
| 762 | static void wake_threads_waitq(struct irq_desc *desc) | ||
| 763 | { | ||
| 764 | if (atomic_dec_and_test(&desc->threads_active) && | ||
| 765 | waitqueue_active(&desc->wait_for_threads)) | ||
| 766 | wake_up(&desc->wait_for_threads); | ||
| 767 | } | ||
| 768 | |||
| 762 | /* | 769 | /* |
| 763 | * Interrupt handler thread | 770 | * Interrupt handler thread |
| 764 | */ | 771 | */ |
| @@ -771,57 +778,41 @@ static int irq_thread(void *data) | |||
| 771 | struct irq_desc *desc = irq_to_desc(action->irq); | 778 | struct irq_desc *desc = irq_to_desc(action->irq); |
| 772 | irqreturn_t (*handler_fn)(struct irq_desc *desc, | 779 | irqreturn_t (*handler_fn)(struct irq_desc *desc, |
| 773 | struct irqaction *action); | 780 | struct irqaction *action); |
| 774 | int wake; | ||
| 775 | 781 | ||
| 776 | if (force_irqthreads & test_bit(IRQTF_FORCED_THREAD, | 782 | if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD, |
| 777 | &action->thread_flags)) | 783 | &action->thread_flags)) |
| 778 | handler_fn = irq_forced_thread_fn; | 784 | handler_fn = irq_forced_thread_fn; |
| 779 | else | 785 | else |
| 780 | handler_fn = irq_thread_fn; | 786 | handler_fn = irq_thread_fn; |
| 781 | 787 | ||
| 782 | sched_setscheduler(current, SCHED_FIFO, ¶m); | 788 | sched_setscheduler(current, SCHED_FIFO, ¶m); |
| 783 | current->irqaction = action; | 789 | current->irq_thread = 1; |
| 784 | 790 | ||
| 785 | while (!irq_wait_for_interrupt(action)) { | 791 | while (!irq_wait_for_interrupt(action)) { |
| 792 | irqreturn_t action_ret; | ||
| 786 | 793 | ||
| 787 | irq_thread_check_affinity(desc, action); | 794 | irq_thread_check_affinity(desc, action); |
| 788 | 795 | ||
| 789 | atomic_inc(&desc->threads_active); | 796 | action_ret = handler_fn(desc, action); |
| 797 | if (!noirqdebug) | ||
| 798 | note_interrupt(action->irq, desc, action_ret); | ||
| 790 | 799 | ||
| 791 | raw_spin_lock_irq(&desc->lock); | 800 | wake_threads_waitq(desc); |
| 792 | if (unlikely(irqd_irq_disabled(&desc->irq_data))) { | ||
| 793 | /* | ||
| 794 | * CHECKME: We might need a dedicated | ||
| 795 | * IRQ_THREAD_PENDING flag here, which | ||
| 796 | * retriggers the thread in check_irq_resend() | ||
| 797 | * but AFAICT IRQS_PENDING should be fine as it | ||
| 798 | * retriggers the interrupt itself --- tglx | ||
| 799 | */ | ||
| 800 | desc->istate |= IRQS_PENDING; | ||
| 801 | raw_spin_unlock_irq(&desc->lock); | ||
| 802 | } else { | ||
| 803 | irqreturn_t action_ret; | ||
| 804 | |||
| 805 | raw_spin_unlock_irq(&desc->lock); | ||
| 806 | action_ret = handler_fn(desc, action); | ||
| 807 | if (!noirqdebug) | ||
| 808 | note_interrupt(action->irq, desc, action_ret); | ||
| 809 | } | ||
| 810 | |||
| 811 | wake = atomic_dec_and_test(&desc->threads_active); | ||
| 812 | |||
| 813 | if (wake && waitqueue_active(&desc->wait_for_threads)) | ||
| 814 | wake_up(&desc->wait_for_threads); | ||
| 815 | } | 801 | } |
| 816 | 802 | ||
| 817 | /* Prevent a stale desc->threads_oneshot */ | ||
| 818 | irq_finalize_oneshot(desc, action, true); | ||
| 819 | |||
| 820 | /* | 803 | /* |
| 821 | * Clear irqaction. Otherwise exit_irq_thread() would make | 804 | * This is the regular exit path. __free_irq() is stopping the |
| 805 | * thread via kthread_stop() after calling | ||
| 806 | * synchronize_irq(). So neither IRQTF_RUNTHREAD nor the | ||
| 807 | * oneshot mask bit can be set. We cannot verify that as we | ||
| 808 | * cannot touch the oneshot mask at this point anymore as | ||
| 809 | * __setup_irq() might have given out currents thread_mask | ||
| 810 | * again. | ||
| 811 | * | ||
| 812 | * Clear irq_thread. Otherwise exit_irq_thread() would make | ||
| 822 | * fuzz about an active irq thread going into nirvana. | 813 | * fuzz about an active irq thread going into nirvana. |
| 823 | */ | 814 | */ |
| 824 | current->irqaction = NULL; | 815 | current->irq_thread = 0; |
| 825 | return 0; | 816 | return 0; |
| 826 | } | 817 | } |
| 827 | 818 | ||
| @@ -832,27 +823,28 @@ void exit_irq_thread(void) | |||
| 832 | { | 823 | { |
| 833 | struct task_struct *tsk = current; | 824 | struct task_struct *tsk = current; |
| 834 | struct irq_desc *desc; | 825 | struct irq_desc *desc; |
| 826 | struct irqaction *action; | ||
| 835 | 827 | ||
| 836 | if (!tsk->irqaction) | 828 | if (!tsk->irq_thread) |
| 837 | return; | 829 | return; |
| 838 | 830 | ||
| 831 | action = kthread_data(tsk); | ||
| 832 | |||
| 839 | printk(KERN_ERR | 833 | printk(KERN_ERR |
| 840 | "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", | 834 | "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", |
| 841 | tsk->comm ? tsk->comm : "", tsk->pid, tsk->irqaction->irq); | 835 | tsk->comm ? tsk->comm : "", tsk->pid, action->irq); |
| 842 | 836 | ||
| 843 | desc = irq_to_desc(tsk->irqaction->irq); | 837 | desc = irq_to_desc(action->irq); |
| 844 | 838 | ||
| 845 | /* | 839 | /* |
| 846 | * Prevent a stale desc->threads_oneshot. Must be called | 840 | * If IRQTF_RUNTHREAD is set, we need to decrement |
| 847 | * before setting the IRQTF_DIED flag. | 841 | * desc->threads_active and wake possible waiters. |
| 848 | */ | 842 | */ |
| 849 | irq_finalize_oneshot(desc, tsk->irqaction, true); | 843 | if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags)) |
| 844 | wake_threads_waitq(desc); | ||
| 850 | 845 | ||
| 851 | /* | 846 | /* Prevent a stale desc->threads_oneshot */ |
| 852 | * Set the THREAD DIED flag to prevent further wakeups of the | 847 | irq_finalize_oneshot(desc, action, true); |
| 853 | * soon to be gone threaded handler. | ||
| 854 | */ | ||
| 855 | set_bit(IRQTF_DIED, &tsk->irqaction->flags); | ||
| 856 | } | 848 | } |
| 857 | 849 | ||
| 858 | static void irq_setup_forced_threading(struct irqaction *new) | 850 | static void irq_setup_forced_threading(struct irqaction *new) |
| @@ -1135,8 +1127,7 @@ out_thread: | |||
| 1135 | struct task_struct *t = new->thread; | 1127 | struct task_struct *t = new->thread; |
| 1136 | 1128 | ||
| 1137 | new->thread = NULL; | 1129 | new->thread = NULL; |
| 1138 | if (likely(!test_bit(IRQTF_DIED, &new->thread_flags))) | 1130 | kthread_stop(t); |
| 1139 | kthread_stop(t); | ||
| 1140 | put_task_struct(t); | 1131 | put_task_struct(t); |
| 1141 | } | 1132 | } |
| 1142 | out_mput: | 1133 | out_mput: |
| @@ -1246,8 +1237,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) | |||
| 1246 | #endif | 1237 | #endif |
| 1247 | 1238 | ||
| 1248 | if (action->thread) { | 1239 | if (action->thread) { |
| 1249 | if (!test_bit(IRQTF_DIED, &action->thread_flags)) | 1240 | kthread_stop(action->thread); |
| 1250 | kthread_stop(action->thread); | ||
| 1251 | put_task_struct(action->thread); | 1241 | put_task_struct(action->thread); |
| 1252 | } | 1242 | } |
| 1253 | 1243 | ||
diff --git a/kernel/softirq.c b/kernel/softirq.c index 4eb3a0fa351e..c82d95a022ef 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -310,31 +310,21 @@ void irq_enter(void) | |||
| 310 | __irq_enter(); | 310 | __irq_enter(); |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED | ||
| 314 | static inline void invoke_softirq(void) | 313 | static inline void invoke_softirq(void) |
| 315 | { | 314 | { |
| 316 | if (!force_irqthreads) | 315 | if (!force_irqthreads) { |
| 316 | #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED | ||
| 317 | __do_softirq(); | 317 | __do_softirq(); |
| 318 | else { | ||
| 319 | __local_bh_disable((unsigned long)__builtin_return_address(0), | ||
| 320 | SOFTIRQ_OFFSET); | ||
| 321 | wakeup_softirqd(); | ||
| 322 | __local_bh_enable(SOFTIRQ_OFFSET); | ||
| 323 | } | ||
| 324 | } | ||
| 325 | #else | 318 | #else |
| 326 | static inline void invoke_softirq(void) | ||
| 327 | { | ||
| 328 | if (!force_irqthreads) | ||
| 329 | do_softirq(); | 319 | do_softirq(); |
| 330 | else { | 320 | #endif |
| 321 | } else { | ||
| 331 | __local_bh_disable((unsigned long)__builtin_return_address(0), | 322 | __local_bh_disable((unsigned long)__builtin_return_address(0), |
| 332 | SOFTIRQ_OFFSET); | 323 | SOFTIRQ_OFFSET); |
| 333 | wakeup_softirqd(); | 324 | wakeup_softirqd(); |
| 334 | __local_bh_enable(SOFTIRQ_OFFSET); | 325 | __local_bh_enable(SOFTIRQ_OFFSET); |
| 335 | } | 326 | } |
| 336 | } | 327 | } |
| 337 | #endif | ||
| 338 | 328 | ||
| 339 | /* | 329 | /* |
| 340 | * Exit an interrupt context. Process softirqs if needed and possible: | 330 | * Exit an interrupt context. Process softirqs if needed and possible: |
