diff options
author | Ohad Ben-Cohen <ohad@wizery.com> | 2011-10-20 11:24:15 -0400 |
---|---|---|
committer | Ohad Ben-Cohen <ohad@wizery.com> | 2012-02-08 15:53:30 -0500 |
commit | 6391a70682b173abb8f2895c03c6b21d764e04e5 (patch) | |
tree | fc0a04f7d8568dae1335afbf87cb24f8f2c416b2 /drivers/remoteproc/remoteproc_debugfs.c | |
parent | 400e64df6b237eb36b127efd72000a2794f9eec1 (diff) |
remoteproc: add debugfs entries
Expose several remote processor properties (name, state, trace buffer)
that are helpful for debugging.
This part is extracted to a separate patch just to keep the review load
down.
Designed with Brian Swetland <swetland@google.com>.
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Cc: Brian Swetland <swetland@google.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Russell King <linux@arm.linux.org.uk>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Greg KH <greg@kroah.com>
Cc: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/remoteproc/remoteproc_debugfs.c')
-rw-r--r-- | drivers/remoteproc/remoteproc_debugfs.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c new file mode 100644 index 000000000000..70277a530133 --- /dev/null +++ b/drivers/remoteproc/remoteproc_debugfs.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Remote Processor Framework | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2011 Google, Inc. | ||
6 | * | ||
7 | * Ohad Ben-Cohen <ohad@wizery.com> | ||
8 | * Mark Grosen <mgrosen@ti.com> | ||
9 | * Brian Swetland <swetland@google.com> | ||
10 | * Fernando Guzman Lugo <fernando.lugo@ti.com> | ||
11 | * Suman Anna <s-anna@ti.com> | ||
12 | * Robert Tivy <rtivy@ti.com> | ||
13 | * Armando Uribe De Leon <x0095078@ti.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | */ | ||
24 | |||
25 | #define pr_fmt(fmt) "%s: " fmt, __func__ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/debugfs.h> | ||
29 | #include <linux/remoteproc.h> | ||
30 | #include <linux/device.h> | ||
31 | |||
32 | /* remoteproc debugfs parent dir */ | ||
33 | static struct dentry *rproc_dbg; | ||
34 | |||
35 | /* | ||
36 | * Some remote processors may support dumping trace logs into a shared | ||
37 | * memory buffer. We expose this trace buffer using debugfs, so users | ||
38 | * can easily tell what's going on remotely. | ||
39 | * | ||
40 | * We will most probably improve the rproc tracing facilities later on, | ||
41 | * but this kind of lightweight and simple mechanism is always good to have, | ||
42 | * as it provides very early tracing with little to no dependencies at all. | ||
43 | */ | ||
44 | static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf, | ||
45 | size_t count, loff_t *ppos) | ||
46 | { | ||
47 | struct rproc_mem_entry *trace = filp->private_data; | ||
48 | int len = strnlen(trace->va, trace->len); | ||
49 | |||
50 | return simple_read_from_buffer(userbuf, count, ppos, trace->va, len); | ||
51 | } | ||
52 | |||
53 | static int rproc_open_generic(struct inode *inode, struct file *file) | ||
54 | { | ||
55 | file->private_data = inode->i_private; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static const struct file_operations trace_rproc_ops = { | ||
61 | .read = rproc_trace_read, | ||
62 | .open = rproc_open_generic, | ||
63 | .llseek = generic_file_llseek, | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * A state-to-string lookup table, for exposing a human readable state | ||
68 | * via debugfs. Always keep in sync with enum rproc_state | ||
69 | */ | ||
70 | static const char * const rproc_state_string[] = { | ||
71 | "offline", | ||
72 | "suspended", | ||
73 | "running", | ||
74 | "crashed", | ||
75 | "invalid", | ||
76 | }; | ||
77 | |||
78 | /* expose the state of the remote processor via debugfs */ | ||
79 | static ssize_t rproc_state_read(struct file *filp, char __user *userbuf, | ||
80 | size_t count, loff_t *ppos) | ||
81 | { | ||
82 | struct rproc *rproc = filp->private_data; | ||
83 | unsigned int state; | ||
84 | char buf[30]; | ||
85 | int i; | ||
86 | |||
87 | state = rproc->state > RPROC_LAST ? RPROC_LAST : rproc->state; | ||
88 | |||
89 | i = snprintf(buf, 30, "%.28s (%d)\n", rproc_state_string[state], | ||
90 | rproc->state); | ||
91 | |||
92 | return simple_read_from_buffer(userbuf, count, ppos, buf, i); | ||
93 | } | ||
94 | |||
95 | static const struct file_operations rproc_state_ops = { | ||
96 | .read = rproc_state_read, | ||
97 | .open = rproc_open_generic, | ||
98 | .llseek = generic_file_llseek, | ||
99 | }; | ||
100 | |||
101 | /* expose the name of the remote processor via debugfs */ | ||
102 | static ssize_t rproc_name_read(struct file *filp, char __user *userbuf, | ||
103 | size_t count, loff_t *ppos) | ||
104 | { | ||
105 | struct rproc *rproc = filp->private_data; | ||
106 | /* need room for the name, a newline and a terminating null */ | ||
107 | char buf[100]; | ||
108 | int i; | ||
109 | |||
110 | i = snprintf(buf, sizeof(buf), "%.98s\n", rproc->name); | ||
111 | |||
112 | return simple_read_from_buffer(userbuf, count, ppos, buf, i); | ||
113 | } | ||
114 | |||
115 | static const struct file_operations rproc_name_ops = { | ||
116 | .read = rproc_name_read, | ||
117 | .open = rproc_open_generic, | ||
118 | .llseek = generic_file_llseek, | ||
119 | }; | ||
120 | |||
121 | void rproc_remove_trace_file(struct dentry *tfile) | ||
122 | { | ||
123 | debugfs_remove(tfile); | ||
124 | } | ||
125 | |||
126 | struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc, | ||
127 | struct rproc_mem_entry *trace) | ||
128 | { | ||
129 | struct dentry *tfile; | ||
130 | |||
131 | tfile = debugfs_create_file(name, 0400, rproc->dbg_dir, | ||
132 | trace, &trace_rproc_ops); | ||
133 | if (!tfile) { | ||
134 | dev_err(rproc->dev, "failed to create debugfs trace entry\n"); | ||
135 | return NULL; | ||
136 | } | ||
137 | |||
138 | return tfile; | ||
139 | } | ||
140 | |||
141 | void rproc_delete_debug_dir(struct rproc *rproc) | ||
142 | { | ||
143 | if (!rproc->dbg_dir) | ||
144 | return; | ||
145 | |||
146 | debugfs_remove_recursive(rproc->dbg_dir); | ||
147 | } | ||
148 | |||
149 | void rproc_create_debug_dir(struct rproc *rproc) | ||
150 | { | ||
151 | struct device *dev = rproc->dev; | ||
152 | |||
153 | if (!rproc_dbg) | ||
154 | return; | ||
155 | |||
156 | rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg); | ||
157 | if (!rproc->dbg_dir) | ||
158 | return; | ||
159 | |||
160 | debugfs_create_file("name", 0400, rproc->dbg_dir, | ||
161 | rproc, &rproc_name_ops); | ||
162 | debugfs_create_file("state", 0400, rproc->dbg_dir, | ||
163 | rproc, &rproc_state_ops); | ||
164 | } | ||
165 | |||
166 | void __init rproc_init_debugfs(void) | ||
167 | { | ||
168 | if (debugfs_initialized()) { | ||
169 | rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
170 | if (!rproc_dbg) | ||
171 | pr_err("can't create debugfs dir\n"); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | void __exit rproc_exit_debugfs(void) | ||
176 | { | ||
177 | if (rproc_dbg) | ||
178 | debugfs_remove(rproc_dbg); | ||
179 | } | ||