1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Simple kernel driver to link kernel Ftrace and an STM device |
4 | * Copyright (c) 2016, Linaro Ltd. |
5 | * |
6 | * STM Ftrace will be registered as a trace_export. |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/stm.h> |
11 | #include <linux/trace.h> |
12 | |
13 | #define STM_FTRACE_NR_CHANNELS 1 |
14 | #define STM_FTRACE_CHAN 0 |
15 | |
16 | static int stm_ftrace_link(struct stm_source_data *data); |
17 | static void stm_ftrace_unlink(struct stm_source_data *data); |
18 | |
19 | static struct stm_ftrace { |
20 | struct stm_source_data data; |
21 | struct trace_export ftrace; |
22 | } stm_ftrace = { |
23 | .data = { |
24 | .name = "ftrace" , |
25 | .nr_chans = STM_FTRACE_NR_CHANNELS, |
26 | .link = stm_ftrace_link, |
27 | .unlink = stm_ftrace_unlink, |
28 | }, |
29 | }; |
30 | |
31 | /** |
32 | * stm_ftrace_write() - write data to STM via 'stm_ftrace' source |
33 | * @buf: buffer containing the data packet |
34 | * @len: length of the data packet |
35 | */ |
36 | static void notrace |
37 | stm_ftrace_write(struct trace_export *export, const void *buf, unsigned int len) |
38 | { |
39 | struct stm_ftrace *stm = container_of(export, struct stm_ftrace, ftrace); |
40 | /* This is called from trace system with preemption disabled */ |
41 | unsigned int cpu = smp_processor_id(); |
42 | |
43 | stm_source_write(data: &stm->data, STM_FTRACE_CHAN + cpu, buf, count: len); |
44 | } |
45 | |
46 | static int stm_ftrace_link(struct stm_source_data *data) |
47 | { |
48 | struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data); |
49 | |
50 | sf->ftrace.write = stm_ftrace_write; |
51 | sf->ftrace.flags = TRACE_EXPORT_FUNCTION | TRACE_EXPORT_EVENT |
52 | | TRACE_EXPORT_MARKER; |
53 | |
54 | return register_ftrace_export(export: &sf->ftrace); |
55 | } |
56 | |
57 | static void stm_ftrace_unlink(struct stm_source_data *data) |
58 | { |
59 | struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data); |
60 | |
61 | unregister_ftrace_export(export: &sf->ftrace); |
62 | } |
63 | |
64 | static int __init stm_ftrace_init(void) |
65 | { |
66 | int ret; |
67 | |
68 | stm_ftrace.data.nr_chans = roundup_pow_of_two(num_possible_cpus()); |
69 | ret = stm_source_register_device(NULL, data: &stm_ftrace.data); |
70 | if (ret) |
71 | pr_err("Failed to register stm_source - ftrace.\n" ); |
72 | |
73 | return ret; |
74 | } |
75 | |
76 | static void __exit stm_ftrace_exit(void) |
77 | { |
78 | stm_source_unregister_device(data: &stm_ftrace.data); |
79 | } |
80 | |
81 | module_init(stm_ftrace_init); |
82 | module_exit(stm_ftrace_exit); |
83 | |
84 | MODULE_LICENSE("GPL v2" ); |
85 | MODULE_DESCRIPTION("stm_ftrace driver" ); |
86 | MODULE_AUTHOR("Chunyan Zhang <zhang.chunyan@linaro.org>" ); |
87 | |