18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/percpu.h>
38c2ecf20Sopenharmony_ci#include <linux/jump_label.h>
48c2ecf20Sopenharmony_ci#include <asm/trace.h>
58c2ecf20Sopenharmony_ci#include <asm/asm-prototypes.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#ifdef CONFIG_JUMP_LABEL
88c2ecf20Sopenharmony_cistruct static_key opal_tracepoint_key = STATIC_KEY_INIT;
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ciint opal_tracepoint_regfunc(void)
118c2ecf20Sopenharmony_ci{
128c2ecf20Sopenharmony_ci	static_key_slow_inc(&opal_tracepoint_key);
138c2ecf20Sopenharmony_ci	return 0;
148c2ecf20Sopenharmony_ci}
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_civoid opal_tracepoint_unregfunc(void)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	static_key_slow_dec(&opal_tracepoint_key);
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci#else
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * We optimise OPAL calls by placing opal_tracepoint_refcount
238c2ecf20Sopenharmony_ci * directly in the TOC so we can check if the opal tracepoints are
248c2ecf20Sopenharmony_ci * enabled via a single load.
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/* NB: reg/unreg are called while guarded with the tracepoints_mutex */
288c2ecf20Sopenharmony_ciextern long opal_tracepoint_refcount;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciint opal_tracepoint_regfunc(void)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	opal_tracepoint_refcount++;
338c2ecf20Sopenharmony_ci	return 0;
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_civoid opal_tracepoint_unregfunc(void)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	opal_tracepoint_refcount--;
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci#endif
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/*
438c2ecf20Sopenharmony_ci * Since the tracing code might execute OPAL calls we need to guard against
448c2ecf20Sopenharmony_ci * recursion.
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(unsigned int, opal_trace_depth);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_civoid __trace_opal_entry(unsigned long opcode, unsigned long *args)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	unsigned long flags;
518c2ecf20Sopenharmony_ci	unsigned int *depth;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	local_irq_save(flags);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	depth = this_cpu_ptr(&opal_trace_depth);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (*depth)
588c2ecf20Sopenharmony_ci		goto out;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	(*depth)++;
618c2ecf20Sopenharmony_ci	preempt_disable();
628c2ecf20Sopenharmony_ci	trace_opal_entry(opcode, args);
638c2ecf20Sopenharmony_ci	(*depth)--;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciout:
668c2ecf20Sopenharmony_ci	local_irq_restore(flags);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_civoid __trace_opal_exit(long opcode, unsigned long retval)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	unsigned long flags;
728c2ecf20Sopenharmony_ci	unsigned int *depth;
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	local_irq_save(flags);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	depth = this_cpu_ptr(&opal_trace_depth);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (*depth)
798c2ecf20Sopenharmony_ci		goto out;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	(*depth)++;
828c2ecf20Sopenharmony_ci	trace_opal_exit(opcode, retval);
838c2ecf20Sopenharmony_ci	preempt_enable();
848c2ecf20Sopenharmony_ci	(*depth)--;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciout:
878c2ecf20Sopenharmony_ci	local_irq_restore(flags);
888c2ecf20Sopenharmony_ci}
89