blob: 4b41310184dff9ae098fde9e83faf3c73d3e9305 [file] [log] [blame]
Masami Hiramatsu9c5b9d32020-01-11 01:06:17 +09001// SPDX-License-Identifier: GPL-2.0
2/*
3 * trace_boot.c
4 * Tracing kernel boot-time
5 */
6
7#define pr_fmt(fmt) "trace_boot: " fmt
8
9#include <linux/ftrace.h>
10#include <linux/init.h>
11#include <linux/bootconfig.h>
12
13#include "trace.h"
14
15#define MAX_BUF_LEN 256
16
17extern int trace_set_options(struct trace_array *tr, char *option);
18extern int tracing_set_tracer(struct trace_array *tr, const char *buf);
19extern ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
20 unsigned long size, int cpu_id);
21
22static void __init
23trace_boot_set_ftrace_options(struct trace_array *tr, struct xbc_node *node)
24{
25 struct xbc_node *anode;
26 const char *p;
27 char buf[MAX_BUF_LEN];
28 unsigned long v = 0;
29
30 /* Common ftrace options */
31 xbc_node_for_each_array_value(node, "options", anode, p) {
32 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) {
33 pr_err("String is too long: %s\n", p);
34 continue;
35 }
36
37 if (trace_set_options(tr, buf) < 0)
38 pr_err("Failed to set option: %s\n", buf);
39 }
40
41 p = xbc_node_find_value(node, "trace_clock", NULL);
42 if (p && *p != '\0') {
43 if (tracing_set_clock(tr, p) < 0)
44 pr_err("Failed to set trace clock: %s\n", p);
45 }
46
47 p = xbc_node_find_value(node, "buffer_size", NULL);
48 if (p && *p != '\0') {
49 v = memparse(p, NULL);
50 if (v < PAGE_SIZE)
51 pr_err("Buffer size is too small: %s\n", p);
52 if (tracing_resize_ring_buffer(tr, v, RING_BUFFER_ALL_CPUS) < 0)
53 pr_err("Failed to resize trace buffer to %s\n", p);
54 }
55}
56
57#ifdef CONFIG_EVENT_TRACING
58extern int ftrace_set_clr_event(struct trace_array *tr, char *buf, int set);
59
60static void __init
61trace_boot_enable_events(struct trace_array *tr, struct xbc_node *node)
62{
63 struct xbc_node *anode;
64 char buf[MAX_BUF_LEN];
65 const char *p;
66
67 xbc_node_for_each_array_value(node, "events", anode, p) {
68 if (strlcpy(buf, p, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf)) {
69 pr_err("String is too long: %s\n", p);
70 continue;
71 }
72
73 if (ftrace_set_clr_event(tr, buf, 1) < 0)
74 pr_err("Failed to enable event: %s\n", p);
75 }
76}
77#else
78#define trace_boot_enable_events(tr, node) do {} while (0)
79#endif
80
81static void __init
82trace_boot_enable_tracer(struct trace_array *tr, struct xbc_node *node)
83{
84 const char *p;
85
86 p = xbc_node_find_value(node, "tracer", NULL);
87 if (p && *p != '\0') {
88 if (tracing_set_tracer(tr, p) < 0)
89 pr_err("Failed to set given tracer: %s\n", p);
90 }
91}
92
93static int __init trace_boot_init(void)
94{
95 struct xbc_node *trace_node;
96 struct trace_array *tr;
97
98 trace_node = xbc_find_node("ftrace");
99 if (!trace_node)
100 return 0;
101
102 tr = top_trace_array();
103 if (!tr)
104 return 0;
105
106 trace_boot_set_ftrace_options(tr, trace_node);
107 trace_boot_enable_events(tr, trace_node);
108 trace_boot_enable_tracer(tr, trace_node);
109
110 return 0;
111}
112
113fs_initcall(trace_boot_init);