diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 23:33:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 23:33:19 -0400 |
commit | 471368557a734c6c486ee757952c902b36e7fd01 (patch) | |
tree | f192a77d2cb70b1d135e7be62418806e8c590a3e | |
parent | cb60e3e65c1b96a4d6444a7a13dc7dd48bc15a2b (diff) | |
parent | e0d8ffd1df44518cb9ac9b1807d1f13cc100fc2f (diff) |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull core irq changes from Ingo Molnar:
"A collection of small fixes."
By Thomas Gleixner
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
hexagon: Remove select of not longer existing Kconfig switches
arm: Select core options instead of redefining them
genirq: Do not consider disabled wakeup irqs
genirq: Allow check_wakeup_irqs to notice level-triggered interrupts
genirq: Be more informative on irq type mismatch
genirq: Reject bogus threaded irq requests
genirq: Streamline irq_action
-rw-r--r-- | arch/arm/Kconfig | 2 | ||||
-rw-r--r-- | arch/hexagon/Kconfig | 2 | ||||
-rw-r--r-- | include/linux/interrupt.h | 8 | ||||
-rw-r--r-- | kernel/irq/chip.c | 4 | ||||
-rw-r--r-- | kernel/irq/manage.c | 46 | ||||
-rw-r--r-- | kernel/irq/pm.c | 7 | ||||
-rw-r--r-- | kernel/irq/resend.c | 7 |
7 files changed, 51 insertions, 25 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4305ae25652b..002b1c8da225 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -34,6 +34,8 @@ config ARM | |||
34 | select HARDIRQS_SW_RESEND | 34 | select HARDIRQS_SW_RESEND |
35 | select GENERIC_IRQ_PROBE | 35 | select GENERIC_IRQ_PROBE |
36 | select GENERIC_IRQ_SHOW | 36 | select GENERIC_IRQ_SHOW |
37 | select GENERIC_IRQ_PROBE | ||
38 | select HARDIRQS_SW_RESEND | ||
37 | select CPU_PM if (SUSPEND || CPU_IDLE) | 39 | select CPU_PM if (SUSPEND || CPU_IDLE) |
38 | select GENERIC_PCI_IOMAP | 40 | select GENERIC_PCI_IOMAP |
39 | select HAVE_BPF_JIT | 41 | select HAVE_BPF_JIT |
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig index d2e4a3330336..22615dd02219 100644 --- a/arch/hexagon/Kconfig +++ b/arch/hexagon/Kconfig | |||
@@ -18,8 +18,6 @@ config HEXAGON | |||
18 | select GENERIC_ATOMIC64 | 18 | select GENERIC_ATOMIC64 |
19 | select HAVE_PERF_EVENTS | 19 | select HAVE_PERF_EVENTS |
20 | select HAVE_GENERIC_HARDIRQS | 20 | select HAVE_GENERIC_HARDIRQS |
21 | select GENERIC_HARDIRQS_NO__DO_IRQ | ||
22 | select GENERIC_HARDIRQS_NO_DEPRECATED | ||
23 | # GENERIC_ALLOCATOR is used by dma_alloc_coherent() | 21 | # GENERIC_ALLOCATOR is used by dma_alloc_coherent() |
24 | select GENERIC_ALLOCATOR | 22 | select GENERIC_ALLOCATOR |
25 | select GENERIC_IRQ_SHOW | 23 | select GENERIC_IRQ_SHOW |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 2aea5d22db07..c91171599cb6 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -93,27 +93,27 @@ typedef irqreturn_t (*irq_handler_t)(int, void *); | |||
93 | /** | 93 | /** |
94 | * struct irqaction - per interrupt action descriptor | 94 | * struct irqaction - per interrupt action descriptor |
95 | * @handler: interrupt handler function | 95 | * @handler: interrupt handler function |
96 | * @flags: flags (see IRQF_* above) | ||
97 | * @name: name of the device | 96 | * @name: name of the device |
98 | * @dev_id: cookie to identify the device | 97 | * @dev_id: cookie to identify the device |
99 | * @percpu_dev_id: cookie to identify the device | 98 | * @percpu_dev_id: cookie to identify the device |
100 | * @next: pointer to the next irqaction for shared interrupts | 99 | * @next: pointer to the next irqaction for shared interrupts |
101 | * @irq: interrupt number | 100 | * @irq: interrupt number |
102 | * @dir: pointer to the proc/irq/NN/name entry | 101 | * @flags: flags (see IRQF_* above) |
103 | * @thread_fn: interrupt handler function for threaded interrupts | 102 | * @thread_fn: interrupt handler function for threaded interrupts |
104 | * @thread: thread pointer for threaded interrupts | 103 | * @thread: thread pointer for threaded interrupts |
105 | * @thread_flags: flags related to @thread | 104 | * @thread_flags: flags related to @thread |
106 | * @thread_mask: bitmask for keeping track of @thread activity | 105 | * @thread_mask: bitmask for keeping track of @thread activity |
106 | * @dir: pointer to the proc/irq/NN/name entry | ||
107 | */ | 107 | */ |
108 | struct irqaction { | 108 | struct irqaction { |
109 | irq_handler_t handler; | 109 | irq_handler_t handler; |
110 | unsigned long flags; | ||
111 | void *dev_id; | 110 | void *dev_id; |
112 | void __percpu *percpu_dev_id; | 111 | void __percpu *percpu_dev_id; |
113 | struct irqaction *next; | 112 | struct irqaction *next; |
114 | int irq; | ||
115 | irq_handler_t thread_fn; | 113 | irq_handler_t thread_fn; |
116 | struct task_struct *thread; | 114 | struct task_struct *thread; |
115 | unsigned int irq; | ||
116 | unsigned int flags; | ||
117 | unsigned long thread_flags; | 117 | unsigned long thread_flags; |
118 | unsigned long thread_mask; | 118 | unsigned long thread_mask; |
119 | const char *name; | 119 | const char *name; |
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 3914c1e03cff..fc275e4f629b 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c | |||
@@ -379,8 +379,10 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) | |||
379 | * If its disabled or no action available | 379 | * If its disabled or no action available |
380 | * keep it masked and get out of here | 380 | * keep it masked and get out of here |
381 | */ | 381 | */ |
382 | if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) | 382 | if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { |
383 | desc->istate |= IRQS_PENDING; | ||
383 | goto out_unlock; | 384 | goto out_unlock; |
385 | } | ||
384 | 386 | ||
385 | handle_irq_event(desc); | 387 | handle_irq_event(desc); |
386 | 388 | ||
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 89a3ea82569b..585f6381f8e4 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -565,8 +565,8 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
565 | * IRQF_TRIGGER_* but the PIC does not support multiple | 565 | * IRQF_TRIGGER_* but the PIC does not support multiple |
566 | * flow-types? | 566 | * flow-types? |
567 | */ | 567 | */ |
568 | pr_debug("No set_type function for IRQ %d (%s)\n", irq, | 568 | pr_debug("genirq: No set_type function for IRQ %d (%s)\n", irq, |
569 | chip ? (chip->name ? : "unknown") : "unknown"); | 569 | chip ? (chip->name ? : "unknown") : "unknown"); |
570 | return 0; | 570 | return 0; |
571 | } | 571 | } |
572 | 572 | ||
@@ -600,7 +600,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | |||
600 | ret = 0; | 600 | ret = 0; |
601 | break; | 601 | break; |
602 | default: | 602 | default: |
603 | pr_err("setting trigger mode %lu for irq %u failed (%pF)\n", | 603 | pr_err("genirq: Setting trigger mode %lu for irq %u failed (%pF)\n", |
604 | flags, irq, chip->irq_set_type); | 604 | flags, irq, chip->irq_set_type); |
605 | } | 605 | } |
606 | if (unmask) | 606 | if (unmask) |
@@ -837,8 +837,7 @@ void exit_irq_thread(void) | |||
837 | 837 | ||
838 | action = kthread_data(tsk); | 838 | action = kthread_data(tsk); |
839 | 839 | ||
840 | printk(KERN_ERR | 840 | pr_err("genirq: exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", |
841 | "exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", | ||
842 | tsk->comm ? tsk->comm : "", tsk->pid, action->irq); | 841 | tsk->comm ? tsk->comm : "", tsk->pid, action->irq); |
843 | 842 | ||
844 | desc = irq_to_desc(action->irq); | 843 | desc = irq_to_desc(action->irq); |
@@ -878,7 +877,6 @@ static int | |||
878 | __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | 877 | __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) |
879 | { | 878 | { |
880 | struct irqaction *old, **old_ptr; | 879 | struct irqaction *old, **old_ptr; |
881 | const char *old_name = NULL; | ||
882 | unsigned long flags, thread_mask = 0; | 880 | unsigned long flags, thread_mask = 0; |
883 | int ret, nested, shared = 0; | 881 | int ret, nested, shared = 0; |
884 | cpumask_var_t mask; | 882 | cpumask_var_t mask; |
@@ -972,10 +970,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
972 | */ | 970 | */ |
973 | if (!((old->flags & new->flags) & IRQF_SHARED) || | 971 | if (!((old->flags & new->flags) & IRQF_SHARED) || |
974 | ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || | 972 | ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || |
975 | ((old->flags ^ new->flags) & IRQF_ONESHOT)) { | 973 | ((old->flags ^ new->flags) & IRQF_ONESHOT)) |
976 | old_name = old->name; | ||
977 | goto mismatch; | 974 | goto mismatch; |
978 | } | ||
979 | 975 | ||
980 | /* All handlers must agree on per-cpuness */ | 976 | /* All handlers must agree on per-cpuness */ |
981 | if ((old->flags & IRQF_PERCPU) != | 977 | if ((old->flags & IRQF_PERCPU) != |
@@ -1031,6 +1027,27 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1031 | * all existing action->thread_mask bits. | 1027 | * all existing action->thread_mask bits. |
1032 | */ | 1028 | */ |
1033 | new->thread_mask = 1 << ffz(thread_mask); | 1029 | new->thread_mask = 1 << ffz(thread_mask); |
1030 | |||
1031 | } else if (new->handler == irq_default_primary_handler) { | ||
1032 | /* | ||
1033 | * The interrupt was requested with handler = NULL, so | ||
1034 | * we use the default primary handler for it. But it | ||
1035 | * does not have the oneshot flag set. In combination | ||
1036 | * with level interrupts this is deadly, because the | ||
1037 | * default primary handler just wakes the thread, then | ||
1038 | * the irq lines is reenabled, but the device still | ||
1039 | * has the level irq asserted. Rinse and repeat.... | ||
1040 | * | ||
1041 | * While this works for edge type interrupts, we play | ||
1042 | * it safe and reject unconditionally because we can't | ||
1043 | * say for sure which type this interrupt really | ||
1044 | * has. The type flags are unreliable as the | ||
1045 | * underlying chip implementation can override them. | ||
1046 | */ | ||
1047 | pr_err("genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n", | ||
1048 | irq); | ||
1049 | ret = -EINVAL; | ||
1050 | goto out_mask; | ||
1034 | } | 1051 | } |
1035 | 1052 | ||
1036 | if (!shared) { | 1053 | if (!shared) { |
@@ -1078,7 +1095,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1078 | 1095 | ||
1079 | if (nmsk != omsk) | 1096 | if (nmsk != omsk) |
1080 | /* hope the handler works with current trigger mode */ | 1097 | /* hope the handler works with current trigger mode */ |
1081 | pr_warning("IRQ %d uses trigger mode %u; requested %u\n", | 1098 | pr_warning("genirq: irq %d uses trigger mode %u; requested %u\n", |
1082 | irq, nmsk, omsk); | 1099 | irq, nmsk, omsk); |
1083 | } | 1100 | } |
1084 | 1101 | ||
@@ -1115,14 +1132,13 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
1115 | return 0; | 1132 | return 0; |
1116 | 1133 | ||
1117 | mismatch: | 1134 | mismatch: |
1118 | #ifdef CONFIG_DEBUG_SHIRQ | ||
1119 | if (!(new->flags & IRQF_PROBE_SHARED)) { | 1135 | if (!(new->flags & IRQF_PROBE_SHARED)) { |
1120 | printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq); | 1136 | pr_err("genirq: Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n", |
1121 | if (old_name) | 1137 | irq, new->flags, new->name, old->flags, old->name); |
1122 | printk(KERN_ERR "current handler: %s\n", old_name); | 1138 | #ifdef CONFIG_DEBUG_SHIRQ |
1123 | dump_stack(); | 1139 | dump_stack(); |
1124 | } | ||
1125 | #endif | 1140 | #endif |
1141 | } | ||
1126 | ret = -EBUSY; | 1142 | ret = -EBUSY; |
1127 | 1143 | ||
1128 | out_mask: | 1144 | out_mask: |
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index 15e53b1766a6..cb228bf21760 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c | |||
@@ -103,8 +103,13 @@ int check_wakeup_irqs(void) | |||
103 | int irq; | 103 | int irq; |
104 | 104 | ||
105 | for_each_irq_desc(irq, desc) { | 105 | for_each_irq_desc(irq, desc) { |
106 | /* | ||
107 | * Only interrupts which are marked as wakeup source | ||
108 | * and have not been disabled before the suspend check | ||
109 | * can abort suspend. | ||
110 | */ | ||
106 | if (irqd_is_wakeup_set(&desc->irq_data)) { | 111 | if (irqd_is_wakeup_set(&desc->irq_data)) { |
107 | if (desc->istate & IRQS_PENDING) | 112 | if (desc->depth == 1 && desc->istate & IRQS_PENDING) |
108 | return -EBUSY; | 113 | return -EBUSY; |
109 | continue; | 114 | continue; |
110 | } | 115 | } |
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c index 14dd5761e8c9..6454db7b6a4d 100644 --- a/kernel/irq/resend.c +++ b/kernel/irq/resend.c | |||
@@ -58,10 +58,13 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq) | |||
58 | /* | 58 | /* |
59 | * We do not resend level type interrupts. Level type | 59 | * We do not resend level type interrupts. Level type |
60 | * interrupts are resent by hardware when they are still | 60 | * interrupts are resent by hardware when they are still |
61 | * active. | 61 | * active. Clear the pending bit so suspend/resume does not |
62 | * get confused. | ||
62 | */ | 63 | */ |
63 | if (irq_settings_is_level(desc)) | 64 | if (irq_settings_is_level(desc)) { |
65 | desc->istate &= ~IRQS_PENDING; | ||
64 | return; | 66 | return; |
67 | } | ||
65 | if (desc->istate & IRQS_REPLAY) | 68 | if (desc->istate & IRQS_REPLAY) |
66 | return; | 69 | return; |
67 | if (desc->istate & IRQS_PENDING) { | 70 | if (desc->istate & IRQS_PENDING) { |