Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
  4 */
  5#include <linux/debugfs.h>
  6#include <linux/dma-mapping.h>
  7#include <linux/slab.h>
  8#include <linux/uaccess.h>
  9
 10#include <soc/tegra/bpmp.h>
 11#include <soc/tegra/bpmp-abi.h>
 12
 13static DEFINE_MUTEX(bpmp_debug_lock);
 14
 15struct seqbuf {
 16	char *buf;
 17	size_t pos;
 18	size_t size;
 19};
 20
 21static void seqbuf_init(struct seqbuf *seqbuf, void *buf, size_t size)
 22{
 23	seqbuf->buf = buf;
 24	seqbuf->size = size;
 25	seqbuf->pos = 0;
 26}
 27
 28static size_t seqbuf_avail(struct seqbuf *seqbuf)
 29{
 30	return seqbuf->pos < seqbuf->size ? seqbuf->size - seqbuf->pos : 0;
 31}
 32
 33static size_t seqbuf_status(struct seqbuf *seqbuf)
 34{
 35	return seqbuf->pos <= seqbuf->size ? 0 : -EOVERFLOW;
 36}
 37
 38static int seqbuf_eof(struct seqbuf *seqbuf)
 39{
 40	return seqbuf->pos >= seqbuf->size;
 41}
 42
 43static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte)
 44{
 45	nbyte = min(nbyte, seqbuf_avail(seqbuf));
 46	memcpy(buf, seqbuf->buf + seqbuf->pos, nbyte);
 47	seqbuf->pos += nbyte;
 48	return seqbuf_status(seqbuf);
 49}
 50
 51static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v)
 52{
 53	int err;
 54
 55	err = seqbuf_read(seqbuf, v, 4);
 56	*v = le32_to_cpu(*v);
 57	return err;
 58}
 59
 60static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str)
 61{
 62	*str = seqbuf->buf + seqbuf->pos;
 63	seqbuf->pos += strnlen(*str, seqbuf_avail(seqbuf));
 64	seqbuf->pos++;
 65	return seqbuf_status(seqbuf);
 66}
 67
 68static void seqbuf_seek(struct seqbuf *seqbuf, ssize_t offset)
 69{
 70	seqbuf->pos += offset;
 71}
 72
 73/* map filename in Linux debugfs to corresponding entry in BPMP */
 74static const char *get_filename(struct tegra_bpmp *bpmp,
 75				const struct file *file, char *buf, int size)
 76{
 77	char root_path_buf[512];
 78	const char *root_path;
 79	const char *filename;
 80	size_t root_len;
 81
 82	root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
 83				sizeof(root_path_buf));
 84	if (IS_ERR(root_path))
 85		return NULL;
 86
 87	root_len = strlen(root_path);
 88
 89	filename = dentry_path(file->f_path.dentry, buf, size);
 90	if (IS_ERR(filename))
 91		return NULL;
 92
 93	if (strlen(filename) < root_len ||
 94			strncmp(filename, root_path, root_len))
 95		return NULL;
 96
 97	filename += root_len;
 98
 99	return filename;
100}
101
102static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
103			  uint32_t *fd, uint32_t *len, bool write)
104{
105	struct mrq_debug_request req = {
106		.cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO),
107	};
108	struct mrq_debug_response resp;
109	struct tegra_bpmp_message msg = {
110		.mrq = MRQ_DEBUG,
111		.tx = {
112			.data = &req,
113			.size = sizeof(req),
114		},
115		.rx = {
116			.data = &resp,
117			.size = sizeof(resp),
118		},
119	};
120	ssize_t sz_name;
121	int err = 0;
122
123	sz_name = strscpy(req.fop.name, name, sizeof(req.fop.name));
124	if (sz_name < 0) {
125		pr_err("File name too large: %s\n", name);
126		return -EINVAL;
127	}
128
129	err = tegra_bpmp_transfer(bpmp, &msg);
130	if (err < 0)
131		return err;
132	else if (msg.rx.ret < 0)
133		return -EINVAL;
134
135	*len = resp.fop.datalen;
136	*fd = resp.fop.fd;
137
138	return 0;
139}
140
141static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
142{
143	struct mrq_debug_request req = {
144		.cmd = cpu_to_le32(CMD_DEBUG_CLOSE),
145		.frd = {
146			.fd = fd,
147		},
148	};
149	struct mrq_debug_response resp;
150	struct tegra_bpmp_message msg = {
151		.mrq = MRQ_DEBUG,
152		.tx = {
153			.data = &req,
154			.size = sizeof(req),
155		},
156		.rx = {
157			.data = &resp,
158			.size = sizeof(resp),
159		},
160	};
161	int err = 0;
162
163	err = tegra_bpmp_transfer(bpmp, &msg);
164	if (err < 0)
165		return err;
166	else if (msg.rx.ret < 0)
167		return -EINVAL;
168
169	return 0;
170}
171
172static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
173			  char *data, size_t sz_data, uint32_t *nbytes)
174{
175	struct mrq_debug_request req = {
176		.cmd = cpu_to_le32(CMD_DEBUG_READ),
177	};
178	struct mrq_debug_response resp;
179	struct tegra_bpmp_message msg = {
180		.mrq = MRQ_DEBUG,
181		.tx = {
182			.data = &req,
183			.size = sizeof(req),
184		},
185		.rx = {
186			.data = &resp,
187			.size = sizeof(resp),
188		},
189	};
190	uint32_t fd = 0, len = 0;
191	int remaining, err;
192
193	mutex_lock(&bpmp_debug_lock);
194	err = mrq_debug_open(bpmp, name, &fd, &len, 0);
195	if (err)
196		goto out;
197
198	if (len > sz_data) {
199		err = -EFBIG;
200		goto close;
201	}
202
203	req.frd.fd = fd;
204	remaining = len;
205
206	while (remaining > 0) {
207		err = tegra_bpmp_transfer(bpmp, &msg);
208		if (err < 0) {
209			goto close;
210		} else if (msg.rx.ret < 0) {
211			err = -EINVAL;
212			goto close;
213		}
214
215		if (resp.frd.readlen > remaining) {
216			pr_err("%s: read data length invalid\n", __func__);
217			err = -EINVAL;
218			goto close;
219		}
220
221		memcpy(data, resp.frd.data, resp.frd.readlen);
222		data += resp.frd.readlen;
223		remaining -= resp.frd.readlen;
224	}
225
226	*nbytes = len;
227
228close:
229	err = mrq_debug_close(bpmp, fd);
230out:
231	mutex_unlock(&bpmp_debug_lock);
232	return err;
233}
234
235static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
236			   uint8_t *data, size_t sz_data)
237{
238	struct mrq_debug_request req = {
239		.cmd = cpu_to_le32(CMD_DEBUG_WRITE)
240	};
241	struct mrq_debug_response resp;
242	struct tegra_bpmp_message msg = {
243		.mrq = MRQ_DEBUG,
244		.tx = {
245			.data = &req,
246			.size = sizeof(req),
247		},
248		.rx = {
249			.data = &resp,
250			.size = sizeof(resp),
251		},
252	};
253	uint32_t fd = 0, len = 0;
254	size_t remaining;
255	int err;
256
257	mutex_lock(&bpmp_debug_lock);
258	err = mrq_debug_open(bpmp, name, &fd, &len, 1);
259	if (err)
260		goto out;
261
262	if (sz_data > len) {
263		err = -EINVAL;
264		goto close;
265	}
266
267	req.fwr.fd = fd;
268	remaining = sz_data;
269
270	while (remaining > 0) {
271		len = min(remaining, sizeof(req.fwr.data));
272		memcpy(req.fwr.data, data, len);
273		req.fwr.datalen = len;
274
275		err = tegra_bpmp_transfer(bpmp, &msg);
276		if (err < 0) {
277			goto close;
278		} else if (msg.rx.ret < 0) {
279			err = -EINVAL;
280			goto close;
281		}
282
283		data += req.fwr.datalen;
284		remaining -= req.fwr.datalen;
285	}
286
287close:
288	err = mrq_debug_close(bpmp, fd);
289out:
290	mutex_unlock(&bpmp_debug_lock);
291	return err;
292}
293
294static int bpmp_debug_show(struct seq_file *m, void *p)
295{
296	struct file *file = m->private;
297	struct inode *inode = file_inode(file);
298	struct tegra_bpmp *bpmp = inode->i_private;
299	char *databuf = NULL;
300	char fnamebuf[256];
301	const char *filename;
302	uint32_t nbytes = 0;
303	size_t len;
304	int err;
305
306	len = seq_get_buf(m, &databuf);
307	if (!databuf)
308		return -ENOMEM;
309
310	filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
311	if (!filename)
312		return -ENOENT;
313
314	err = mrq_debug_read(bpmp, filename, databuf, len, &nbytes);
315	if (!err)
316		seq_commit(m, nbytes);
317
318	return err;
319}
320
321static ssize_t bpmp_debug_store(struct file *file, const char __user *buf,
322		size_t count, loff_t *f_pos)
323{
324	struct inode *inode = file_inode(file);
325	struct tegra_bpmp *bpmp = inode->i_private;
326	char *databuf = NULL;
327	char fnamebuf[256];
328	const char *filename;
329	ssize_t err;
330
331	filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
332	if (!filename)
333		return -ENOENT;
334
335	databuf = kmalloc(count, GFP_KERNEL);
336	if (!databuf)
337		return -ENOMEM;
338
339	if (copy_from_user(databuf, buf, count)) {
340		err = -EFAULT;
341		goto free_ret;
342	}
343
344	err = mrq_debug_write(bpmp, filename, databuf, count);
345
346free_ret:
347	kfree(databuf);
348
349	return err ?: count;
350}
351
352static int bpmp_debug_open(struct inode *inode, struct file *file)
353{
354	return single_open_size(file, bpmp_debug_show, file, SZ_256K);
355}
356
357static const struct file_operations bpmp_debug_fops = {
358	.open		= bpmp_debug_open,
359	.read		= seq_read,
360	.llseek		= seq_lseek,
361	.write		= bpmp_debug_store,
362	.release	= single_release,
363};
364
365static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
366					struct dentry *parent,
367					char *ppath)
368{
369	const size_t pathlen = SZ_256;
370	const size_t bufsize = SZ_16K;
371	uint32_t dsize, attrs = 0;
372	struct dentry *dentry;
373	struct seqbuf seqbuf;
374	char *buf, *pathbuf;
375	const char *name;
376	int err = 0;
377
378	if (!bpmp || !parent || !ppath)
379		return -EINVAL;
380
381	buf = kmalloc(bufsize, GFP_KERNEL);
382	if (!buf)
383		return -ENOMEM;
384
385	pathbuf = kzalloc(pathlen, GFP_KERNEL);
386	if (!pathbuf) {
387		kfree(buf);
388		return -ENOMEM;
389	}
390
391	err = mrq_debug_read(bpmp, ppath, buf, bufsize, &dsize);
392	if (err)
393		goto out;
394
395	seqbuf_init(&seqbuf, buf, dsize);
396
397	while (!seqbuf_eof(&seqbuf)) {
398		err = seqbuf_read_u32(&seqbuf, &attrs);
399		if (err)
400			goto out;
401
402		err = seqbuf_read_str(&seqbuf, &name);
403		if (err < 0)
404			goto out;
405
406		if (attrs & DEBUGFS_S_ISDIR) {
407			size_t len;
408
409			dentry = debugfs_create_dir(name, parent);
410			if (IS_ERR(dentry)) {
411				err = PTR_ERR(dentry);
412				goto out;
413			}
414
415			len = strlen(ppath) + strlen(name) + 1;
416			if (len >= pathlen) {
417				err = -EINVAL;
418				goto out;
419			}
420
421			strncpy(pathbuf, ppath, pathlen);
422			strncat(pathbuf, name, strlen(name));
423			strcat(pathbuf, "/");
424
425			err = bpmp_populate_debugfs_inband(bpmp, dentry,
426							   pathbuf);
427			if (err < 0)
428				goto out;
429		} else {
430			umode_t mode;
431
432			mode = attrs & DEBUGFS_S_IRUSR ? 0400 : 0;
433			mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0;
434			dentry = debugfs_create_file(name, mode, parent, bpmp,
435						     &bpmp_debug_fops);
436			if (!dentry) {
437				err = -ENOMEM;
438				goto out;
439			}
440		}
441	}
442
443out:
444	kfree(pathbuf);
445	kfree(buf);
446
447	return err;
448}
449
450static int mrq_debugfs_read(struct tegra_bpmp *bpmp,
451			    dma_addr_t name, size_t sz_name,
452			    dma_addr_t data, size_t sz_data,
453			    size_t *nbytes)
454{
455	struct mrq_debugfs_request req = {
456		.cmd = cpu_to_le32(CMD_DEBUGFS_READ),
457		.fop = {
458			.fnameaddr = cpu_to_le32((uint32_t)name),
459			.fnamelen = cpu_to_le32((uint32_t)sz_name),
460			.dataaddr = cpu_to_le32((uint32_t)data),
461			.datalen = cpu_to_le32((uint32_t)sz_data),
462		},
463	};
464	struct mrq_debugfs_response resp;
465	struct tegra_bpmp_message msg = {
466		.mrq = MRQ_DEBUGFS,
467		.tx = {
468			.data = &req,
469			.size = sizeof(req),
470		},
471		.rx = {
472			.data = &resp,
473			.size = sizeof(resp),
474		},
475	};
476	int err;
477
478	err = tegra_bpmp_transfer(bpmp, &msg);
479	if (err < 0)
480		return err;
481	else if (msg.rx.ret < 0)
482		return -EINVAL;
483
484	*nbytes = (size_t)resp.fop.nbytes;
485
486	return 0;
487}
488
489static int mrq_debugfs_write(struct tegra_bpmp *bpmp,
490			     dma_addr_t name, size_t sz_name,
491			     dma_addr_t data, size_t sz_data)
492{
493	const struct mrq_debugfs_request req = {
494		.cmd = cpu_to_le32(CMD_DEBUGFS_WRITE),
495		.fop = {
496			.fnameaddr = cpu_to_le32((uint32_t)name),
497			.fnamelen = cpu_to_le32((uint32_t)sz_name),
498			.dataaddr = cpu_to_le32((uint32_t)data),
499			.datalen = cpu_to_le32((uint32_t)sz_data),
500		},
501	};
502	struct tegra_bpmp_message msg = {
503		.mrq = MRQ_DEBUGFS,
504		.tx = {
505			.data = &req,
506			.size = sizeof(req),
507		},
508	};
509
510	return tegra_bpmp_transfer(bpmp, &msg);
511}
512
513static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr,
514			       size_t size, size_t *nbytes)
515{
516	const struct mrq_debugfs_request req = {
517		.cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR),
518		.dumpdir = {
519			.dataaddr = cpu_to_le32((uint32_t)addr),
520			.datalen = cpu_to_le32((uint32_t)size),
521		},
522	};
523	struct mrq_debugfs_response resp;
524	struct tegra_bpmp_message msg = {
525		.mrq = MRQ_DEBUGFS,
526		.tx = {
527			.data = &req,
528			.size = sizeof(req),
529		},
530		.rx = {
531			.data = &resp,
532			.size = sizeof(resp),
533		},
534	};
535	int err;
536
537	err = tegra_bpmp_transfer(bpmp, &msg);
538	if (err < 0)
539		return err;
540	else if (msg.rx.ret < 0)
541		return -EINVAL;
542
543	*nbytes = (size_t)resp.dumpdir.nbytes;
544
545	return 0;
546}
547
548static int debugfs_show(struct seq_file *m, void *p)
549{
550	struct file *file = m->private;
551	struct inode *inode = file_inode(file);
552	struct tegra_bpmp *bpmp = inode->i_private;
553	const size_t datasize = m->size;
554	const size_t namesize = SZ_256;
555	void *datavirt, *namevirt;
556	dma_addr_t dataphys, namephys;
557	char buf[256];
558	const char *filename;
559	size_t len, nbytes;
560	int err;
561
562	filename = get_filename(bpmp, file, buf, sizeof(buf));
563	if (!filename)
564		return -ENOENT;
565
566	namevirt = dma_alloc_coherent(bpmp->dev, namesize, &namephys,
567				      GFP_KERNEL | GFP_DMA32);
568	if (!namevirt)
569		return -ENOMEM;
570
571	datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
572				      GFP_KERNEL | GFP_DMA32);
573	if (!datavirt) {
574		err = -ENOMEM;
575		goto free_namebuf;
576	}
577
578	len = strlen(filename);
579	strncpy(namevirt, filename, namesize);
580
581	err = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
582			       &nbytes);
583
584	if (!err)
585		seq_write(m, datavirt, nbytes);
586
587	dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
588free_namebuf:
589	dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
590
591	return err;
592}
593
594static int debugfs_open(struct inode *inode, struct file *file)
595{
596	return single_open_size(file, debugfs_show, file, SZ_128K);
597}
598
599static ssize_t debugfs_store(struct file *file, const char __user *buf,
600		size_t count, loff_t *f_pos)
601{
602	struct inode *inode = file_inode(file);
603	struct tegra_bpmp *bpmp = inode->i_private;
604	const size_t datasize = count;
605	const size_t namesize = SZ_256;
606	void *datavirt, *namevirt;
607	dma_addr_t dataphys, namephys;
608	char fnamebuf[256];
609	const char *filename;
610	size_t len;
611	int err;
612
613	filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
614	if (!filename)
615		return -ENOENT;
616
617	namevirt = dma_alloc_coherent(bpmp->dev, namesize, &namephys,
618				      GFP_KERNEL | GFP_DMA32);
619	if (!namevirt)
620		return -ENOMEM;
621
622	datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
623				      GFP_KERNEL | GFP_DMA32);
624	if (!datavirt) {
625		err = -ENOMEM;
626		goto free_namebuf;
627	}
628
629	len = strlen(filename);
630	strncpy(namevirt, filename, namesize);
631
632	if (copy_from_user(datavirt, buf, count)) {
633		err = -EFAULT;
634		goto free_databuf;
635	}
636
637	err = mrq_debugfs_write(bpmp, namephys, len, dataphys,
638				count);
639
640free_databuf:
641	dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
642free_namebuf:
643	dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
644
645	return err ?: count;
646}
647
648static const struct file_operations debugfs_fops = {
649	.open		= debugfs_open,
650	.read		= seq_read,
651	.llseek		= seq_lseek,
652	.write		= debugfs_store,
653	.release	= single_release,
654};
655
656static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
657			     struct dentry *parent, uint32_t depth)
658{
659	int err;
660	uint32_t d, t;
661	const char *name;
662	struct dentry *dentry;
663
664	while (!seqbuf_eof(seqbuf)) {
665		err = seqbuf_read_u32(seqbuf, &d);
666		if (err < 0)
667			return err;
668
669		if (d < depth) {
670			seqbuf_seek(seqbuf, -4);
671			/* go up a level */
672			return 0;
673		} else if (d != depth) {
674			/* malformed data received from BPMP */
675			return -EIO;
676		}
677
678		err = seqbuf_read_u32(seqbuf, &t);
679		if (err < 0)
680			return err;
681		err = seqbuf_read_str(seqbuf, &name);
682		if (err < 0)
683			return err;
684
685		if (t & DEBUGFS_S_ISDIR) {
686			dentry = debugfs_create_dir(name, parent);
687			if (!dentry)
688				return -ENOMEM;
689			err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
690			if (err < 0)
691				return err;
692		} else {
693			umode_t mode;
694
695			mode = t & DEBUGFS_S_IRUSR ? S_IRUSR : 0;
696			mode |= t & DEBUGFS_S_IWUSR ? S_IWUSR : 0;
697			dentry = debugfs_create_file(name, mode,
698						     parent, bpmp,
699						     &debugfs_fops);
700			if (!dentry)
701				return -ENOMEM;
702		}
703	}
704
705	return 0;
706}
707
708static int bpmp_populate_debugfs_shmem(struct tegra_bpmp *bpmp)
709{
710	struct seqbuf seqbuf;
711	const size_t sz = SZ_512K;
712	dma_addr_t phys;
713	size_t nbytes;
714	void *virt;
715	int err;
716
717	virt = dma_alloc_coherent(bpmp->dev, sz, &phys,
718				  GFP_KERNEL | GFP_DMA32);
719	if (!virt)
720		return -ENOMEM;
721
722	err = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes);
723	if (err < 0) {
724		goto free;
725	} else if (nbytes > sz) {
726		err = -EINVAL;
727		goto free;
728	}
729
730	seqbuf_init(&seqbuf, virt, nbytes);
731	err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0);
732free:
733	dma_free_coherent(bpmp->dev, sz, virt, phys);
734
735	return err;
736}
737
738int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
739{
740	struct dentry *root;
741	bool inband;
742	int err;
743
744	inband = tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUG);
745
746	if (!inband && !tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
747		return 0;
748
749	root = debugfs_create_dir("bpmp", NULL);
750	if (!root)
751		return -ENOMEM;
752
753	bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
754	if (!bpmp->debugfs_mirror) {
755		err = -ENOMEM;
756		goto out;
757	}
758
759	if (inband)
760		err = bpmp_populate_debugfs_inband(bpmp, bpmp->debugfs_mirror,
761						   "/");
762	else
763		err = bpmp_populate_debugfs_shmem(bpmp);
764
765out:
766	if (err < 0)
767		debugfs_remove_recursive(root);
768
769	return err;
770}