xref: /linux/arch/powerpc/include/asm/interrupt.h (revision 86dbb39416493add2bdf5b7ad39a1276f2107b83)
18d41fc61SNicholas Piggin /* SPDX-License-Identifier: GPL-2.0-or-later */
28d41fc61SNicholas Piggin #ifndef _ASM_POWERPC_INTERRUPT_H
38d41fc61SNicholas Piggin #define _ASM_POWERPC_INTERRUPT_H
48d41fc61SNicholas Piggin 
58d41fc61SNicholas Piggin #include <linux/context_tracking.h>
6e6f8a6c8SNicholas Piggin #include <linux/hardirq.h>
756acfdd8SNicholas Piggin #include <asm/cputime.h>
88d41fc61SNicholas Piggin #include <asm/ftrace.h>
9*86dbb394SNicholas Piggin #include <asm/runlatch.h>
108d41fc61SNicholas Piggin 
1125b7e6bbSNicholas Piggin struct interrupt_state {
12f821bc97SNicholas Piggin #ifdef CONFIG_PPC_BOOK3E_64
13540d4d34SNicholas Piggin 	enum ctx_state ctx_state;
14540d4d34SNicholas Piggin #endif
1525b7e6bbSNicholas Piggin };
1625b7e6bbSNicholas Piggin 
1725b7e6bbSNicholas Piggin static inline void interrupt_enter_prepare(struct pt_regs *regs, struct interrupt_state *state)
1825b7e6bbSNicholas Piggin {
1975b96950SNicholas Piggin 	/*
2075b96950SNicholas Piggin 	 * Book3E reconciles irq soft mask in asm
2175b96950SNicholas Piggin 	 */
22f821bc97SNicholas Piggin #ifdef CONFIG_PPC_BOOK3S_64
2375b96950SNicholas Piggin 	if (irq_soft_mask_set_return(IRQS_ALL_DISABLED) == IRQS_ENABLED)
2475b96950SNicholas Piggin 		trace_hardirqs_off();
2575b96950SNicholas Piggin 	local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
2675b96950SNicholas Piggin 
27f821bc97SNicholas Piggin 	if (user_mode(regs)) {
28f821bc97SNicholas Piggin 		CT_WARN_ON(ct_state() != CONTEXT_USER);
29f821bc97SNicholas Piggin 		user_exit_irqoff();
3056acfdd8SNicholas Piggin 
3156acfdd8SNicholas Piggin 		account_cpu_user_entry();
3256acfdd8SNicholas Piggin 		account_stolen_time();
33f821bc97SNicholas Piggin 	} else {
34f821bc97SNicholas Piggin 		/*
35f821bc97SNicholas Piggin 		 * CT_WARN_ON comes here via program_check_exception,
36f821bc97SNicholas Piggin 		 * so avoid recursion.
37f821bc97SNicholas Piggin 		 */
38f821bc97SNicholas Piggin 		if (TRAP(regs) != 0x700)
39f821bc97SNicholas Piggin 			CT_WARN_ON(ct_state() != CONTEXT_KERNEL);
40f821bc97SNicholas Piggin 	}
41f821bc97SNicholas Piggin #endif
4275b96950SNicholas Piggin 
4375b96950SNicholas Piggin #ifdef CONFIG_PPC_BOOK3E_64
4475b96950SNicholas Piggin 	state->ctx_state = exception_enter();
4556acfdd8SNicholas Piggin 	if (user_mode(regs))
4656acfdd8SNicholas Piggin 		account_cpu_user_entry();
4775b96950SNicholas Piggin #endif
4825b7e6bbSNicholas Piggin }
4925b7e6bbSNicholas Piggin 
5025b7e6bbSNicholas Piggin /*
5125b7e6bbSNicholas Piggin  * Care should be taken to note that interrupt_exit_prepare and
5225b7e6bbSNicholas Piggin  * interrupt_async_exit_prepare do not necessarily return immediately to
5325b7e6bbSNicholas Piggin  * regs context (e.g., if regs is usermode, we don't necessarily return to
5425b7e6bbSNicholas Piggin  * user mode). Other interrupts might be taken between here and return,
5525b7e6bbSNicholas Piggin  * context switch / preemption may occur in the exit path after this, or a
5625b7e6bbSNicholas Piggin  * signal may be delivered, etc.
5725b7e6bbSNicholas Piggin  *
5825b7e6bbSNicholas Piggin  * The real interrupt exit code is platform specific, e.g.,
5925b7e6bbSNicholas Piggin  * interrupt_exit_user_prepare / interrupt_exit_kernel_prepare for 64s.
6025b7e6bbSNicholas Piggin  *
6125b7e6bbSNicholas Piggin  * However interrupt_nmi_exit_prepare does return directly to regs, because
6225b7e6bbSNicholas Piggin  * NMIs do not do "exit work" or replay soft-masked interrupts.
6325b7e6bbSNicholas Piggin  */
6425b7e6bbSNicholas Piggin static inline void interrupt_exit_prepare(struct pt_regs *regs, struct interrupt_state *state)
6525b7e6bbSNicholas Piggin {
66f821bc97SNicholas Piggin #ifdef CONFIG_PPC_BOOK3E_64
67540d4d34SNicholas Piggin 	exception_exit(state->ctx_state);
68540d4d34SNicholas Piggin #endif
69f821bc97SNicholas Piggin 
70f821bc97SNicholas Piggin 	/*
71f821bc97SNicholas Piggin 	 * Book3S exits to user via interrupt_exit_user_prepare(), which does
72f821bc97SNicholas Piggin 	 * context tracking, which is a cleaner way to handle PREEMPT=y
73f821bc97SNicholas Piggin 	 * and avoid context entry/exit in e.g., preempt_schedule_irq()),
74f821bc97SNicholas Piggin 	 * which is likely to be where the core code wants to end up.
75f821bc97SNicholas Piggin 	 *
76f821bc97SNicholas Piggin 	 * The above comment explains why we can't do the
77f821bc97SNicholas Piggin 	 *
78f821bc97SNicholas Piggin 	 *     if (user_mode(regs))
79f821bc97SNicholas Piggin 	 *         user_exit_irqoff();
80f821bc97SNicholas Piggin 	 *
81f821bc97SNicholas Piggin 	 * sequence here.
82f821bc97SNicholas Piggin 	 */
8325b7e6bbSNicholas Piggin }
8425b7e6bbSNicholas Piggin 
8525b7e6bbSNicholas Piggin static inline void interrupt_async_enter_prepare(struct pt_regs *regs, struct interrupt_state *state)
8625b7e6bbSNicholas Piggin {
87*86dbb394SNicholas Piggin #ifdef CONFIG_PPC_BOOK3S_64
88*86dbb394SNicholas Piggin 	if (cpu_has_feature(CPU_FTR_CTRL) &&
89*86dbb394SNicholas Piggin 	    !test_thread_local_flags(_TLF_RUNLATCH))
90*86dbb394SNicholas Piggin 		__ppc64_runlatch_on();
91*86dbb394SNicholas Piggin #endif
92*86dbb394SNicholas Piggin 
936fdb0f41SNicholas Piggin 	interrupt_enter_prepare(regs, state);
941b1b6a6fSNicholas Piggin 	irq_enter();
9525b7e6bbSNicholas Piggin }
9625b7e6bbSNicholas Piggin 
9725b7e6bbSNicholas Piggin static inline void interrupt_async_exit_prepare(struct pt_regs *regs, struct interrupt_state *state)
9825b7e6bbSNicholas Piggin {
991b1b6a6fSNicholas Piggin 	irq_exit();
1006fdb0f41SNicholas Piggin 	interrupt_exit_prepare(regs, state);
10125b7e6bbSNicholas Piggin }
10225b7e6bbSNicholas Piggin 
10325b7e6bbSNicholas Piggin struct interrupt_nmi_state {
104118178e6SNicholas Piggin #ifdef CONFIG_PPC64
1056ecbb582SNicholas Piggin #ifdef CONFIG_PPC_BOOK3S_64
1066ecbb582SNicholas Piggin 	u8 irq_soft_mask;
1076ecbb582SNicholas Piggin 	u8 irq_happened;
1086ecbb582SNicholas Piggin #endif
109118178e6SNicholas Piggin 	u8 ftrace_enabled;
110118178e6SNicholas Piggin #endif
11125b7e6bbSNicholas Piggin };
11225b7e6bbSNicholas Piggin 
11325b7e6bbSNicholas Piggin static inline void interrupt_nmi_enter_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state)
11425b7e6bbSNicholas Piggin {
115118178e6SNicholas Piggin #ifdef CONFIG_PPC64
1166ecbb582SNicholas Piggin #ifdef CONFIG_PPC_BOOK3S_64
1176ecbb582SNicholas Piggin 	state->irq_soft_mask = local_paca->irq_soft_mask;
1186ecbb582SNicholas Piggin 	state->irq_happened = local_paca->irq_happened;
1196ecbb582SNicholas Piggin 
1206ecbb582SNicholas Piggin 	/*
1216ecbb582SNicholas Piggin 	 * Set IRQS_ALL_DISABLED unconditionally so irqs_disabled() does
1226ecbb582SNicholas Piggin 	 * the right thing, and set IRQ_HARD_DIS. We do not want to reconcile
1236ecbb582SNicholas Piggin 	 * because that goes through irq tracing which we don't want in NMI.
1246ecbb582SNicholas Piggin 	 */
1256ecbb582SNicholas Piggin 	local_paca->irq_soft_mask = IRQS_ALL_DISABLED;
1266ecbb582SNicholas Piggin 	local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
1276ecbb582SNicholas Piggin 
1286ecbb582SNicholas Piggin 	/* Don't do any per-CPU operations until interrupt state is fixed */
1296ecbb582SNicholas Piggin #endif
130118178e6SNicholas Piggin 	/* Allow DEC and PMI to be traced when they are soft-NMI */
131118178e6SNicholas Piggin 	if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260) {
132118178e6SNicholas Piggin 		state->ftrace_enabled = this_cpu_get_ftrace_enabled();
133118178e6SNicholas Piggin 		this_cpu_set_ftrace_enabled(0);
134118178e6SNicholas Piggin 	}
135118178e6SNicholas Piggin #endif
136118178e6SNicholas Piggin 
137118178e6SNicholas Piggin 	/*
138118178e6SNicholas Piggin 	 * Do not use nmi_enter() for pseries hash guest taking a real-mode
139118178e6SNicholas Piggin 	 * NMI because not everything it touches is within the RMA limit.
140118178e6SNicholas Piggin 	 */
141118178e6SNicholas Piggin 	if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) ||
142118178e6SNicholas Piggin 			!firmware_has_feature(FW_FEATURE_LPAR) ||
143118178e6SNicholas Piggin 			radix_enabled() || (mfmsr() & MSR_DR))
144118178e6SNicholas Piggin 		nmi_enter();
14525b7e6bbSNicholas Piggin }
14625b7e6bbSNicholas Piggin 
14725b7e6bbSNicholas Piggin static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state)
14825b7e6bbSNicholas Piggin {
149118178e6SNicholas Piggin 	if (!IS_ENABLED(CONFIG_PPC_BOOK3S_64) ||
150118178e6SNicholas Piggin 			!firmware_has_feature(FW_FEATURE_LPAR) ||
151118178e6SNicholas Piggin 			radix_enabled() || (mfmsr() & MSR_DR))
152118178e6SNicholas Piggin 		nmi_exit();
153118178e6SNicholas Piggin 
154118178e6SNicholas Piggin #ifdef CONFIG_PPC64
155118178e6SNicholas Piggin 	if (TRAP(regs) != 0x900 && TRAP(regs) != 0xf00 && TRAP(regs) != 0x260)
156118178e6SNicholas Piggin 		this_cpu_set_ftrace_enabled(state->ftrace_enabled);
1576ecbb582SNicholas Piggin 
1586ecbb582SNicholas Piggin #ifdef CONFIG_PPC_BOOK3S_64
1596ecbb582SNicholas Piggin 	/* Check we didn't change the pending interrupt mask. */
1606ecbb582SNicholas Piggin 	WARN_ON_ONCE((state->irq_happened | PACA_IRQ_HARD_DIS) != local_paca->irq_happened);
1616ecbb582SNicholas Piggin 	local_paca->irq_happened = state->irq_happened;
1626ecbb582SNicholas Piggin 	local_paca->irq_soft_mask = state->irq_soft_mask;
1636ecbb582SNicholas Piggin #endif
164118178e6SNicholas Piggin #endif
16525b7e6bbSNicholas Piggin }
16625b7e6bbSNicholas Piggin 
1678d41fc61SNicholas Piggin /**
1688d41fc61SNicholas Piggin  * DECLARE_INTERRUPT_HANDLER_RAW - Declare raw interrupt handler function
1698d41fc61SNicholas Piggin  * @func:	Function name of the entry point
1708d41fc61SNicholas Piggin  * @returns:	Returns a value back to asm caller
1718d41fc61SNicholas Piggin  */
1728d41fc61SNicholas Piggin #define DECLARE_INTERRUPT_HANDLER_RAW(func)				\
1738d41fc61SNicholas Piggin 	__visible long func(struct pt_regs *regs)
1748d41fc61SNicholas Piggin 
1758d41fc61SNicholas Piggin /**
1768d41fc61SNicholas Piggin  * DEFINE_INTERRUPT_HANDLER_RAW - Define raw interrupt handler function
1778d41fc61SNicholas Piggin  * @func:	Function name of the entry point
1788d41fc61SNicholas Piggin  * @returns:	Returns a value back to asm caller
1798d41fc61SNicholas Piggin  *
1808d41fc61SNicholas Piggin  * @func is called from ASM entry code.
1818d41fc61SNicholas Piggin  *
1828d41fc61SNicholas Piggin  * This is a plain function which does no tracing, reconciling, etc.
1838d41fc61SNicholas Piggin  * The macro is written so it acts as function definition. Append the
1848d41fc61SNicholas Piggin  * body with a pair of curly brackets.
1858d41fc61SNicholas Piggin  *
1868d41fc61SNicholas Piggin  * raw interrupt handlers must not enable or disable interrupts, or
1878d41fc61SNicholas Piggin  * schedule, tracing and instrumentation (ftrace, lockdep, etc) would
1888d41fc61SNicholas Piggin  * not be advisable either, although may be possible in a pinch, the
1898d41fc61SNicholas Piggin  * trace will look odd at least.
1908d41fc61SNicholas Piggin  *
1918d41fc61SNicholas Piggin  * A raw handler may call one of the other interrupt handler functions
1928d41fc61SNicholas Piggin  * to be converted into that interrupt context without these restrictions.
1938d41fc61SNicholas Piggin  *
1948d41fc61SNicholas Piggin  * On PPC64, _RAW handlers may return with fast_interrupt_return.
1958d41fc61SNicholas Piggin  *
1968d41fc61SNicholas Piggin  * Specific handlers may have additional restrictions.
1978d41fc61SNicholas Piggin  */
1988d41fc61SNicholas Piggin #define DEFINE_INTERRUPT_HANDLER_RAW(func)				\
1998d41fc61SNicholas Piggin static __always_inline long ____##func(struct pt_regs *regs);		\
2008d41fc61SNicholas Piggin 									\
2018d41fc61SNicholas Piggin __visible noinstr long func(struct pt_regs *regs)			\
2028d41fc61SNicholas Piggin {									\
2038d41fc61SNicholas Piggin 	long ret;							\
2048d41fc61SNicholas Piggin 									\
2058d41fc61SNicholas Piggin 	ret = ____##func (regs);					\
2068d41fc61SNicholas Piggin 									\
2078d41fc61SNicholas Piggin 	return ret;							\
2088d41fc61SNicholas Piggin }									\
2098d41fc61SNicholas Piggin 									\
2108d41fc61SNicholas Piggin static __always_inline long ____##func(struct pt_regs *regs)
2118d41fc61SNicholas Piggin 
2128d41fc61SNicholas Piggin /**
2138d41fc61SNicholas Piggin  * DECLARE_INTERRUPT_HANDLER - Declare synchronous interrupt handler function
2148d41fc61SNicholas Piggin  * @func:	Function name of the entry point
2158d41fc61SNicholas Piggin  */
2168d41fc61SNicholas Piggin #define DECLARE_INTERRUPT_HANDLER(func)					\
2178d41fc61SNicholas Piggin 	__visible void func(struct pt_regs *regs)
2188d41fc61SNicholas Piggin 
2198d41fc61SNicholas Piggin /**
2208d41fc61SNicholas Piggin  * DEFINE_INTERRUPT_HANDLER - Define synchronous interrupt handler function
2218d41fc61SNicholas Piggin  * @func:	Function name of the entry point
2228d41fc61SNicholas Piggin  *
2238d41fc61SNicholas Piggin  * @func is called from ASM entry code.
2248d41fc61SNicholas Piggin  *
2258d41fc61SNicholas Piggin  * The macro is written so it acts as function definition. Append the
2268d41fc61SNicholas Piggin  * body with a pair of curly brackets.
2278d41fc61SNicholas Piggin  */
2288d41fc61SNicholas Piggin #define DEFINE_INTERRUPT_HANDLER(func)					\
2298d41fc61SNicholas Piggin static __always_inline void ____##func(struct pt_regs *regs);		\
2308d41fc61SNicholas Piggin 									\
2318d41fc61SNicholas Piggin __visible noinstr void func(struct pt_regs *regs)			\
2328d41fc61SNicholas Piggin {									\
23325b7e6bbSNicholas Piggin 	struct interrupt_state state;					\
23425b7e6bbSNicholas Piggin 									\
23525b7e6bbSNicholas Piggin 	interrupt_enter_prepare(regs, &state);				\
23625b7e6bbSNicholas Piggin 									\
2378d41fc61SNicholas Piggin 	____##func (regs);						\
23825b7e6bbSNicholas Piggin 									\
23925b7e6bbSNicholas Piggin 	interrupt_exit_prepare(regs, &state);				\
2408d41fc61SNicholas Piggin }									\
2418d41fc61SNicholas Piggin 									\
2428d41fc61SNicholas Piggin static __always_inline void ____##func(struct pt_regs *regs)
2438d41fc61SNicholas Piggin 
2448d41fc61SNicholas Piggin /**
2458d41fc61SNicholas Piggin  * DECLARE_INTERRUPT_HANDLER_RET - Declare synchronous interrupt handler function
2468d41fc61SNicholas Piggin  * @func:	Function name of the entry point
2478d41fc61SNicholas Piggin  * @returns:	Returns a value back to asm caller
2488d41fc61SNicholas Piggin  */
2498d41fc61SNicholas Piggin #define DECLARE_INTERRUPT_HANDLER_RET(func)				\
2508d41fc61SNicholas Piggin 	__visible long func(struct pt_regs *regs)
2518d41fc61SNicholas Piggin 
2528d41fc61SNicholas Piggin /**
2538d41fc61SNicholas Piggin  * DEFINE_INTERRUPT_HANDLER_RET - Define synchronous interrupt handler function
2548d41fc61SNicholas Piggin  * @func:	Function name of the entry point
2558d41fc61SNicholas Piggin  * @returns:	Returns a value back to asm caller
2568d41fc61SNicholas Piggin  *
2578d41fc61SNicholas Piggin  * @func is called from ASM entry code.
2588d41fc61SNicholas Piggin  *
2598d41fc61SNicholas Piggin  * The macro is written so it acts as function definition. Append the
2608d41fc61SNicholas Piggin  * body with a pair of curly brackets.
2618d41fc61SNicholas Piggin  */
2628d41fc61SNicholas Piggin #define DEFINE_INTERRUPT_HANDLER_RET(func)				\
2638d41fc61SNicholas Piggin static __always_inline long ____##func(struct pt_regs *regs);		\
2648d41fc61SNicholas Piggin 									\
2658d41fc61SNicholas Piggin __visible noinstr long func(struct pt_regs *regs)			\
2668d41fc61SNicholas Piggin {									\
26725b7e6bbSNicholas Piggin 	struct interrupt_state state;					\
2688d41fc61SNicholas Piggin 	long ret;							\
2698d41fc61SNicholas Piggin 									\
27025b7e6bbSNicholas Piggin 	interrupt_enter_prepare(regs, &state);				\
27125b7e6bbSNicholas Piggin 									\
2728d41fc61SNicholas Piggin 	ret = ____##func (regs);					\
2738d41fc61SNicholas Piggin 									\
27425b7e6bbSNicholas Piggin 	interrupt_exit_prepare(regs, &state);				\
27525b7e6bbSNicholas Piggin 									\
2768d41fc61SNicholas Piggin 	return ret;							\
2778d41fc61SNicholas Piggin }									\
2788d41fc61SNicholas Piggin 									\
2798d41fc61SNicholas Piggin static __always_inline long ____##func(struct pt_regs *regs)
2808d41fc61SNicholas Piggin 
2818d41fc61SNicholas Piggin /**
2828d41fc61SNicholas Piggin  * DECLARE_INTERRUPT_HANDLER_ASYNC - Declare asynchronous interrupt handler function
2838d41fc61SNicholas Piggin  * @func:	Function name of the entry point
2848d41fc61SNicholas Piggin  */
2858d41fc61SNicholas Piggin #define DECLARE_INTERRUPT_HANDLER_ASYNC(func)				\
2868d41fc61SNicholas Piggin 	__visible void func(struct pt_regs *regs)
2878d41fc61SNicholas Piggin 
2888d41fc61SNicholas Piggin /**
2898d41fc61SNicholas Piggin  * DEFINE_INTERRUPT_HANDLER_ASYNC - Define asynchronous interrupt handler function
2908d41fc61SNicholas Piggin  * @func:	Function name of the entry point
2918d41fc61SNicholas Piggin  *
2928d41fc61SNicholas Piggin  * @func is called from ASM entry code.
2938d41fc61SNicholas Piggin  *
2948d41fc61SNicholas Piggin  * The macro is written so it acts as function definition. Append the
2958d41fc61SNicholas Piggin  * body with a pair of curly brackets.
2968d41fc61SNicholas Piggin  */
2978d41fc61SNicholas Piggin #define DEFINE_INTERRUPT_HANDLER_ASYNC(func)				\
2988d41fc61SNicholas Piggin static __always_inline void ____##func(struct pt_regs *regs);		\
2998d41fc61SNicholas Piggin 									\
3008d41fc61SNicholas Piggin __visible noinstr void func(struct pt_regs *regs)			\
3018d41fc61SNicholas Piggin {									\
30225b7e6bbSNicholas Piggin 	struct interrupt_state state;					\
30325b7e6bbSNicholas Piggin 									\
30425b7e6bbSNicholas Piggin 	interrupt_async_enter_prepare(regs, &state);			\
30525b7e6bbSNicholas Piggin 									\
3068d41fc61SNicholas Piggin 	____##func (regs);						\
30725b7e6bbSNicholas Piggin 									\
30825b7e6bbSNicholas Piggin 	interrupt_async_exit_prepare(regs, &state);			\
3098d41fc61SNicholas Piggin }									\
3108d41fc61SNicholas Piggin 									\
3118d41fc61SNicholas Piggin static __always_inline void ____##func(struct pt_regs *regs)
3128d41fc61SNicholas Piggin 
3138d41fc61SNicholas Piggin /**
3148d41fc61SNicholas Piggin  * DECLARE_INTERRUPT_HANDLER_NMI - Declare NMI interrupt handler function
3158d41fc61SNicholas Piggin  * @func:	Function name of the entry point
3168d41fc61SNicholas Piggin  * @returns:	Returns a value back to asm caller
3178d41fc61SNicholas Piggin  */
3188d41fc61SNicholas Piggin #define DECLARE_INTERRUPT_HANDLER_NMI(func)				\
3198d41fc61SNicholas Piggin 	__visible long func(struct pt_regs *regs)
3208d41fc61SNicholas Piggin 
3218d41fc61SNicholas Piggin /**
3228d41fc61SNicholas Piggin  * DEFINE_INTERRUPT_HANDLER_NMI - Define NMI interrupt handler function
3238d41fc61SNicholas Piggin  * @func:	Function name of the entry point
3248d41fc61SNicholas Piggin  * @returns:	Returns a value back to asm caller
3258d41fc61SNicholas Piggin  *
3268d41fc61SNicholas Piggin  * @func is called from ASM entry code.
3278d41fc61SNicholas Piggin  *
3288d41fc61SNicholas Piggin  * The macro is written so it acts as function definition. Append the
3298d41fc61SNicholas Piggin  * body with a pair of curly brackets.
3308d41fc61SNicholas Piggin  */
3318d41fc61SNicholas Piggin #define DEFINE_INTERRUPT_HANDLER_NMI(func)				\
3328d41fc61SNicholas Piggin static __always_inline long ____##func(struct pt_regs *regs);		\
3338d41fc61SNicholas Piggin 									\
3348d41fc61SNicholas Piggin __visible noinstr long func(struct pt_regs *regs)			\
3358d41fc61SNicholas Piggin {									\
33625b7e6bbSNicholas Piggin 	struct interrupt_nmi_state state;				\
3378d41fc61SNicholas Piggin 	long ret;							\
3388d41fc61SNicholas Piggin 									\
33925b7e6bbSNicholas Piggin 	interrupt_nmi_enter_prepare(regs, &state);			\
34025b7e6bbSNicholas Piggin 									\
3418d41fc61SNicholas Piggin 	ret = ____##func (regs);					\
3428d41fc61SNicholas Piggin 									\
34325b7e6bbSNicholas Piggin 	interrupt_nmi_exit_prepare(regs, &state);			\
34425b7e6bbSNicholas Piggin 									\
3458d41fc61SNicholas Piggin 	return ret;							\
3468d41fc61SNicholas Piggin }									\
3478d41fc61SNicholas Piggin 									\
3488d41fc61SNicholas Piggin static __always_inline long ____##func(struct pt_regs *regs)
3498d41fc61SNicholas Piggin 
3503a96570fSNicholas Piggin 
3513a96570fSNicholas Piggin /* Interrupt handlers */
3523a96570fSNicholas Piggin /* kernel/traps.c */
3533a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_NMI(system_reset_exception);
3543a96570fSNicholas Piggin #ifdef CONFIG_PPC_BOOK3S_64
3553a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_ASYNC(machine_check_exception);
3563a96570fSNicholas Piggin #else
3573a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_NMI(machine_check_exception);
3583a96570fSNicholas Piggin #endif
3593a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(SMIException);
3603a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(handle_hmi_exception);
3613a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(unknown_exception);
3623a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_ASYNC(unknown_async_exception);
3633a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(instruction_breakpoint_exception);
3643a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(RunModeException);
3653a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(single_step_exception);
3663a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(program_check_exception);
3673a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(emulation_assist_interrupt);
3683a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(alignment_exception);
3693a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(StackOverflow);
3703a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(stack_overflow_exception);
3713a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(kernel_fp_unavailable_exception);
3723a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(altivec_unavailable_exception);
3733a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(vsx_unavailable_exception);
3743a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(facility_unavailable_exception);
3753a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(fp_unavailable_tm);
3763a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(altivec_unavailable_tm);
3773a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(vsx_unavailable_tm);
3783a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi);
3793a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_ASYNC(performance_monitor_exception_async);
3803a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_RAW(performance_monitor_exception);
3813a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(DebugException);
3823a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(altivec_assist_exception);
3833a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(CacheLockingException);
3843a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(SPEFloatingPointException);
3853a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(SPEFloatingPointRoundException);
3863a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(unrecoverable_exception);
3873a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(WatchdogException);
3883a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(kernel_bad_stack);
3893a96570fSNicholas Piggin 
3903a96570fSNicholas Piggin /* slb.c */
3913a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_RAW(do_slb_fault);
3923a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(do_bad_slb_fault);
3933a96570fSNicholas Piggin 
3943a96570fSNicholas Piggin /* hash_utils.c */
3953a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_RAW(do_hash_fault);
3963a96570fSNicholas Piggin 
3973a96570fSNicholas Piggin /* fault.c */
3983a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_RET(do_page_fault);
3993a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(do_bad_page_fault_segv);
4003a96570fSNicholas Piggin 
4013a96570fSNicholas Piggin /* process.c */
4023a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER(do_break);
4033a96570fSNicholas Piggin 
4043a96570fSNicholas Piggin /* time.c */
4053a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_ASYNC(timer_interrupt);
4063a96570fSNicholas Piggin 
4073a96570fSNicholas Piggin /* mce.c */
4083a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_NMI(machine_check_early);
4093a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode);
4103a96570fSNicholas Piggin 
4113a96570fSNicholas Piggin DECLARE_INTERRUPT_HANDLER_ASYNC(TAUException);
4123a96570fSNicholas Piggin 
4133a96570fSNicholas Piggin void replay_system_reset(void);
4143a96570fSNicholas Piggin void replay_soft_interrupts(void);
4153a96570fSNicholas Piggin 
416e6f8a6c8SNicholas Piggin static inline void interrupt_cond_local_irq_enable(struct pt_regs *regs)
417e6f8a6c8SNicholas Piggin {
418e6f8a6c8SNicholas Piggin 	if (!arch_irq_disabled_regs(regs))
419e6f8a6c8SNicholas Piggin 		local_irq_enable();
420e6f8a6c8SNicholas Piggin }
421e6f8a6c8SNicholas Piggin 
4228d41fc61SNicholas Piggin #endif /* _ASM_POWERPC_INTERRUPT_H */
423