hc
2024-10-12 a5969cabbb4660eab42b6ef0412cbbd1200cf14d
kernel/drivers/remoteproc/remoteproc_debugfs.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Remote Processor Framework
34 *
....@@ -11,15 +12,6 @@
1112 * Suman Anna <s-anna@ti.com>
1213 * Robert Tivy <rtivy@ti.com>
1314 * 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.
2315 */
2416
2517 #define pr_fmt(fmt) "%s: " fmt, __func__
....@@ -36,6 +28,93 @@
3628 static struct dentry *rproc_dbg;
3729
3830 /*
31
+ * A coredump-configuration-to-string lookup table, for exposing a
32
+ * human readable configuration via debugfs. Always keep in sync with
33
+ * enum rproc_coredump_mechanism
34
+ */
35
+static const char * const rproc_coredump_str[] = {
36
+ [RPROC_COREDUMP_DISABLED] = "disabled",
37
+ [RPROC_COREDUMP_ENABLED] = "enabled",
38
+ [RPROC_COREDUMP_INLINE] = "inline",
39
+};
40
+
41
+/* Expose the current coredump configuration via debugfs */
42
+static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf,
43
+ size_t count, loff_t *ppos)
44
+{
45
+ struct rproc *rproc = filp->private_data;
46
+ char buf[20];
47
+ int len;
48
+
49
+ len = scnprintf(buf, sizeof(buf), "%s\n",
50
+ rproc_coredump_str[rproc->dump_conf]);
51
+
52
+ return simple_read_from_buffer(userbuf, count, ppos, buf, len);
53
+}
54
+
55
+/*
56
+ * By writing to the 'coredump' debugfs entry, we control the behavior of the
57
+ * coredump mechanism dynamically. The default value of this entry is "disabled".
58
+ *
59
+ * The 'coredump' debugfs entry supports these commands:
60
+ *
61
+ * disabled: By default coredump collection is disabled. Recovery will
62
+ * proceed without collecting any dump.
63
+ *
64
+ * enabled: When the remoteproc crashes the entire coredump will be copied
65
+ * to a separate buffer and exposed to userspace.
66
+ *
67
+ * inline: The coredump will not be copied to a separate buffer and the
68
+ * recovery process will have to wait until data is read by
69
+ * userspace. But this avoid usage of extra memory.
70
+ */
71
+static ssize_t rproc_coredump_write(struct file *filp,
72
+ const char __user *user_buf, size_t count,
73
+ loff_t *ppos)
74
+{
75
+ struct rproc *rproc = filp->private_data;
76
+ int ret, err = 0;
77
+ char buf[20];
78
+
79
+ if (count < 1 || count > sizeof(buf))
80
+ return -EINVAL;
81
+
82
+ ret = copy_from_user(buf, user_buf, count);
83
+ if (ret)
84
+ return -EFAULT;
85
+
86
+ /* remove end of line */
87
+ if (buf[count - 1] == '\n')
88
+ buf[count - 1] = '\0';
89
+
90
+ if (rproc->state == RPROC_CRASHED) {
91
+ dev_err(&rproc->dev, "can't change coredump configuration\n");
92
+ err = -EBUSY;
93
+ goto out;
94
+ }
95
+
96
+ if (!strncmp(buf, "disabled", count)) {
97
+ rproc->dump_conf = RPROC_COREDUMP_DISABLED;
98
+ } else if (!strncmp(buf, "enabled", count)) {
99
+ rproc->dump_conf = RPROC_COREDUMP_ENABLED;
100
+ } else if (!strncmp(buf, "inline", count)) {
101
+ rproc->dump_conf = RPROC_COREDUMP_INLINE;
102
+ } else {
103
+ dev_err(&rproc->dev, "Invalid coredump configuration\n");
104
+ err = -EINVAL;
105
+ }
106
+out:
107
+ return err ? err : count;
108
+}
109
+
110
+static const struct file_operations rproc_coredump_fops = {
111
+ .read = rproc_coredump_read,
112
+ .write = rproc_coredump_write,
113
+ .open = simple_open,
114
+ .llseek = generic_file_llseek,
115
+};
116
+
117
+/*
39118 * Some remote processors may support dumping trace logs into a shared
40119 * memory buffer. We expose this trace buffer using debugfs, so users
41120 * can easily tell what's going on remotely.
....@@ -47,10 +126,23 @@
47126 static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
48127 size_t count, loff_t *ppos)
49128 {
50
- struct rproc_mem_entry *trace = filp->private_data;
51
- int len = strnlen(trace->va, trace->len);
129
+ struct rproc_debug_trace *data = filp->private_data;
130
+ struct rproc_mem_entry *trace = &data->trace_mem;
131
+ void *va;
132
+ char buf[100];
133
+ int len;
52134
53
- return simple_read_from_buffer(userbuf, count, ppos, trace->va, len);
135
+ va = rproc_da_to_va(data->rproc, trace->da, trace->len, NULL);
136
+
137
+ if (!va) {
138
+ len = scnprintf(buf, sizeof(buf), "Trace %s not available\n",
139
+ trace->name);
140
+ va = buf;
141
+ } else {
142
+ len = strnlen(va, trace->len);
143
+ }
144
+
145
+ return simple_read_from_buffer(userbuf, count, ppos, va, len);
54146 }
55147
56148 static const struct file_operations trace_rproc_ops = {
....@@ -133,16 +225,16 @@
133225 buf[count - 1] = '\0';
134226
135227 if (!strncmp(buf, "enabled", count)) {
228
+ /* change the flag and begin the recovery process if needed */
136229 rproc->recovery_disabled = false;
137
- /* if rproc has crashed, trigger recovery */
138
- if (rproc->state == RPROC_CRASHED)
139
- rproc_trigger_recovery(rproc);
230
+ rproc_trigger_recovery(rproc);
140231 } else if (!strncmp(buf, "disabled", count)) {
141232 rproc->recovery_disabled = true;
142233 } else if (!strncmp(buf, "recover", count)) {
143
- /* if rproc has crashed, trigger recovery */
144
- if (rproc->state == RPROC_CRASHED)
145
- rproc_trigger_recovery(rproc);
234
+ /* begin the recovery process without changing the flag */
235
+ rproc_trigger_recovery(rproc);
236
+ } else {
237
+ return -EINVAL;
146238 }
147239
148240 return count;
....@@ -151,6 +243,30 @@
151243 static const struct file_operations rproc_recovery_ops = {
152244 .read = rproc_recovery_read,
153245 .write = rproc_recovery_write,
246
+ .open = simple_open,
247
+ .llseek = generic_file_llseek,
248
+};
249
+
250
+/* expose the crash trigger via debugfs */
251
+static ssize_t
252
+rproc_crash_write(struct file *filp, const char __user *user_buf,
253
+ size_t count, loff_t *ppos)
254
+{
255
+ struct rproc *rproc = filp->private_data;
256
+ unsigned int type;
257
+ int ret;
258
+
259
+ ret = kstrtouint_from_user(user_buf, count, 0, &type);
260
+ if (ret < 0)
261
+ return ret;
262
+
263
+ rproc_report_crash(rproc, type);
264
+
265
+ return count;
266
+}
267
+
268
+static const struct file_operations rproc_crash_ops = {
269
+ .write = rproc_crash_write,
154270 .open = simple_open,
155271 .llseek = generic_file_llseek,
156272 };
....@@ -240,17 +356,7 @@
240356 return 0;
241357 }
242358
243
-static int rproc_rsc_table_open(struct inode *inode, struct file *file)
244
-{
245
- return single_open(file, rproc_rsc_table_show, inode->i_private);
246
-}
247
-
248
-static const struct file_operations rproc_rsc_table_ops = {
249
- .open = rproc_rsc_table_open,
250
- .read = seq_read,
251
- .llseek = seq_lseek,
252
- .release = single_release,
253
-};
359
+DEFINE_SHOW_ATTRIBUTE(rproc_rsc_table);
254360
255361 /* Expose carveout content via debugfs */
256362 static int rproc_carveouts_show(struct seq_file *seq, void *p)
....@@ -260,26 +366,17 @@
260366
261367 list_for_each_entry(carveout, &rproc->carveouts, node) {
262368 seq_puts(seq, "Carveout memory entry:\n");
369
+ seq_printf(seq, "\tName: %s\n", carveout->name);
263370 seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
264371 seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
265372 seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
266
- seq_printf(seq, "\tLength: 0x%x Bytes\n\n", carveout->len);
373
+ seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len);
267374 }
268375
269376 return 0;
270377 }
271378
272
-static int rproc_carveouts_open(struct inode *inode, struct file *file)
273
-{
274
- return single_open(file, rproc_carveouts_show, inode->i_private);
275
-}
276
-
277
-static const struct file_operations rproc_carveouts_ops = {
278
- .open = rproc_carveouts_open,
279
- .read = seq_read,
280
- .llseek = seq_lseek,
281
- .release = single_release,
282
-};
379
+DEFINE_SHOW_ATTRIBUTE(rproc_carveouts);
283380
284381 void rproc_remove_trace_file(struct dentry *tfile)
285382 {
....@@ -287,7 +384,7 @@
287384 }
288385
289386 struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
290
- struct rproc_mem_entry *trace)
387
+ struct rproc_debug_trace *trace)
291388 {
292389 struct dentry *tfile;
293390
....@@ -303,9 +400,6 @@
303400
304401 void rproc_delete_debug_dir(struct rproc *rproc)
305402 {
306
- if (!rproc->dbg_dir)
307
- return;
308
-
309403 debugfs_remove_recursive(rproc->dbg_dir);
310404 }
311405
....@@ -322,12 +416,16 @@
322416
323417 debugfs_create_file("name", 0400, rproc->dbg_dir,
324418 rproc, &rproc_name_ops);
325
- debugfs_create_file("recovery", 0400, rproc->dbg_dir,
419
+ debugfs_create_file("recovery", 0600, rproc->dbg_dir,
326420 rproc, &rproc_recovery_ops);
421
+ debugfs_create_file("crash", 0200, rproc->dbg_dir,
422
+ rproc, &rproc_crash_ops);
327423 debugfs_create_file("resource_table", 0400, rproc->dbg_dir,
328
- rproc, &rproc_rsc_table_ops);
424
+ rproc, &rproc_rsc_table_fops);
329425 debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
330
- rproc, &rproc_carveouts_ops);
426
+ rproc, &rproc_carveouts_fops);
427
+ debugfs_create_file("coredump", 0600, rproc->dbg_dir,
428
+ rproc, &rproc_coredump_fops);
331429 }
332430
333431 void __init rproc_init_debugfs(void)