diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-11 20:02:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-11-11 20:02:59 -0500 |
commit | 1006fae359cc810c16354805c0cffbb6ffee602e (patch) | |
tree | bd69f7a235f679a8336b237ed9722bb7f64db39a | |
parent | 70fdcb83db15c85a0495b07dc55d9347a4c2efd9 (diff) | |
parent | 5702941eec32cfd7b8cf9e36a0936e48170011a4 (diff) |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull IRQ changes from Ingo Molnar:
"The biggest change this cycle are the softirq/hardirq stack
interaction and nesting fixes, cleanups and reorganizations from
Frederic. This is the longer followup story to the softirq nesting
fix that is already upstream (commit ded797547548: "irq: Force hardirq
exit's softirq processing on its own stack")"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
irqchip: bcm2835: Convert to use IRQCHIP_DECLARE macro
powerpc: Tell about irq stack coverage
x86: Tell about irq stack coverage
irq: Optimize softirq stack selection in irq exit
irq: Justify the various softirq stack choices
irq: Improve a bit softirq debugging
irq: Optimize call to softirq on hardirq exit
irq: Consolidate do_softirq() arch overriden implementations
x86/irq: Correct comment about i8259 initialization
-rw-r--r-- | arch/Kconfig | 10 | ||||
-rw-r--r-- | arch/arm/mach-bcm2835/bcm2835.c | 5 | ||||
-rw-r--r-- | arch/metag/kernel/irq.c | 52 | ||||
-rw-r--r-- | arch/parisc/kernel/irq.c | 17 | ||||
-rw-r--r-- | arch/powerpc/Kconfig | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 17 | ||||
-rw-r--r-- | arch/s390/kernel/irq.c | 52 | ||||
-rw-r--r-- | arch/sh/kernel/irq.c | 57 | ||||
-rw-r--r-- | arch/sparc/kernel/irq_64.c | 31 | ||||
-rw-r--r-- | arch/x86/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/kernel/entry_64.S | 4 | ||||
-rw-r--r-- | arch/x86/kernel/i8259.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/irq_32.c | 30 | ||||
-rw-r--r-- | arch/x86/kernel/irq_64.c | 21 | ||||
-rw-r--r-- | drivers/irqchip/irq-bcm2835.c | 22 | ||||
-rw-r--r-- | include/linux/interrupt.h | 11 | ||||
-rw-r--r-- | include/linux/irqchip/bcm2835.h | 29 | ||||
-rw-r--r-- | kernel/softirq.c | 37 |
18 files changed, 145 insertions, 255 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index af2cc6eabcc7..ad95133f8fae 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
@@ -390,6 +390,16 @@ config HAVE_UNDERSCORE_SYMBOL_PREFIX | |||
390 | Some architectures generate an _ in front of C symbols; things like | 390 | Some architectures generate an _ in front of C symbols; things like |
391 | module loading and assembly files need to know about this. | 391 | module loading and assembly files need to know about this. |
392 | 392 | ||
393 | config HAVE_IRQ_EXIT_ON_IRQ_STACK | ||
394 | bool | ||
395 | help | ||
396 | Architecture doesn't only execute the irq handler on the irq stack | ||
397 | but also irq_exit(). This way we can process softirqs on this irq | ||
398 | stack instead of switching to a new one when we call __do_softirq() | ||
399 | in the end of an hardirq. | ||
400 | This spares a stack switch and improves cache usage on softirq | ||
401 | processing. | ||
402 | |||
393 | # | 403 | # |
394 | # ABI hall of shame | 404 | # ABI hall of shame |
395 | # | 405 | # |
diff --git a/arch/arm/mach-bcm2835/bcm2835.c b/arch/arm/mach-bcm2835/bcm2835.c index d50135be0c20..70f2f3925f0e 100644 --- a/arch/arm/mach-bcm2835/bcm2835.c +++ b/arch/arm/mach-bcm2835/bcm2835.c | |||
@@ -14,7 +14,7 @@ | |||
14 | 14 | ||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/irqchip/bcm2835.h> | 17 | #include <linux/irqchip.h> |
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
20 | #include <linux/clk/bcm2835.h> | 20 | #include <linux/clk/bcm2835.h> |
@@ -130,8 +130,7 @@ static const char * const bcm2835_compat[] = { | |||
130 | 130 | ||
131 | DT_MACHINE_START(BCM2835, "BCM2835") | 131 | DT_MACHINE_START(BCM2835, "BCM2835") |
132 | .map_io = bcm2835_map_io, | 132 | .map_io = bcm2835_map_io, |
133 | .init_irq = bcm2835_init_irq, | 133 | .init_irq = irqchip_init, |
134 | .handle_irq = bcm2835_handle_irq, | ||
135 | .init_machine = bcm2835_init, | 134 | .init_machine = bcm2835_init, |
136 | .restart = bcm2835_restart, | 135 | .restart = bcm2835_restart, |
137 | .dt_compat = bcm2835_compat | 136 | .dt_compat = bcm2835_compat |
diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c index 2a2c9d55187e..3b4b7f6c0950 100644 --- a/arch/metag/kernel/irq.c +++ b/arch/metag/kernel/irq.c | |||
@@ -159,44 +159,30 @@ void irq_ctx_exit(int cpu) | |||
159 | 159 | ||
160 | extern asmlinkage void __do_softirq(void); | 160 | extern asmlinkage void __do_softirq(void); |
161 | 161 | ||
162 | asmlinkage void do_softirq(void) | 162 | void do_softirq_own_stack(void) |
163 | { | 163 | { |
164 | unsigned long flags; | ||
165 | struct thread_info *curctx; | 164 | struct thread_info *curctx; |
166 | union irq_ctx *irqctx; | 165 | union irq_ctx *irqctx; |
167 | u32 *isp; | 166 | u32 *isp; |
168 | 167 | ||
169 | if (in_interrupt()) | 168 | curctx = current_thread_info(); |
170 | return; | 169 | irqctx = softirq_ctx[smp_processor_id()]; |
171 | 170 | irqctx->tinfo.task = curctx->task; | |
172 | local_irq_save(flags); | 171 | |
173 | 172 | /* build the stack frame on the softirq stack */ | |
174 | if (local_softirq_pending()) { | 173 | isp = (u32 *) ((char *)irqctx + sizeof(struct thread_info)); |
175 | curctx = current_thread_info(); | 174 | |
176 | irqctx = softirq_ctx[smp_processor_id()]; | 175 | asm volatile ( |
177 | irqctx->tinfo.task = curctx->task; | 176 | "MOV D0.5,%0\n" |
178 | 177 | "SWAP A0StP,D0.5\n" | |
179 | /* build the stack frame on the softirq stack */ | 178 | "CALLR D1RtP,___do_softirq\n" |
180 | isp = (u32 *) ((char *)irqctx + sizeof(struct thread_info)); | 179 | "MOV A0StP,D0.5\n" |
181 | 180 | : | |
182 | asm volatile ( | 181 | : "r" (isp) |
183 | "MOV D0.5,%0\n" | 182 | : "memory", "cc", "D1Ar1", "D0Ar2", "D1Ar3", "D0Ar4", |
184 | "SWAP A0StP,D0.5\n" | 183 | "D1Ar5", "D0Ar6", "D0Re0", "D1Re0", "D0.4", "D1RtP", |
185 | "CALLR D1RtP,___do_softirq\n" | 184 | "D0.5" |
186 | "MOV A0StP,D0.5\n" | 185 | ); |
187 | : | ||
188 | : "r" (isp) | ||
189 | : "memory", "cc", "D1Ar1", "D0Ar2", "D1Ar3", "D0Ar4", | ||
190 | "D1Ar5", "D0Ar6", "D0Re0", "D1Re0", "D0.4", "D1RtP", | ||
191 | "D0.5" | ||
192 | ); | ||
193 | /* | ||
194 | * Shouldn't happen, we returned above if in_interrupt(): | ||
195 | */ | ||
196 | WARN_ON_ONCE(softirq_count()); | ||
197 | } | ||
198 | |||
199 | local_irq_restore(flags); | ||
200 | } | 186 | } |
201 | #endif | 187 | #endif |
202 | 188 | ||
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 501ac8b4dcdf..8ceac4785609 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c | |||
@@ -495,22 +495,9 @@ static void execute_on_irq_stack(void *func, unsigned long param1) | |||
495 | *irq_stack_in_use = 1; | 495 | *irq_stack_in_use = 1; |
496 | } | 496 | } |
497 | 497 | ||
498 | asmlinkage void do_softirq(void) | 498 | void do_softirq_own_stack(void) |
499 | { | 499 | { |
500 | __u32 pending; | 500 | execute_on_irq_stack(__do_softirq, 0); |
501 | unsigned long flags; | ||
502 | |||
503 | if (in_interrupt()) | ||
504 | return; | ||
505 | |||
506 | local_irq_save(flags); | ||
507 | |||
508 | pending = local_softirq_pending(); | ||
509 | |||
510 | if (pending) | ||
511 | execute_on_irq_stack(__do_softirq, 0); | ||
512 | |||
513 | local_irq_restore(flags); | ||
514 | } | 501 | } |
515 | #endif /* CONFIG_IRQSTACKS */ | 502 | #endif /* CONFIG_IRQSTACKS */ |
516 | 503 | ||
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 38f3b7e47ec5..b365d5cbb722 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -138,6 +138,7 @@ config PPC | |||
138 | select OLD_SIGSUSPEND | 138 | select OLD_SIGSUSPEND |
139 | select OLD_SIGACTION if PPC32 | 139 | select OLD_SIGACTION if PPC32 |
140 | select HAVE_DEBUG_STACKOVERFLOW | 140 | select HAVE_DEBUG_STACKOVERFLOW |
141 | select HAVE_IRQ_EXIT_ON_IRQ_STACK | ||
141 | 142 | ||
142 | config EARLY_PRINTK | 143 | config EARLY_PRINTK |
143 | bool | 144 | bool |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index c7cb8c232d2f..ba0165615215 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -594,7 +594,7 @@ void irq_ctx_init(void) | |||
594 | } | 594 | } |
595 | } | 595 | } |
596 | 596 | ||
597 | static inline void do_softirq_onstack(void) | 597 | void do_softirq_own_stack(void) |
598 | { | 598 | { |
599 | struct thread_info *curtp, *irqtp; | 599 | struct thread_info *curtp, *irqtp; |
600 | 600 | ||
@@ -612,21 +612,6 @@ static inline void do_softirq_onstack(void) | |||
612 | set_bits(irqtp->flags, &curtp->flags); | 612 | set_bits(irqtp->flags, &curtp->flags); |
613 | } | 613 | } |
614 | 614 | ||
615 | void do_softirq(void) | ||
616 | { | ||
617 | unsigned long flags; | ||
618 | |||
619 | if (in_interrupt()) | ||
620 | return; | ||
621 | |||
622 | local_irq_save(flags); | ||
623 | |||
624 | if (local_softirq_pending()) | ||
625 | do_softirq_onstack(); | ||
626 | |||
627 | local_irq_restore(flags); | ||
628 | } | ||
629 | |||
630 | irq_hw_number_t virq_to_hw(unsigned int virq) | 615 | irq_hw_number_t virq_to_hw(unsigned int virq) |
631 | { | 616 | { |
632 | struct irq_data *irq_data = irq_get_irq_data(virq); | 617 | struct irq_data *irq_data = irq_get_irq_data(virq); |
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 8ac2097f13d4..bb27a262c44a 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c | |||
@@ -157,39 +157,29 @@ int arch_show_interrupts(struct seq_file *p, int prec) | |||
157 | /* | 157 | /* |
158 | * Switch to the asynchronous interrupt stack for softirq execution. | 158 | * Switch to the asynchronous interrupt stack for softirq execution. |
159 | */ | 159 | */ |
160 | asmlinkage void do_softirq(void) | 160 | void do_softirq_own_stack(void) |
161 | { | 161 | { |
162 | unsigned long flags, old, new; | 162 | unsigned long old, new; |
163 | 163 | ||
164 | if (in_interrupt()) | 164 | /* Get current stack pointer. */ |
165 | return; | 165 | asm volatile("la %0,0(15)" : "=a" (old)); |
166 | 166 | /* Check against async. stack address range. */ | |
167 | local_irq_save(flags); | 167 | new = S390_lowcore.async_stack; |
168 | 168 | if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) { | |
169 | if (local_softirq_pending()) { | 169 | /* Need to switch to the async. stack. */ |
170 | /* Get current stack pointer. */ | 170 | new -= STACK_FRAME_OVERHEAD; |
171 | asm volatile("la %0,0(15)" : "=a" (old)); | 171 | ((struct stack_frame *) new)->back_chain = old; |
172 | /* Check against async. stack address range. */ | 172 | asm volatile(" la 15,0(%0)\n" |
173 | new = S390_lowcore.async_stack; | 173 | " basr 14,%2\n" |
174 | if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) { | 174 | " la 15,0(%1)\n" |
175 | /* Need to switch to the async. stack. */ | 175 | : : "a" (new), "a" (old), |
176 | new -= STACK_FRAME_OVERHEAD; | 176 | "a" (__do_softirq) |
177 | ((struct stack_frame *) new)->back_chain = old; | 177 | : "0", "1", "2", "3", "4", "5", "14", |
178 | 178 | "cc", "memory" ); | |
179 | asm volatile(" la 15,0(%0)\n" | 179 | } else { |
180 | " basr 14,%2\n" | 180 | /* We are already on the async stack. */ |
181 | " la 15,0(%1)\n" | 181 | __do_softirq(); |
182 | : : "a" (new), "a" (old), | ||
183 | "a" (__do_softirq) | ||
184 | : "0", "1", "2", "3", "4", "5", "14", | ||
185 | "cc", "memory" ); | ||
186 | } else { | ||
187 | /* We are already on the async stack. */ | ||
188 | __do_softirq(); | ||
189 | } | ||
190 | } | 182 | } |
191 | |||
192 | local_irq_restore(flags); | ||
193 | } | 183 | } |
194 | 184 | ||
195 | /* | 185 | /* |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 063af10ff3c1..0833736afa32 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -149,47 +149,32 @@ void irq_ctx_exit(int cpu) | |||
149 | hardirq_ctx[cpu] = NULL; | 149 | hardirq_ctx[cpu] = NULL; |
150 | } | 150 | } |
151 | 151 | ||
152 | asmlinkage void do_softirq(void) | 152 | void do_softirq_own_stack(void) |
153 | { | 153 | { |
154 | unsigned long flags; | ||
155 | struct thread_info *curctx; | 154 | struct thread_info *curctx; |
156 | union irq_ctx *irqctx; | 155 | union irq_ctx *irqctx; |
157 | u32 *isp; | 156 | u32 *isp; |
158 | 157 | ||
159 | if (in_interrupt()) | 158 | curctx = current_thread_info(); |
160 | return; | 159 | irqctx = softirq_ctx[smp_processor_id()]; |
161 | 160 | irqctx->tinfo.task = curctx->task; | |
162 | local_irq_save(flags); | 161 | irqctx->tinfo.previous_sp = current_stack_pointer; |
163 | 162 | ||
164 | if (local_softirq_pending()) { | 163 | /* build the stack frame on the softirq stack */ |
165 | curctx = current_thread_info(); | 164 | isp = (u32 *)((char *)irqctx + sizeof(*irqctx)); |
166 | irqctx = softirq_ctx[smp_processor_id()]; | 165 | |
167 | irqctx->tinfo.task = curctx->task; | 166 | __asm__ __volatile__ ( |
168 | irqctx->tinfo.previous_sp = current_stack_pointer; | 167 | "mov r15, r9 \n" |
169 | 168 | "jsr @%0 \n" | |
170 | /* build the stack frame on the softirq stack */ | 169 | /* switch to the softirq stack */ |
171 | isp = (u32 *)((char *)irqctx + sizeof(*irqctx)); | 170 | " mov %1, r15 \n" |
172 | 171 | /* restore the thread stack */ | |
173 | __asm__ __volatile__ ( | 172 | "mov r9, r15 \n" |
174 | "mov r15, r9 \n" | 173 | : /* no outputs */ |
175 | "jsr @%0 \n" | 174 | : "r" (__do_softirq), "r" (isp) |
176 | /* switch to the softirq stack */ | 175 | : "memory", "r0", "r1", "r2", "r3", "r4", |
177 | " mov %1, r15 \n" | 176 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" |
178 | /* restore the thread stack */ | 177 | ); |
179 | "mov r9, r15 \n" | ||
180 | : /* no outputs */ | ||
181 | : "r" (__do_softirq), "r" (isp) | ||
182 | : "memory", "r0", "r1", "r2", "r3", "r4", | ||
183 | "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr" | ||
184 | ); | ||
185 | |||
186 | /* | ||
187 | * Shouldn't happen, we returned above if in_interrupt(): | ||
188 | */ | ||
189 | WARN_ON_ONCE(softirq_count()); | ||
190 | } | ||
191 | |||
192 | local_irq_restore(flags); | ||
193 | } | 178 | } |
194 | #else | 179 | #else |
195 | static inline void handle_one_irq(unsigned int irq) | 180 | static inline void handle_one_irq(unsigned int irq) |
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index d4840cec2c55..666193f4e8bb 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
@@ -698,30 +698,19 @@ void __irq_entry handler_irq(int pil, struct pt_regs *regs) | |||
698 | set_irq_regs(old_regs); | 698 | set_irq_regs(old_regs); |
699 | } | 699 | } |
700 | 700 | ||
701 | void do_softirq(void) | 701 | void do_softirq_own_stack(void) |
702 | { | 702 | { |
703 | unsigned long flags; | 703 | void *orig_sp, *sp = softirq_stack[smp_processor_id()]; |
704 | |||
705 | if (in_interrupt()) | ||
706 | return; | ||
707 | |||
708 | local_irq_save(flags); | ||
709 | 704 | ||
710 | if (local_softirq_pending()) { | 705 | sp += THREAD_SIZE - 192 - STACK_BIAS; |
711 | void *orig_sp, *sp = softirq_stack[smp_processor_id()]; | ||
712 | |||
713 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
714 | |||
715 | __asm__ __volatile__("mov %%sp, %0\n\t" | ||
716 | "mov %1, %%sp" | ||
717 | : "=&r" (orig_sp) | ||
718 | : "r" (sp)); | ||
719 | __do_softirq(); | ||
720 | __asm__ __volatile__("mov %0, %%sp" | ||
721 | : : "r" (orig_sp)); | ||
722 | } | ||
723 | 706 | ||
724 | local_irq_restore(flags); | 707 | __asm__ __volatile__("mov %%sp, %0\n\t" |
708 | "mov %1, %%sp" | ||
709 | : "=&r" (orig_sp) | ||
710 | : "r" (sp)); | ||
711 | __do_softirq(); | ||
712 | __asm__ __volatile__("mov %0, %%sp" | ||
713 | : : "r" (orig_sp)); | ||
725 | } | 714 | } |
726 | 715 | ||
727 | #ifdef CONFIG_HOTPLUG_CPU | 716 | #ifdef CONFIG_HOTPLUG_CPU |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f67e839f06c8..5cd6eea9b7b3 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -123,6 +123,7 @@ config X86 | |||
123 | select COMPAT_OLD_SIGACTION if IA32_EMULATION | 123 | select COMPAT_OLD_SIGACTION if IA32_EMULATION |
124 | select RTC_LIB | 124 | select RTC_LIB |
125 | select HAVE_DEBUG_STACKOVERFLOW | 125 | select HAVE_DEBUG_STACKOVERFLOW |
126 | select HAVE_IRQ_EXIT_ON_IRQ_STACK if X86_64 | ||
126 | 127 | ||
127 | config INSTRUCTION_DECODER | 128 | config INSTRUCTION_DECODER |
128 | def_bool y | 129 | def_bool y |
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S index b077f4cc225a..083da7c2f40d 100644 --- a/arch/x86/kernel/entry_64.S +++ b/arch/x86/kernel/entry_64.S | |||
@@ -1342,7 +1342,7 @@ bad_gs: | |||
1342 | .previous | 1342 | .previous |
1343 | 1343 | ||
1344 | /* Call softirq on interrupt stack. Interrupts are off. */ | 1344 | /* Call softirq on interrupt stack. Interrupts are off. */ |
1345 | ENTRY(call_softirq) | 1345 | ENTRY(do_softirq_own_stack) |
1346 | CFI_STARTPROC | 1346 | CFI_STARTPROC |
1347 | pushq_cfi %rbp | 1347 | pushq_cfi %rbp |
1348 | CFI_REL_OFFSET rbp,0 | 1348 | CFI_REL_OFFSET rbp,0 |
@@ -1359,7 +1359,7 @@ ENTRY(call_softirq) | |||
1359 | decl PER_CPU_VAR(irq_count) | 1359 | decl PER_CPU_VAR(irq_count) |
1360 | ret | 1360 | ret |
1361 | CFI_ENDPROC | 1361 | CFI_ENDPROC |
1362 | END(call_softirq) | 1362 | END(do_softirq_own_stack) |
1363 | 1363 | ||
1364 | #ifdef CONFIG_XEN | 1364 | #ifdef CONFIG_XEN |
1365 | zeroentry xen_hypervisor_callback xen_do_hypervisor_callback | 1365 | zeroentry xen_hypervisor_callback xen_do_hypervisor_callback |
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index 9a5c460404dc..2e977b5d61dd 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c | |||
@@ -312,8 +312,7 @@ static void init_8259A(int auto_eoi) | |||
312 | */ | 312 | */ |
313 | outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ | 313 | outb_pic(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ |
314 | 314 | ||
315 | /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 on x86-64, | 315 | /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */ |
316 | to 0x20-0x27 on i386 */ | ||
317 | outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR); | 316 | outb_pic(IRQ0_VECTOR, PIC_MASTER_IMR); |
318 | 317 | ||
319 | /* 8259A-1 (the master) has a slave on IR2 */ | 318 | /* 8259A-1 (the master) has a slave on IR2 */ |
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 4186755f1d7c..8a5bb01dbc0e 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c | |||
@@ -149,35 +149,21 @@ void irq_ctx_init(int cpu) | |||
149 | cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu)); | 149 | cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu)); |
150 | } | 150 | } |
151 | 151 | ||
152 | asmlinkage void do_softirq(void) | 152 | void do_softirq_own_stack(void) |
153 | { | 153 | { |
154 | unsigned long flags; | ||
155 | struct thread_info *curctx; | 154 | struct thread_info *curctx; |
156 | union irq_ctx *irqctx; | 155 | union irq_ctx *irqctx; |
157 | u32 *isp; | 156 | u32 *isp; |
158 | 157 | ||
159 | if (in_interrupt()) | 158 | curctx = current_thread_info(); |
160 | return; | 159 | irqctx = __this_cpu_read(softirq_ctx); |
161 | 160 | irqctx->tinfo.task = curctx->task; | |
162 | local_irq_save(flags); | 161 | irqctx->tinfo.previous_esp = current_stack_pointer; |
163 | |||
164 | if (local_softirq_pending()) { | ||
165 | curctx = current_thread_info(); | ||
166 | irqctx = __this_cpu_read(softirq_ctx); | ||
167 | irqctx->tinfo.task = curctx->task; | ||
168 | irqctx->tinfo.previous_esp = current_stack_pointer; | ||
169 | |||
170 | /* build the stack frame on the softirq stack */ | ||
171 | isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); | ||
172 | 162 | ||
173 | call_on_stack(__do_softirq, isp); | 163 | /* build the stack frame on the softirq stack */ |
174 | /* | 164 | isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); |
175 | * Shouldn't happen, we returned above if in_interrupt(): | ||
176 | */ | ||
177 | WARN_ON_ONCE(softirq_count()); | ||
178 | } | ||
179 | 165 | ||
180 | local_irq_restore(flags); | 166 | call_on_stack(__do_softirq, isp); |
181 | } | 167 | } |
182 | 168 | ||
183 | bool handle_irq(unsigned irq, struct pt_regs *regs) | 169 | bool handle_irq(unsigned irq, struct pt_regs *regs) |
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index d04d3ecded62..4d1c746892eb 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c | |||
@@ -87,24 +87,3 @@ bool handle_irq(unsigned irq, struct pt_regs *regs) | |||
87 | generic_handle_irq_desc(irq, desc); | 87 | generic_handle_irq_desc(irq, desc); |
88 | return true; | 88 | return true; |
89 | } | 89 | } |
90 | |||
91 | |||
92 | extern void call_softirq(void); | ||
93 | |||
94 | asmlinkage void do_softirq(void) | ||
95 | { | ||
96 | __u32 pending; | ||
97 | unsigned long flags; | ||
98 | |||
99 | if (in_interrupt()) | ||
100 | return; | ||
101 | |||
102 | local_irq_save(flags); | ||
103 | pending = local_softirq_pending(); | ||
104 | /* Switch to interrupt stack */ | ||
105 | if (pending) { | ||
106 | call_softirq(); | ||
107 | WARN_ON_ONCE(softirq_count()); | ||
108 | } | ||
109 | local_irq_restore(flags); | ||
110 | } | ||
diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index 16c78f1c5ef2..1693b8e7f26a 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c | |||
@@ -49,9 +49,11 @@ | |||
49 | #include <linux/of_address.h> | 49 | #include <linux/of_address.h> |
50 | #include <linux/of_irq.h> | 50 | #include <linux/of_irq.h> |
51 | #include <linux/irqdomain.h> | 51 | #include <linux/irqdomain.h> |
52 | #include <linux/irqchip/bcm2835.h> | ||
53 | 52 | ||
54 | #include <asm/exception.h> | 53 | #include <asm/exception.h> |
54 | #include <asm/mach/irq.h> | ||
55 | |||
56 | #include "irqchip.h" | ||
55 | 57 | ||
56 | /* Put the bank and irq (32 bits) into the hwirq */ | 58 | /* Put the bank and irq (32 bits) into the hwirq */ |
57 | #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) | 59 | #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) |
@@ -93,6 +95,8 @@ struct armctrl_ic { | |||
93 | }; | 95 | }; |
94 | 96 | ||
95 | static struct armctrl_ic intc __read_mostly; | 97 | static struct armctrl_ic intc __read_mostly; |
98 | static asmlinkage void __exception_irq_entry bcm2835_handle_irq( | ||
99 | struct pt_regs *regs); | ||
96 | 100 | ||
97 | static void armctrl_mask_irq(struct irq_data *d) | 101 | static void armctrl_mask_irq(struct irq_data *d) |
98 | { | 102 | { |
@@ -164,17 +168,9 @@ static int __init armctrl_of_init(struct device_node *node, | |||
164 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 168 | set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); |
165 | } | 169 | } |
166 | } | 170 | } |
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static struct of_device_id irq_of_match[] __initconst = { | ||
171 | { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init }, | ||
172 | { } | ||
173 | }; | ||
174 | 171 | ||
175 | void __init bcm2835_init_irq(void) | 172 | set_handle_irq(bcm2835_handle_irq); |
176 | { | 173 | return 0; |
177 | of_irq_init(irq_of_match); | ||
178 | } | 174 | } |
179 | 175 | ||
180 | /* | 176 | /* |
@@ -200,7 +196,7 @@ static void armctrl_handle_shortcut(int bank, struct pt_regs *regs, | |||
200 | handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); | 196 | handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); |
201 | } | 197 | } |
202 | 198 | ||
203 | asmlinkage void __exception_irq_entry bcm2835_handle_irq( | 199 | static asmlinkage void __exception_irq_entry bcm2835_handle_irq( |
204 | struct pt_regs *regs) | 200 | struct pt_regs *regs) |
205 | { | 201 | { |
206 | u32 stat, irq; | 202 | u32 stat, irq; |
@@ -222,3 +218,5 @@ asmlinkage void __exception_irq_entry bcm2835_handle_irq( | |||
222 | } | 218 | } |
223 | } | 219 | } |
224 | } | 220 | } |
221 | |||
222 | IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); | ||
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 5e865b554940..c9e831dc80bc 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -19,6 +19,7 @@ | |||
19 | 19 | ||
20 | #include <linux/atomic.h> | 20 | #include <linux/atomic.h> |
21 | #include <asm/ptrace.h> | 21 | #include <asm/ptrace.h> |
22 | #include <asm/irq.h> | ||
22 | 23 | ||
23 | /* | 24 | /* |
24 | * These correspond to the IORESOURCE_IRQ_* defines in | 25 | * These correspond to the IORESOURCE_IRQ_* defines in |
@@ -374,6 +375,16 @@ struct softirq_action | |||
374 | 375 | ||
375 | asmlinkage void do_softirq(void); | 376 | asmlinkage void do_softirq(void); |
376 | asmlinkage void __do_softirq(void); | 377 | asmlinkage void __do_softirq(void); |
378 | |||
379 | #ifdef __ARCH_HAS_DO_SOFTIRQ | ||
380 | void do_softirq_own_stack(void); | ||
381 | #else | ||
382 | static inline void do_softirq_own_stack(void) | ||
383 | { | ||
384 | __do_softirq(); | ||
385 | } | ||
386 | #endif | ||
387 | |||
377 | extern void open_softirq(int nr, void (*action)(struct softirq_action *)); | 388 | extern void open_softirq(int nr, void (*action)(struct softirq_action *)); |
378 | extern void softirq_init(void); | 389 | extern void softirq_init(void); |
379 | extern void __raise_softirq_irqoff(unsigned int nr); | 390 | extern void __raise_softirq_irqoff(unsigned int nr); |
diff --git a/include/linux/irqchip/bcm2835.h b/include/linux/irqchip/bcm2835.h deleted file mode 100644 index 48a859bc9dca..000000000000 --- a/include/linux/irqchip/bcm2835.h +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Broadcom | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef __LINUX_IRQCHIP_BCM2835_H_ | ||
20 | #define __LINUX_IRQCHIP_BCM2835_H_ | ||
21 | |||
22 | #include <asm/exception.h> | ||
23 | |||
24 | extern void bcm2835_init_irq(void); | ||
25 | |||
26 | extern asmlinkage void __exception_irq_entry bcm2835_handle_irq( | ||
27 | struct pt_regs *regs); | ||
28 | |||
29 | #endif | ||
diff --git a/kernel/softirq.c b/kernel/softirq.c index d7d498d8cc4f..dacd0ab51df4 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #define CREATE_TRACE_POINTS | 29 | #define CREATE_TRACE_POINTS |
30 | #include <trace/events/irq.h> | 30 | #include <trace/events/irq.h> |
31 | 31 | ||
32 | #include <asm/irq.h> | ||
33 | /* | 32 | /* |
34 | - No shared variables, all the data are CPU local. | 33 | - No shared variables, all the data are CPU local. |
35 | - If a softirq needs serialization, let it serialize itself | 34 | - If a softirq needs serialization, let it serialize itself |
@@ -134,7 +133,6 @@ EXPORT_SYMBOL(local_bh_disable); | |||
134 | 133 | ||
135 | static void __local_bh_enable(unsigned int cnt) | 134 | static void __local_bh_enable(unsigned int cnt) |
136 | { | 135 | { |
137 | WARN_ON_ONCE(in_irq()); | ||
138 | WARN_ON_ONCE(!irqs_disabled()); | 136 | WARN_ON_ONCE(!irqs_disabled()); |
139 | 137 | ||
140 | if (softirq_count() == cnt) | 138 | if (softirq_count() == cnt) |
@@ -149,6 +147,7 @@ static void __local_bh_enable(unsigned int cnt) | |||
149 | */ | 147 | */ |
150 | void _local_bh_enable(void) | 148 | void _local_bh_enable(void) |
151 | { | 149 | { |
150 | WARN_ON_ONCE(in_irq()); | ||
152 | __local_bh_enable(SOFTIRQ_DISABLE_OFFSET); | 151 | __local_bh_enable(SOFTIRQ_DISABLE_OFFSET); |
153 | } | 152 | } |
154 | 153 | ||
@@ -171,8 +170,13 @@ static inline void _local_bh_enable_ip(unsigned long ip) | |||
171 | */ | 170 | */ |
172 | sub_preempt_count(SOFTIRQ_DISABLE_OFFSET - 1); | 171 | sub_preempt_count(SOFTIRQ_DISABLE_OFFSET - 1); |
173 | 172 | ||
174 | if (unlikely(!in_interrupt() && local_softirq_pending())) | 173 | if (unlikely(!in_interrupt() && local_softirq_pending())) { |
174 | /* | ||
175 | * Run softirq if any pending. And do it in its own stack | ||
176 | * as we may be calling this deep in a task call stack already. | ||
177 | */ | ||
175 | do_softirq(); | 178 | do_softirq(); |
179 | } | ||
176 | 180 | ||
177 | dec_preempt_count(); | 181 | dec_preempt_count(); |
178 | #ifdef CONFIG_TRACE_IRQFLAGS | 182 | #ifdef CONFIG_TRACE_IRQFLAGS |
@@ -280,10 +284,11 @@ restart: | |||
280 | 284 | ||
281 | account_irq_exit_time(current); | 285 | account_irq_exit_time(current); |
282 | __local_bh_enable(SOFTIRQ_OFFSET); | 286 | __local_bh_enable(SOFTIRQ_OFFSET); |
287 | WARN_ON_ONCE(in_interrupt()); | ||
283 | tsk_restore_flags(current, old_flags, PF_MEMALLOC); | 288 | tsk_restore_flags(current, old_flags, PF_MEMALLOC); |
284 | } | 289 | } |
285 | 290 | ||
286 | #ifndef __ARCH_HAS_DO_SOFTIRQ | 291 | |
287 | 292 | ||
288 | asmlinkage void do_softirq(void) | 293 | asmlinkage void do_softirq(void) |
289 | { | 294 | { |
@@ -298,13 +303,11 @@ asmlinkage void do_softirq(void) | |||
298 | pending = local_softirq_pending(); | 303 | pending = local_softirq_pending(); |
299 | 304 | ||
300 | if (pending) | 305 | if (pending) |
301 | __do_softirq(); | 306 | do_softirq_own_stack(); |
302 | 307 | ||
303 | local_irq_restore(flags); | 308 | local_irq_restore(flags); |
304 | } | 309 | } |
305 | 310 | ||
306 | #endif | ||
307 | |||
308 | /* | 311 | /* |
309 | * Enter an interrupt context. | 312 | * Enter an interrupt context. |
310 | */ | 313 | */ |
@@ -329,15 +332,21 @@ void irq_enter(void) | |||
329 | static inline void invoke_softirq(void) | 332 | static inline void invoke_softirq(void) |
330 | { | 333 | { |
331 | if (!force_irqthreads) { | 334 | if (!force_irqthreads) { |
335 | #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK | ||
332 | /* | 336 | /* |
333 | * We can safely execute softirq on the current stack if | 337 | * We can safely execute softirq on the current stack if |
334 | * it is the irq stack, because it should be near empty | 338 | * it is the irq stack, because it should be near empty |
335 | * at this stage. But we have no way to know if the arch | 339 | * at this stage. |
336 | * calls irq_exit() on the irq stack. So call softirq | ||
337 | * in its own stack to prevent from any overrun on top | ||
338 | * of a potentially deep task stack. | ||
339 | */ | 340 | */ |
340 | do_softirq(); | 341 | __do_softirq(); |
342 | #else | ||
343 | /* | ||
344 | * Otherwise, irq_exit() is called on the task stack that can | ||
345 | * be potentially deep already. So call softirq in its own stack | ||
346 | * to prevent from any overrun. | ||
347 | */ | ||
348 | do_softirq_own_stack(); | ||
349 | #endif | ||
341 | } else { | 350 | } else { |
342 | wakeup_softirqd(); | 351 | wakeup_softirqd(); |
343 | } | 352 | } |
@@ -771,6 +780,10 @@ static void run_ksoftirqd(unsigned int cpu) | |||
771 | { | 780 | { |
772 | local_irq_disable(); | 781 | local_irq_disable(); |
773 | if (local_softirq_pending()) { | 782 | if (local_softirq_pending()) { |
783 | /* | ||
784 | * We can safely run softirq on inline stack, as we are not deep | ||
785 | * in the task stack here. | ||
786 | */ | ||
774 | __do_softirq(); | 787 | __do_softirq(); |
775 | rcu_note_context_switch(cpu); | 788 | rcu_note_context_switch(cpu); |
776 | local_irq_enable(); | 789 | local_irq_enable(); |