1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/percpu.h>
3 #include <linux/jump_label.h>
4 #include <asm/trace.h>
5 
6 #ifdef CONFIG_JUMP_LABEL
7 struct static_key opal_tracepoint_key = STATIC_KEY_INIT;
8 
9 int opal_tracepoint_regfunc(void)
10 {
11 	static_key_slow_inc(&opal_tracepoint_key);
12 	return 0;
13 }
14 
15 void opal_tracepoint_unregfunc(void)
16 {
17 	static_key_slow_dec(&opal_tracepoint_key);
18 }
19 #else
20 /*
21  * We optimise OPAL calls by placing opal_tracepoint_refcount
22  * directly in the TOC so we can check if the opal tracepoints are
23  * enabled via a single load.
24  */
25 
26 /* NB: reg/unreg are called while guarded with the tracepoints_mutex */
27 extern long opal_tracepoint_refcount;
28 
29 int opal_tracepoint_regfunc(void)
30 {
31 	opal_tracepoint_refcount++;
32 	return 0;
33 }
34 
35 void opal_tracepoint_unregfunc(void)
36 {
37 	opal_tracepoint_refcount--;
38 }
39 #endif
40 
41 /*
42  * Since the tracing code might execute OPAL calls we need to guard against
43  * recursion.
44  */
45 static DEFINE_PER_CPU(unsigned int, opal_trace_depth);
46 
47 void __trace_opal_entry(unsigned long opcode, unsigned long *args)
48 {
49 	unsigned long flags;
50 	unsigned int *depth;
51 
52 	local_irq_save(flags);
53 
54 	depth = this_cpu_ptr(&opal_trace_depth);
55 
56 	if (*depth)
57 		goto out;
58 
59 	(*depth)++;
60 	preempt_disable();
61 	trace_opal_entry(opcode, args);
62 	(*depth)--;
63 
64 out:
65 	local_irq_restore(flags);
66 }
67 
68 void __trace_opal_exit(long opcode, unsigned long retval)
69 {
70 	unsigned long flags;
71 	unsigned int *depth;
72 
73 	local_irq_save(flags);
74 
75 	depth = this_cpu_ptr(&opal_trace_depth);
76 
77 	if (*depth)
78 		goto out;
79 
80 	(*depth)++;
81 	trace_opal_exit(opcode, retval);
82 	preempt_enable();
83 	(*depth)--;
84 
85 out:
86 	local_irq_restore(flags);
87 }
88