18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Simple kernel driver to link kernel Ftrace and an STM device
48c2ecf20Sopenharmony_ci * Copyright (c) 2016, Linaro Ltd.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * STM Ftrace will be registered as a trace_export.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/stm.h>
118c2ecf20Sopenharmony_ci#include <linux/trace.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define STM_FTRACE_NR_CHANNELS 1
148c2ecf20Sopenharmony_ci#define STM_FTRACE_CHAN 0
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int stm_ftrace_link(struct stm_source_data *data);
178c2ecf20Sopenharmony_cistatic void stm_ftrace_unlink(struct stm_source_data *data);
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic struct stm_ftrace {
208c2ecf20Sopenharmony_ci	struct stm_source_data	data;
218c2ecf20Sopenharmony_ci	struct trace_export	ftrace;
228c2ecf20Sopenharmony_ci} stm_ftrace = {
238c2ecf20Sopenharmony_ci	.data	= {
248c2ecf20Sopenharmony_ci		.name		= "ftrace",
258c2ecf20Sopenharmony_ci		.nr_chans	= STM_FTRACE_NR_CHANNELS,
268c2ecf20Sopenharmony_ci		.link		= stm_ftrace_link,
278c2ecf20Sopenharmony_ci		.unlink		= stm_ftrace_unlink,
288c2ecf20Sopenharmony_ci	},
298c2ecf20Sopenharmony_ci};
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/**
328c2ecf20Sopenharmony_ci * stm_ftrace_write() - write data to STM via 'stm_ftrace' source
338c2ecf20Sopenharmony_ci * @buf:	buffer containing the data packet
348c2ecf20Sopenharmony_ci * @len:	length of the data packet
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic void notrace
378c2ecf20Sopenharmony_cistm_ftrace_write(struct trace_export *export, const void *buf, unsigned int len)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct stm_ftrace *stm = container_of(export, struct stm_ftrace, ftrace);
408c2ecf20Sopenharmony_ci	/* This is called from trace system with preemption disabled */
418c2ecf20Sopenharmony_ci	unsigned int cpu = smp_processor_id();
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	stm_source_write(&stm->data, STM_FTRACE_CHAN + cpu, buf, len);
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_cistatic int stm_ftrace_link(struct stm_source_data *data)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	sf->ftrace.write = stm_ftrace_write;
518c2ecf20Sopenharmony_ci	sf->ftrace.flags = TRACE_EXPORT_FUNCTION | TRACE_EXPORT_EVENT
528c2ecf20Sopenharmony_ci			| TRACE_EXPORT_MARKER;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	return register_ftrace_export(&sf->ftrace);
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void stm_ftrace_unlink(struct stm_source_data *data)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	unregister_ftrace_export(&sf->ftrace);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int __init stm_ftrace_init(void)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	int ret;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	stm_ftrace.data.nr_chans = roundup_pow_of_two(num_possible_cpus());
698c2ecf20Sopenharmony_ci	ret = stm_source_register_device(NULL, &stm_ftrace.data);
708c2ecf20Sopenharmony_ci	if (ret)
718c2ecf20Sopenharmony_ci		pr_err("Failed to register stm_source - ftrace.\n");
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return ret;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic void __exit stm_ftrace_exit(void)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	stm_source_unregister_device(&stm_ftrace.data);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cimodule_init(stm_ftrace_init);
828c2ecf20Sopenharmony_cimodule_exit(stm_ftrace_exit);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
858c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("stm_ftrace driver");
868c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chunyan Zhang <zhang.chunyan@linaro.org>");
87