aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-10-07 17:08:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-10-07 17:19:39 -0400
commit8b5ede69d24db939f52b47effff2f6fe1e83e08b (patch)
treec492c191c688296cdd708e1d9e5fc6cc63197edf
parentfd848319e751739a93aa9fc8182e57e87c5a0df1 (diff)
powerpc/irq: Don't switch to irq stack from softirq stack
irq_exit() is now called on the irq stack, which can trigger a switch to the softirq stack from the irq stack. If an interrupt happens at that point, we will not properly detect the re-entrancy and clobber the original return context on the irq stack. This fixes it. The side effect is to prevent all nesting from softirq stack to irq stack even in the "safe" case but it's simpler that way and matches what x86_64 does. Reported-by: Cédric Le Goater <clg@fr.ibm.com> Tested-by: Cédric Le Goater <clg@fr.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/powerpc/kernel/irq.c5
1 files changed, 3 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 57d286a78f86..c7cb8c232d2f 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -495,14 +495,15 @@ void __do_irq(struct pt_regs *regs)
495void do_IRQ(struct pt_regs *regs) 495void do_IRQ(struct pt_regs *regs)
496{ 496{
497 struct pt_regs *old_regs = set_irq_regs(regs); 497 struct pt_regs *old_regs = set_irq_regs(regs);
498 struct thread_info *curtp, *irqtp; 498 struct thread_info *curtp, *irqtp, *sirqtp;
499 499
500 /* Switch to the irq stack to handle this */ 500 /* Switch to the irq stack to handle this */
501 curtp = current_thread_info(); 501 curtp = current_thread_info();
502 irqtp = hardirq_ctx[raw_smp_processor_id()]; 502 irqtp = hardirq_ctx[raw_smp_processor_id()];
503 sirqtp = softirq_ctx[raw_smp_processor_id()];
503 504
504 /* Already there ? */ 505 /* Already there ? */
505 if (unlikely(curtp == irqtp)) { 506 if (unlikely(curtp == irqtp || curtp == sirqtp)) {
506 __do_irq(regs); 507 __do_irq(regs);
507 set_irq_regs(old_regs); 508 set_irq_regs(old_regs);
508 return; 509 return;