diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2021-04-06 12:55:08 +1000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2021-04-08 21:17:45 +1000 |
commit | 98db179a78dd8379e9d2cbfc3f00224168a9344c (patch) | |
tree | ed500c2bbf9cac178df23f6d758371a89f8a134f /arch/powerpc/include/asm/interrupt.h | |
parent | 10f8f96179ecc7f69c927f6d231f6d02736cea83 (diff) | |
download | linux-98db179a78dd8379e9d2cbfc3f00224168a9344c.tar.gz linux-98db179a78dd8379e9d2cbfc3f00224168a9344c.tar.bz2 linux-98db179a78dd8379e9d2cbfc3f00224168a9344c.zip |
powerpc/64s: power4 nap fixup in C
There is no need for this to be in asm, use the new intrrupt entry wrapper.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Tested-by: Andreas Schwab <schwab@linux-m68k.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210406025508.821718-1-npiggin@gmail.com
Diffstat (limited to 'arch/powerpc/include/asm/interrupt.h')
-rw-r--r-- | arch/powerpc/include/asm/interrupt.h | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h index 7c633896d758..05e7fc4ffb50 100644 --- a/arch/powerpc/include/asm/interrupt.h +++ b/arch/powerpc/include/asm/interrupt.h @@ -9,6 +9,17 @@ #include <asm/kprobes.h> #include <asm/runlatch.h> +static inline void nap_adjust_return(struct pt_regs *regs) +{ +#ifdef CONFIG_PPC_970_NAP + 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); + regs->nip = (unsigned long)power4_idle_nap_return; + } +#endif +} + struct interrupt_state { #ifdef CONFIG_PPC_BOOK3E_64 enum ctx_state ctx_state; @@ -124,6 +135,14 @@ static inline void interrupt_async_enter_prepare(struct pt_regs *regs, struct in static inline void interrupt_async_exit_prepare(struct pt_regs *regs, struct interrupt_state *state) { + /* + * 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); + irq_exit(); interrupt_exit_prepare(regs, state); } @@ -179,6 +198,11 @@ static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct inter radix_enabled() || (mfmsr() & MSR_DR)) nmi_exit(); + /* + * nmi does not call nap_adjust_return because nmi should not create + * new work to do (must use irq_work for that). + */ + #ifdef CONFIG_PPC64 if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260) this_cpu_set_ftrace_enabled(state->ftrace_enabled); |