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