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