ca8e08b18a161981821b5cb5d44ed5abd229162b
[linux-2.6-microblaze.git] / arch / powerpc / include / asm / interrupt.h
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 #ifndef _ASM_POWERPC_INTERRUPT_H
3 #define _ASM_POWERPC_INTERRUPT_H
4
5 #include <linux/context_tracking.h>
6 #include <linux/hardirq.h>
7 #include <asm/cputime.h>
8 #include <asm/ftrace.h>
9
10 struct interrupt_state {
11 #ifdef CONFIG_PPC_BOOK3E_64
12         enum ctx_state ctx_state;
13 #endif
14 };
15
16 static inline void interrupt_enter_prepare(struct pt_regs *regs, struct interrupt_state *state)
17 {
18         /*
19          * Book3E reconciles irq soft mask in asm
20          */
21 #ifdef CONFIG_PPC_BOOK3S_64
22         if (irq_soft_mask_set_return(IRQS_ALL_DISABLED) == IRQS_ENABLED)
23                 trace_hardirqs_off();
24         local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
25
26         if (user_mode(regs)) {
27                 CT_WARN_ON(ct_state() != CONTEXT_USER);
28                 user_exit_irqoff();
29
30                 account_cpu_user_entry();
31                 account_stolen_time();
32         } else {
33                 /*
34                  * CT_WARN_ON comes here via program_check_exception,
35                  * so avoid recursion.
36                  */
37                 if (TRAP(regs) != 0x700)
38                         CT_WARN_ON(ct_state() != CONTEXT_KERNEL);
39         }
40 #endif
41
42 #ifdef CONFIG_PPC_BOOK3E_64
43         state->ctx_state = exception_enter();
44         if (user_mode(regs))
45                 account_cpu_user_entry();
46 #endif
47 }
48
49 /*
50  * Care should be taken to note that interrupt_exit_prepare and
51  * interrupt_async_exit_prepare do not necessarily return immediately to
52  * regs context (e.g., if regs is usermode, we don't necessarily return to
53  * user mode). Other interrupts might be taken between here and return,
54  * context switch / preemption may occur in the exit path after this, or a
55  * signal may be delivered, etc.
56  *
57  * The real interrupt exit code is platform specific, e.g.,
58  * interrupt_exit_user_prepare / interrupt_exit_kernel_prepare for 64s.
59  *
60  * However interrupt_nmi_exit_prepare does return directly to regs, because
61  * NMIs do not do "exit work" or replay soft-masked interrupts.
62  */
63 static inline void interrupt_exit_prepare(struct pt_regs *regs, struct interrupt_state *state)
64 {
65 #ifdef CONFIG_PPC_BOOK3E_64
66         exception_exit(state->ctx_state);
67 #endif
68
69         /*
70          * Book3S exits to user via interrupt_exit_user_prepare(), which does
71          * context tracking, which is a cleaner way to handle PREEMPT=y
72          * and avoid context entry/exit in e.g., preempt_schedule_irq()),
73          * which is likely to be where the core code wants to end up.
74          *
75          * The above comment explains why we can't do the
76          *
77          *     if (user_mode(regs))
78          *         user_exit_irqoff();
79          *
80          * sequence here.
81          */
82 }
83
84 static inline void interrupt_async_enter_prepare(struct pt_regs *regs, struct interrupt_state *state)
85 {
86         interrupt_enter_prepare(regs, state);
87         irq_enter();
88 }
89
90 static inline void interrupt_async_exit_prepare(struct pt_regs *regs, struct interrupt_state *state)
91 {
92         irq_exit();
93         interrupt_exit_prepare(regs, state);
94 }
95
96 struct interrupt_nmi_state {
97 };
98
99 static inline void interrupt_nmi_enter_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state)
100 {
101 }
102
103 static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct interrupt_nmi_state *state)
104 {
105 }
106
107 /**
108  * DECLARE_INTERRUPT_HANDLER_RAW - Declare raw interrupt handler function
109  * @func:       Function name of the entry point
110  * @returns:    Returns a value back to asm caller
111  */
112 #define DECLARE_INTERRUPT_HANDLER_RAW(func)                             \
113         __visible long func(struct pt_regs *regs)
114
115 /**
116  * DEFINE_INTERRUPT_HANDLER_RAW - Define raw interrupt handler function
117  * @func:       Function name of the entry point
118  * @returns:    Returns a value back to asm caller
119  *
120  * @func is called from ASM entry code.
121  *
122  * This is a plain function which does no tracing, reconciling, etc.
123  * The macro is written so it acts as function definition. Append the
124  * body with a pair of curly brackets.
125  *
126  * raw interrupt handlers must not enable or disable interrupts, or
127  * schedule, tracing and instrumentation (ftrace, lockdep, etc) would
128  * not be advisable either, although may be possible in a pinch, the
129  * trace will look odd at least.
130  *
131  * A raw handler may call one of the other interrupt handler functions
132  * to be converted into that interrupt context without these restrictions.
133  *
134  * On PPC64, _RAW handlers may return with fast_interrupt_return.
135  *
136  * Specific handlers may have additional restrictions.
137  */
138 #define DEFINE_INTERRUPT_HANDLER_RAW(func)                              \
139 static __always_inline long ____##func(struct pt_regs *regs);           \
140                                                                         \
141 __visible noinstr long func(struct pt_regs *regs)                       \
142 {                                                                       \
143         long ret;                                                       \
144                                                                         \
145         ret = ____##func (regs);                                        \
146                                                                         \
147         return ret;                                                     \
148 }                                                                       \
149                                                                         \
150 static __always_inline long ____##func(struct pt_regs *regs)
151
152 /**
153  * DECLARE_INTERRUPT_HANDLER - Declare synchronous interrupt handler function
154  * @func:       Function name of the entry point
155  */
156 #define DECLARE_INTERRUPT_HANDLER(func)                                 \
157         __visible void func(struct pt_regs *regs)
158
159 /**
160  * DEFINE_INTERRUPT_HANDLER - Define synchronous interrupt handler function
161  * @func:       Function name of the entry point
162  *
163  * @func is called from ASM entry code.
164  *
165  * The macro is written so it acts as function definition. Append the
166  * body with a pair of curly brackets.
167  */
168 #define DEFINE_INTERRUPT_HANDLER(func)                                  \
169 static __always_inline void ____##func(struct pt_regs *regs);           \
170                                                                         \
171 __visible noinstr void func(struct pt_regs *regs)                       \
172 {                                                                       \
173         struct interrupt_state state;                                   \
174                                                                         \
175         interrupt_enter_prepare(regs, &state);                          \
176                                                                         \
177         ____##func (regs);                                              \
178                                                                         \
179         interrupt_exit_prepare(regs, &state);                           \
180 }                                                                       \
181                                                                         \
182 static __always_inline void ____##func(struct pt_regs *regs)
183
184 /**
185  * DECLARE_INTERRUPT_HANDLER_RET - Declare synchronous interrupt handler function
186  * @func:       Function name of the entry point
187  * @returns:    Returns a value back to asm caller
188  */
189 #define DECLARE_INTERRUPT_HANDLER_RET(func)                             \
190         __visible long func(struct pt_regs *regs)
191
192 /**
193  * DEFINE_INTERRUPT_HANDLER_RET - Define synchronous interrupt handler function
194  * @func:       Function name of the entry point
195  * @returns:    Returns a value back to asm caller
196  *
197  * @func is called from ASM entry code.
198  *
199  * The macro is written so it acts as function definition. Append the
200  * body with a pair of curly brackets.
201  */
202 #define DEFINE_INTERRUPT_HANDLER_RET(func)                              \
203 static __always_inline long ____##func(struct pt_regs *regs);           \
204                                                                         \
205 __visible noinstr long func(struct pt_regs *regs)                       \
206 {                                                                       \
207         struct interrupt_state state;                                   \
208         long ret;                                                       \
209                                                                         \
210         interrupt_enter_prepare(regs, &state);                          \
211                                                                         \
212         ret = ____##func (regs);                                        \
213                                                                         \
214         interrupt_exit_prepare(regs, &state);                           \
215                                                                         \
216         return ret;                                                     \
217 }                                                                       \
218                                                                         \
219 static __always_inline long ____##func(struct pt_regs *regs)
220
221 /**
222  * DECLARE_INTERRUPT_HANDLER_ASYNC - Declare asynchronous interrupt handler function
223  * @func:       Function name of the entry point
224  */
225 #define DECLARE_INTERRUPT_HANDLER_ASYNC(func)                           \
226         __visible void func(struct pt_regs *regs)
227
228 /**
229  * DEFINE_INTERRUPT_HANDLER_ASYNC - Define asynchronous interrupt handler function
230  * @func:       Function name of the entry point
231  *
232  * @func is called from ASM entry code.
233  *
234  * The macro is written so it acts as function definition. Append the
235  * body with a pair of curly brackets.
236  */
237 #define DEFINE_INTERRUPT_HANDLER_ASYNC(func)                            \
238 static __always_inline void ____##func(struct pt_regs *regs);           \
239                                                                         \
240 __visible noinstr void func(struct pt_regs *regs)                       \
241 {                                                                       \
242         struct interrupt_state state;                                   \
243                                                                         \
244         interrupt_async_enter_prepare(regs, &state);                    \
245                                                                         \
246         ____##func (regs);                                              \
247                                                                         \
248         interrupt_async_exit_prepare(regs, &state);                     \
249 }                                                                       \
250                                                                         \
251 static __always_inline void ____##func(struct pt_regs *regs)
252
253 /**
254  * DECLARE_INTERRUPT_HANDLER_NMI - Declare NMI interrupt handler function
255  * @func:       Function name of the entry point
256  * @returns:    Returns a value back to asm caller
257  */
258 #define DECLARE_INTERRUPT_HANDLER_NMI(func)                             \
259         __visible long func(struct pt_regs *regs)
260
261 /**
262  * DEFINE_INTERRUPT_HANDLER_NMI - Define NMI interrupt handler function
263  * @func:       Function name of the entry point
264  * @returns:    Returns a value back to asm caller
265  *
266  * @func is called from ASM entry code.
267  *
268  * The macro is written so it acts as function definition. Append the
269  * body with a pair of curly brackets.
270  */
271 #define DEFINE_INTERRUPT_HANDLER_NMI(func)                              \
272 static __always_inline long ____##func(struct pt_regs *regs);           \
273                                                                         \
274 __visible noinstr long func(struct pt_regs *regs)                       \
275 {                                                                       \
276         struct interrupt_nmi_state state;                               \
277         long ret;                                                       \
278                                                                         \
279         interrupt_nmi_enter_prepare(regs, &state);                      \
280                                                                         \
281         ret = ____##func (regs);                                        \
282                                                                         \
283         interrupt_nmi_exit_prepare(regs, &state);                       \
284                                                                         \
285         return ret;                                                     \
286 }                                                                       \
287                                                                         \
288 static __always_inline long ____##func(struct pt_regs *regs)
289
290
291 /* Interrupt handlers */
292 /* kernel/traps.c */
293 DECLARE_INTERRUPT_HANDLER_NMI(system_reset_exception);
294 #ifdef CONFIG_PPC_BOOK3S_64
295 DECLARE_INTERRUPT_HANDLER_ASYNC(machine_check_exception);
296 #else
297 DECLARE_INTERRUPT_HANDLER_NMI(machine_check_exception);
298 #endif
299 DECLARE_INTERRUPT_HANDLER(SMIException);
300 DECLARE_INTERRUPT_HANDLER(handle_hmi_exception);
301 DECLARE_INTERRUPT_HANDLER(unknown_exception);
302 DECLARE_INTERRUPT_HANDLER_ASYNC(unknown_async_exception);
303 DECLARE_INTERRUPT_HANDLER(instruction_breakpoint_exception);
304 DECLARE_INTERRUPT_HANDLER(RunModeException);
305 DECLARE_INTERRUPT_HANDLER(single_step_exception);
306 DECLARE_INTERRUPT_HANDLER(program_check_exception);
307 DECLARE_INTERRUPT_HANDLER(emulation_assist_interrupt);
308 DECLARE_INTERRUPT_HANDLER(alignment_exception);
309 DECLARE_INTERRUPT_HANDLER(StackOverflow);
310 DECLARE_INTERRUPT_HANDLER(stack_overflow_exception);
311 DECLARE_INTERRUPT_HANDLER(kernel_fp_unavailable_exception);
312 DECLARE_INTERRUPT_HANDLER(altivec_unavailable_exception);
313 DECLARE_INTERRUPT_HANDLER(vsx_unavailable_exception);
314 DECLARE_INTERRUPT_HANDLER(facility_unavailable_exception);
315 DECLARE_INTERRUPT_HANDLER(fp_unavailable_tm);
316 DECLARE_INTERRUPT_HANDLER(altivec_unavailable_tm);
317 DECLARE_INTERRUPT_HANDLER(vsx_unavailable_tm);
318 DECLARE_INTERRUPT_HANDLER_NMI(performance_monitor_exception_nmi);
319 DECLARE_INTERRUPT_HANDLER_ASYNC(performance_monitor_exception_async);
320 DECLARE_INTERRUPT_HANDLER_RAW(performance_monitor_exception);
321 DECLARE_INTERRUPT_HANDLER(DebugException);
322 DECLARE_INTERRUPT_HANDLER(altivec_assist_exception);
323 DECLARE_INTERRUPT_HANDLER(CacheLockingException);
324 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointException);
325 DECLARE_INTERRUPT_HANDLER(SPEFloatingPointRoundException);
326 DECLARE_INTERRUPT_HANDLER(unrecoverable_exception);
327 DECLARE_INTERRUPT_HANDLER(WatchdogException);
328 DECLARE_INTERRUPT_HANDLER(kernel_bad_stack);
329
330 /* slb.c */
331 DECLARE_INTERRUPT_HANDLER_RAW(do_slb_fault);
332 DECLARE_INTERRUPT_HANDLER(do_bad_slb_fault);
333
334 /* hash_utils.c */
335 DECLARE_INTERRUPT_HANDLER_RAW(do_hash_fault);
336
337 /* fault.c */
338 DECLARE_INTERRUPT_HANDLER_RET(do_page_fault);
339 DECLARE_INTERRUPT_HANDLER(do_bad_page_fault_segv);
340
341 /* process.c */
342 DECLARE_INTERRUPT_HANDLER(do_break);
343
344 /* time.c */
345 DECLARE_INTERRUPT_HANDLER_ASYNC(timer_interrupt);
346
347 /* mce.c */
348 DECLARE_INTERRUPT_HANDLER_NMI(machine_check_early);
349 DECLARE_INTERRUPT_HANDLER_NMI(hmi_exception_realmode);
350
351 DECLARE_INTERRUPT_HANDLER_ASYNC(TAUException);
352
353 void replay_system_reset(void);
354 void replay_soft_interrupts(void);
355
356 static inline void interrupt_cond_local_irq_enable(struct pt_regs *regs)
357 {
358         if (!arch_irq_disabled_regs(regs))
359                 local_irq_enable();
360 }
361
362 #endif /* _ASM_POWERPC_INTERRUPT_H */