aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-11 20:02:59 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-11 20:02:59 -0500
commit1006fae359cc810c16354805c0cffbb6ffee602e (patch)
treebd69f7a235f679a8336b237ed9722bb7f64db39a
parent70fdcb83db15c85a0495b07dc55d9347a4c2efd9 (diff)
parent5702941eec32cfd7b8cf9e36a0936e48170011a4 (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/Kconfig10
-rw-r--r--arch/arm/mach-bcm2835/bcm2835.c5
-rw-r--r--arch/metag/kernel/irq.c52
-rw-r--r--arch/parisc/kernel/irq.c17
-rw-r--r--arch/powerpc/Kconfig1
-rw-r--r--arch/powerpc/kernel/irq.c17
-rw-r--r--arch/s390/kernel/irq.c52
-rw-r--r--arch/sh/kernel/irq.c57
-rw-r--r--arch/sparc/kernel/irq_64.c31
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/kernel/entry_64.S4
-rw-r--r--arch/x86/kernel/i8259.c3
-rw-r--r--arch/x86/kernel/irq_32.c30
-rw-r--r--arch/x86/kernel/irq_64.c21
-rw-r--r--drivers/irqchip/irq-bcm2835.c22
-rw-r--r--include/linux/interrupt.h11
-rw-r--r--include/linux/irqchip/bcm2835.h29
-rw-r--r--kernel/softirq.c37
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
393config 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
131DT_MACHINE_START(BCM2835, "BCM2835") 131DT_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
160extern asmlinkage void __do_softirq(void); 160extern asmlinkage void __do_softirq(void);
161 161
162asmlinkage void do_softirq(void) 162void 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
498asmlinkage void do_softirq(void) 498void 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
142config EARLY_PRINTK 143config 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
597static inline void do_softirq_onstack(void) 597void 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
615void 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
630irq_hw_number_t virq_to_hw(unsigned int virq) 615irq_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 */
160asmlinkage void do_softirq(void) 160void 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
152asmlinkage void do_softirq(void) 152void 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
195static inline void handle_one_irq(unsigned int irq) 180static 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
701void do_softirq(void) 701void 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
127config INSTRUCTION_DECODER 128config 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. */
1345ENTRY(call_softirq) 1345ENTRY(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
1362END(call_softirq) 1362END(do_softirq_own_stack)
1363 1363
1364#ifdef CONFIG_XEN 1364#ifdef CONFIG_XEN
1365zeroentry xen_hypervisor_callback xen_do_hypervisor_callback 1365zeroentry 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
152asmlinkage void do_softirq(void) 152void 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
183bool handle_irq(unsigned irq, struct pt_regs *regs) 169bool 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
92extern void call_softirq(void);
93
94asmlinkage 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
95static struct armctrl_ic intc __read_mostly; 97static struct armctrl_ic intc __read_mostly;
98static asmlinkage void __exception_irq_entry bcm2835_handle_irq(
99 struct pt_regs *regs);
96 100
97static void armctrl_mask_irq(struct irq_data *d) 101static 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
170static struct of_device_id irq_of_match[] __initconst = {
171 { .compatible = "brcm,bcm2835-armctrl-ic", .data = armctrl_of_init },
172 { }
173};
174 171
175void __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
203asmlinkage void __exception_irq_entry bcm2835_handle_irq( 199static 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
222IRQCHIP_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
375asmlinkage void do_softirq(void); 376asmlinkage void do_softirq(void);
376asmlinkage void __do_softirq(void); 377asmlinkage void __do_softirq(void);
378
379#ifdef __ARCH_HAS_DO_SOFTIRQ
380void do_softirq_own_stack(void);
381#else
382static inline void do_softirq_own_stack(void)
383{
384 __do_softirq();
385}
386#endif
387
377extern void open_softirq(int nr, void (*action)(struct softirq_action *)); 388extern void open_softirq(int nr, void (*action)(struct softirq_action *));
378extern void softirq_init(void); 389extern void softirq_init(void);
379extern void __raise_softirq_irqoff(unsigned int nr); 390extern 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
24extern void bcm2835_init_irq(void);
25
26extern 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
135static void __local_bh_enable(unsigned int cnt) 134static 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 */
150void _local_bh_enable(void) 148void _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
288asmlinkage void do_softirq(void) 293asmlinkage 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)
329static inline void invoke_softirq(void) 332static 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();