diff options
| -rw-r--r-- | arch/powerpc/include/asm/entry-common.h | 15 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/interrupt.h | 1 |
2 files changed, 8 insertions, 8 deletions
diff --git a/arch/powerpc/include/asm/entry-common.h b/arch/powerpc/include/asm/entry-common.h index fc636c42e89a..c5adb5006361 100644 --- a/arch/powerpc/include/asm/entry-common.h +++ b/arch/powerpc/include/asm/entry-common.h @@ -66,6 +66,13 @@ static inline void srr_regs_clobbered(void) static inline void nap_adjust_return(struct pt_regs *regs) { #ifdef CONFIG_PPC_970_NAP + /* + * Adjust the nap return address before irq_exit_rcu(). irq_exit_rcu() + * may invoke softirqs with interrupts re-enabled, allowing a nested + * async interrupt to arrive. If _TLF_NAPPING is still set at that + * point, the nested interrupt would erroneously redirect its own + * return address to power4_idle_nap_return, corrupting the stack. + */ if (unlikely(test_thread_local_flags(_TLF_NAPPING))) { /* Can avoid a test-and-clear because NMIs do not call this */ clear_thread_local_flags(_TLF_NAPPING); @@ -286,14 +293,6 @@ static inline void arch_interrupt_async_enter_prepare(struct pt_regs *regs) static inline void arch_interrupt_async_exit_prepare(struct pt_regs *regs) { - /* - * Adjust at exit so the main handler sees the true NIA. This must - * come before irq_exit() because irq_exit can enable interrupts, and - * if another interrupt is taken before nap_adjust_return has run - * here, then that interrupt would return directly to idle nap return. - */ - nap_adjust_return(regs); - arch_interrupt_exit_prepare(regs); } diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h index fb42a664ae54..1b45a49e9bed 100644 --- a/arch/powerpc/include/asm/interrupt.h +++ b/arch/powerpc/include/asm/interrupt.h @@ -246,6 +246,7 @@ interrupt_handler void func(struct pt_regs *regs) \ instrumentation_begin(); \ irq_enter_rcu(); \ ____##func (regs); \ + nap_adjust_return(regs); \ irq_exit_rcu(); \ instrumentation_end(); \ arch_interrupt_async_exit_prepare(regs); \ |
