• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Remote Processor Framework
4  *
5  * Copyright (C) 2011 Texas Instruments, Inc.
6  * Copyright (C) 2011 Google, Inc.
7  *
8  * Ohad Ben-Cohen <ohad@wizery.com>
9  * Mark Grosen <mgrosen@ti.com>
10  * Brian Swetland <swetland@google.com>
11  * Fernando Guzman Lugo <fernando.lugo@ti.com>
12  * Suman Anna <s-anna@ti.com>
13  * Robert Tivy <rtivy@ti.com>
14  * Armando Uribe De Leon <x0095078@ti.com>
15  */
16 
17 #define pr_fmt(fmt)    "%s: " fmt, __func__
18 
19 #include <linux/kernel.h>
20 #include <linux/debugfs.h>
21 #include <linux/remoteproc.h>
22 #include <linux/device.h>
23 #include <linux/uaccess.h>
24 
25 #include "remoteproc_internal.h"
26 
27 /* remoteproc debugfs parent dir */
28 static struct dentry *rproc_dbg;
29 
30 /*
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 */
rproc_coredump_read(struct file * filp,char __user * userbuf,size_t count,loff_t * ppos)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  */
rproc_coredump_write(struct file * filp,const char __user * user_buf,size_t count,loff_t * ppos)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 /*
118  * Some remote processors may support dumping trace logs into a shared
119  * memory buffer. We expose this trace buffer using debugfs, so users
120  * can easily tell what's going on remotely.
121  *
122  * We will most probably improve the rproc tracing facilities later on,
123  * but this kind of lightweight and simple mechanism is always good to have,
124  * as it provides very early tracing with little to no dependencies at all.
125  */
rproc_trace_read(struct file * filp,char __user * userbuf,size_t count,loff_t * ppos)126 static ssize_t rproc_trace_read(struct file *filp, char __user *userbuf,
127 				size_t count, loff_t *ppos)
128 {
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;
134 
135 	va = rproc_da_to_va(data->rproc, trace->da, trace->len);
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);
146 }
147 
148 static const struct file_operations trace_rproc_ops = {
149 	.read = rproc_trace_read,
150 	.open = simple_open,
151 	.llseek	= generic_file_llseek,
152 };
153 
154 /* expose the name of the remote processor via debugfs */
rproc_name_read(struct file * filp,char __user * userbuf,size_t count,loff_t * ppos)155 static ssize_t rproc_name_read(struct file *filp, char __user *userbuf,
156 			       size_t count, loff_t *ppos)
157 {
158 	struct rproc *rproc = filp->private_data;
159 	/* need room for the name, a newline and a terminating null */
160 	char buf[100];
161 	int i;
162 
163 	i = scnprintf(buf, sizeof(buf), "%.98s\n", rproc->name);
164 
165 	return simple_read_from_buffer(userbuf, count, ppos, buf, i);
166 }
167 
168 static const struct file_operations rproc_name_ops = {
169 	.read = rproc_name_read,
170 	.open = simple_open,
171 	.llseek	= generic_file_llseek,
172 };
173 
174 /* expose recovery flag via debugfs */
rproc_recovery_read(struct file * filp,char __user * userbuf,size_t count,loff_t * ppos)175 static ssize_t rproc_recovery_read(struct file *filp, char __user *userbuf,
176 				   size_t count, loff_t *ppos)
177 {
178 	struct rproc *rproc = filp->private_data;
179 	char *buf = rproc->recovery_disabled ? "disabled\n" : "enabled\n";
180 
181 	return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf));
182 }
183 
184 /*
185  * By writing to the 'recovery' debugfs entry, we control the behavior of the
186  * recovery mechanism dynamically. The default value of this entry is "enabled".
187  *
188  * The 'recovery' debugfs entry supports these commands:
189  *
190  * enabled:	When enabled, the remote processor will be automatically
191  *		recovered whenever it crashes. Moreover, if the remote
192  *		processor crashes while recovery is disabled, it will
193  *		be automatically recovered too as soon as recovery is enabled.
194  *
195  * disabled:	When disabled, a remote processor will remain in a crashed
196  *		state if it crashes. This is useful for debugging purposes;
197  *		without it, debugging a crash is substantially harder.
198  *
199  * recover:	This function will trigger an immediate recovery if the
200  *		remote processor is in a crashed state, without changing
201  *		or checking the recovery state (enabled/disabled).
202  *		This is useful during debugging sessions, when one expects
203  *		additional crashes to happen after enabling recovery. In this
204  *		case, enabling recovery will make it hard to debug subsequent
205  *		crashes, so it's recommended to keep recovery disabled, and
206  *		instead use the "recover" command as needed.
207  */
208 static ssize_t
rproc_recovery_write(struct file * filp,const char __user * user_buf,size_t count,loff_t * ppos)209 rproc_recovery_write(struct file *filp, const char __user *user_buf,
210 		     size_t count, loff_t *ppos)
211 {
212 	struct rproc *rproc = filp->private_data;
213 	char buf[10];
214 	int ret;
215 
216 	if (count < 1 || count > sizeof(buf))
217 		return -EINVAL;
218 
219 	ret = copy_from_user(buf, user_buf, count);
220 	if (ret)
221 		return -EFAULT;
222 
223 	/* remove end of line */
224 	if (buf[count - 1] == '\n')
225 		buf[count - 1] = '\0';
226 
227 	if (!strncmp(buf, "enabled", count)) {
228 		/* change the flag and begin the recovery process if needed */
229 		rproc->recovery_disabled = false;
230 		rproc_trigger_recovery(rproc);
231 	} else if (!strncmp(buf, "disabled", count)) {
232 		rproc->recovery_disabled = true;
233 	} else if (!strncmp(buf, "recover", count)) {
234 		/* begin the recovery process without changing the flag */
235 		rproc_trigger_recovery(rproc);
236 	} else {
237 		return -EINVAL;
238 	}
239 
240 	return count;
241 }
242 
243 static const struct file_operations rproc_recovery_ops = {
244 	.read = rproc_recovery_read,
245 	.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
rproc_crash_write(struct file * filp,const char __user * user_buf,size_t count,loff_t * ppos)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,
270 	.open = simple_open,
271 	.llseek = generic_file_llseek,
272 };
273 
274 /* Expose resource table content via debugfs */
rproc_rsc_table_show(struct seq_file * seq,void * p)275 static int rproc_rsc_table_show(struct seq_file *seq, void *p)
276 {
277 	static const char * const types[] = {"carveout", "devmem", "trace", "vdev"};
278 	struct rproc *rproc = seq->private;
279 	struct resource_table *table = rproc->table_ptr;
280 	struct fw_rsc_carveout *c;
281 	struct fw_rsc_devmem *d;
282 	struct fw_rsc_trace *t;
283 	struct fw_rsc_vdev *v;
284 	int i, j;
285 
286 	if (!table) {
287 		seq_puts(seq, "No resource table found\n");
288 		return 0;
289 	}
290 
291 	for (i = 0; i < table->num; i++) {
292 		int offset = table->offset[i];
293 		struct fw_rsc_hdr *hdr = (void *)table + offset;
294 		void *rsc = (void *)hdr + sizeof(*hdr);
295 
296 		switch (hdr->type) {
297 		case RSC_CARVEOUT:
298 			c = rsc;
299 			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
300 			seq_printf(seq, "  Device Address 0x%x\n", c->da);
301 			seq_printf(seq, "  Physical Address 0x%x\n", c->pa);
302 			seq_printf(seq, "  Length 0x%x Bytes\n", c->len);
303 			seq_printf(seq, "  Flags 0x%x\n", c->flags);
304 			seq_printf(seq, "  Reserved (should be zero) [%d]\n", c->reserved);
305 			seq_printf(seq, "  Name %s\n\n", c->name);
306 			break;
307 		case RSC_DEVMEM:
308 			d = rsc;
309 			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
310 			seq_printf(seq, "  Device Address 0x%x\n", d->da);
311 			seq_printf(seq, "  Physical Address 0x%x\n", d->pa);
312 			seq_printf(seq, "  Length 0x%x Bytes\n", d->len);
313 			seq_printf(seq, "  Flags 0x%x\n", d->flags);
314 			seq_printf(seq, "  Reserved (should be zero) [%d]\n", d->reserved);
315 			seq_printf(seq, "  Name %s\n\n", d->name);
316 			break;
317 		case RSC_TRACE:
318 			t = rsc;
319 			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
320 			seq_printf(seq, "  Device Address 0x%x\n", t->da);
321 			seq_printf(seq, "  Length 0x%x Bytes\n", t->len);
322 			seq_printf(seq, "  Reserved (should be zero) [%d]\n", t->reserved);
323 			seq_printf(seq, "  Name %s\n\n", t->name);
324 			break;
325 		case RSC_VDEV:
326 			v = rsc;
327 			seq_printf(seq, "Entry %d is of type %s\n", i, types[hdr->type]);
328 
329 			seq_printf(seq, "  ID %d\n", v->id);
330 			seq_printf(seq, "  Notify ID %d\n", v->notifyid);
331 			seq_printf(seq, "  Device features 0x%x\n", v->dfeatures);
332 			seq_printf(seq, "  Guest features 0x%x\n", v->gfeatures);
333 			seq_printf(seq, "  Config length 0x%x\n", v->config_len);
334 			seq_printf(seq, "  Status 0x%x\n", v->status);
335 			seq_printf(seq, "  Number of vrings %d\n", v->num_of_vrings);
336 			seq_printf(seq, "  Reserved (should be zero) [%d][%d]\n\n",
337 				   v->reserved[0], v->reserved[1]);
338 
339 			for (j = 0; j < v->num_of_vrings; j++) {
340 				seq_printf(seq, "  Vring %d\n", j);
341 				seq_printf(seq, "    Device Address 0x%x\n", v->vring[j].da);
342 				seq_printf(seq, "    Alignment %d\n", v->vring[j].align);
343 				seq_printf(seq, "    Number of buffers %d\n", v->vring[j].num);
344 				seq_printf(seq, "    Notify ID %d\n", v->vring[j].notifyid);
345 				seq_printf(seq, "    Physical Address 0x%x\n\n",
346 					   v->vring[j].pa);
347 			}
348 			break;
349 		default:
350 			seq_printf(seq, "Unknown resource type found: %d [hdr: %pK]\n",
351 				   hdr->type, hdr);
352 			break;
353 		}
354 	}
355 
356 	return 0;
357 }
358 
359 DEFINE_SHOW_ATTRIBUTE(rproc_rsc_table);
360 
361 /* Expose carveout content via debugfs */
rproc_carveouts_show(struct seq_file * seq,void * p)362 static int rproc_carveouts_show(struct seq_file *seq, void *p)
363 {
364 	struct rproc *rproc = seq->private;
365 	struct rproc_mem_entry *carveout;
366 
367 	list_for_each_entry(carveout, &rproc->carveouts, node) {
368 		seq_puts(seq, "Carveout memory entry:\n");
369 		seq_printf(seq, "\tName: %s\n", carveout->name);
370 		seq_printf(seq, "\tVirtual address: %pK\n", carveout->va);
371 		seq_printf(seq, "\tDMA address: %pad\n", &carveout->dma);
372 		seq_printf(seq, "\tDevice address: 0x%x\n", carveout->da);
373 		seq_printf(seq, "\tLength: 0x%zx Bytes\n\n", carveout->len);
374 	}
375 
376 	return 0;
377 }
378 
379 DEFINE_SHOW_ATTRIBUTE(rproc_carveouts);
380 
rproc_remove_trace_file(struct dentry * tfile)381 void rproc_remove_trace_file(struct dentry *tfile)
382 {
383 	debugfs_remove(tfile);
384 }
385 
rproc_create_trace_file(const char * name,struct rproc * rproc,struct rproc_debug_trace * trace)386 struct dentry *rproc_create_trace_file(const char *name, struct rproc *rproc,
387 				       struct rproc_debug_trace *trace)
388 {
389 	struct dentry *tfile;
390 
391 	tfile = debugfs_create_file(name, 0400, rproc->dbg_dir, trace,
392 				    &trace_rproc_ops);
393 	if (!tfile) {
394 		dev_err(&rproc->dev, "failed to create debugfs trace entry\n");
395 		return NULL;
396 	}
397 
398 	return tfile;
399 }
400 
rproc_delete_debug_dir(struct rproc * rproc)401 void rproc_delete_debug_dir(struct rproc *rproc)
402 {
403 	debugfs_remove_recursive(rproc->dbg_dir);
404 }
405 
rproc_create_debug_dir(struct rproc * rproc)406 void rproc_create_debug_dir(struct rproc *rproc)
407 {
408 	struct device *dev = &rproc->dev;
409 
410 	if (!rproc_dbg)
411 		return;
412 
413 	rproc->dbg_dir = debugfs_create_dir(dev_name(dev), rproc_dbg);
414 	if (!rproc->dbg_dir)
415 		return;
416 
417 	debugfs_create_file("name", 0400, rproc->dbg_dir,
418 			    rproc, &rproc_name_ops);
419 	debugfs_create_file("recovery", 0600, rproc->dbg_dir,
420 			    rproc, &rproc_recovery_ops);
421 	debugfs_create_file("crash", 0200, rproc->dbg_dir,
422 			    rproc, &rproc_crash_ops);
423 	debugfs_create_file("resource_table", 0400, rproc->dbg_dir,
424 			    rproc, &rproc_rsc_table_fops);
425 	debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir,
426 			    rproc, &rproc_carveouts_fops);
427 	debugfs_create_file("coredump", 0600, rproc->dbg_dir,
428 			    rproc, &rproc_coredump_fops);
429 }
430 
rproc_init_debugfs(void)431 void __init rproc_init_debugfs(void)
432 {
433 	if (debugfs_initialized()) {
434 		rproc_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
435 		if (!rproc_dbg)
436 			pr_err("can't create debugfs dir\n");
437 	}
438 }
439 
rproc_exit_debugfs(void)440 void __exit rproc_exit_debugfs(void)
441 {
442 	debugfs_remove(rproc_dbg);
443 }
444