xref: /linux/drivers/firmware/tegra/bpmp-debugfs.c (revision 44f57d78)
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/uaccess.h>
8 
9 #include <soc/tegra/bpmp.h>
10 #include <soc/tegra/bpmp-abi.h>
11 
12 struct seqbuf {
13 	char *buf;
14 	size_t pos;
15 	size_t size;
16 };
17 
18 static void seqbuf_init(struct seqbuf *seqbuf, void *buf, size_t size)
19 {
20 	seqbuf->buf = buf;
21 	seqbuf->size = size;
22 	seqbuf->pos = 0;
23 }
24 
25 static size_t seqbuf_avail(struct seqbuf *seqbuf)
26 {
27 	return seqbuf->pos < seqbuf->size ? seqbuf->size - seqbuf->pos : 0;
28 }
29 
30 static size_t seqbuf_status(struct seqbuf *seqbuf)
31 {
32 	return seqbuf->pos <= seqbuf->size ? 0 : -EOVERFLOW;
33 }
34 
35 static int seqbuf_eof(struct seqbuf *seqbuf)
36 {
37 	return seqbuf->pos >= seqbuf->size;
38 }
39 
40 static int seqbuf_read(struct seqbuf *seqbuf, void *buf, size_t nbyte)
41 {
42 	nbyte = min(nbyte, seqbuf_avail(seqbuf));
43 	memcpy(buf, seqbuf->buf + seqbuf->pos, nbyte);
44 	seqbuf->pos += nbyte;
45 	return seqbuf_status(seqbuf);
46 }
47 
48 static int seqbuf_read_u32(struct seqbuf *seqbuf, uint32_t *v)
49 {
50 	int err;
51 
52 	err = seqbuf_read(seqbuf, v, 4);
53 	*v = le32_to_cpu(*v);
54 	return err;
55 }
56 
57 static int seqbuf_read_str(struct seqbuf *seqbuf, const char **str)
58 {
59 	*str = seqbuf->buf + seqbuf->pos;
60 	seqbuf->pos += strnlen(*str, seqbuf_avail(seqbuf));
61 	seqbuf->pos++;
62 	return seqbuf_status(seqbuf);
63 }
64 
65 static void seqbuf_seek(struct seqbuf *seqbuf, ssize_t offset)
66 {
67 	seqbuf->pos += offset;
68 }
69 
70 /* map filename in Linux debugfs to corresponding entry in BPMP */
71 static const char *get_filename(struct tegra_bpmp *bpmp,
72 				const struct file *file, char *buf, int size)
73 {
74 	char root_path_buf[512];
75 	const char *root_path;
76 	const char *filename;
77 	size_t root_len;
78 
79 	root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
80 				sizeof(root_path_buf));
81 	if (IS_ERR(root_path))
82 		return NULL;
83 
84 	root_len = strlen(root_path);
85 
86 	filename = dentry_path(file->f_path.dentry, buf, size);
87 	if (IS_ERR(filename))
88 		return NULL;
89 
90 	if (strlen(filename) < root_len ||
91 			strncmp(filename, root_path, root_len))
92 		return NULL;
93 
94 	filename += root_len;
95 
96 	return filename;
97 }
98 
99 static int mrq_debugfs_read(struct tegra_bpmp *bpmp,
100 			    dma_addr_t name, size_t sz_name,
101 			    dma_addr_t data, size_t sz_data,
102 			    size_t *nbytes)
103 {
104 	struct mrq_debugfs_request req = {
105 		.cmd = cpu_to_le32(CMD_DEBUGFS_READ),
106 		.fop = {
107 			.fnameaddr = cpu_to_le32((uint32_t)name),
108 			.fnamelen = cpu_to_le32((uint32_t)sz_name),
109 			.dataaddr = cpu_to_le32((uint32_t)data),
110 			.datalen = cpu_to_le32((uint32_t)sz_data),
111 		},
112 	};
113 	struct mrq_debugfs_response resp;
114 	struct tegra_bpmp_message msg = {
115 		.mrq = MRQ_DEBUGFS,
116 		.tx = {
117 			.data = &req,
118 			.size = sizeof(req),
119 		},
120 		.rx = {
121 			.data = &resp,
122 			.size = sizeof(resp),
123 		},
124 	};
125 	int err;
126 
127 	err = tegra_bpmp_transfer(bpmp, &msg);
128 	if (err < 0)
129 		return err;
130 
131 	*nbytes = (size_t)resp.fop.nbytes;
132 
133 	return 0;
134 }
135 
136 static int mrq_debugfs_write(struct tegra_bpmp *bpmp,
137 			     dma_addr_t name, size_t sz_name,
138 			     dma_addr_t data, size_t sz_data)
139 {
140 	const struct mrq_debugfs_request req = {
141 		.cmd = cpu_to_le32(CMD_DEBUGFS_WRITE),
142 		.fop = {
143 			.fnameaddr = cpu_to_le32((uint32_t)name),
144 			.fnamelen = cpu_to_le32((uint32_t)sz_name),
145 			.dataaddr = cpu_to_le32((uint32_t)data),
146 			.datalen = cpu_to_le32((uint32_t)sz_data),
147 		},
148 	};
149 	struct tegra_bpmp_message msg = {
150 		.mrq = MRQ_DEBUGFS,
151 		.tx = {
152 			.data = &req,
153 			.size = sizeof(req),
154 		},
155 	};
156 
157 	return tegra_bpmp_transfer(bpmp, &msg);
158 }
159 
160 static int mrq_debugfs_dumpdir(struct tegra_bpmp *bpmp, dma_addr_t addr,
161 			       size_t size, size_t *nbytes)
162 {
163 	const struct mrq_debugfs_request req = {
164 		.cmd = cpu_to_le32(CMD_DEBUGFS_DUMPDIR),
165 		.dumpdir = {
166 			.dataaddr = cpu_to_le32((uint32_t)addr),
167 			.datalen = cpu_to_le32((uint32_t)size),
168 		},
169 	};
170 	struct mrq_debugfs_response resp;
171 	struct tegra_bpmp_message msg = {
172 		.mrq = MRQ_DEBUGFS,
173 		.tx = {
174 			.data = &req,
175 			.size = sizeof(req),
176 		},
177 		.rx = {
178 			.data = &resp,
179 			.size = sizeof(resp),
180 		},
181 	};
182 	int err;
183 
184 	err = tegra_bpmp_transfer(bpmp, &msg);
185 	if (err < 0)
186 		return err;
187 
188 	*nbytes = (size_t)resp.dumpdir.nbytes;
189 
190 	return 0;
191 }
192 
193 static int debugfs_show(struct seq_file *m, void *p)
194 {
195 	struct file *file = m->private;
196 	struct inode *inode = file_inode(file);
197 	struct tegra_bpmp *bpmp = inode->i_private;
198 	const size_t datasize = m->size;
199 	const size_t namesize = SZ_256;
200 	void *datavirt, *namevirt;
201 	dma_addr_t dataphys, namephys;
202 	char buf[256];
203 	const char *filename;
204 	size_t len, nbytes;
205 	int ret;
206 
207 	filename = get_filename(bpmp, file, buf, sizeof(buf));
208 	if (!filename)
209 		return -ENOENT;
210 
211 	namevirt = dma_alloc_coherent(bpmp->dev, namesize, &namephys,
212 				      GFP_KERNEL | GFP_DMA32);
213 	if (!namevirt)
214 		return -ENOMEM;
215 
216 	datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
217 				      GFP_KERNEL | GFP_DMA32);
218 	if (!datavirt) {
219 		ret = -ENOMEM;
220 		goto free_namebuf;
221 	}
222 
223 	len = strlen(filename);
224 	strncpy(namevirt, filename, namesize);
225 
226 	ret = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
227 			       &nbytes);
228 
229 	if (!ret)
230 		seq_write(m, datavirt, nbytes);
231 
232 	dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
233 free_namebuf:
234 	dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
235 
236 	return ret;
237 }
238 
239 static int debugfs_open(struct inode *inode, struct file *file)
240 {
241 	return single_open_size(file, debugfs_show, file, SZ_128K);
242 }
243 
244 static ssize_t debugfs_store(struct file *file, const char __user *buf,
245 		size_t count, loff_t *f_pos)
246 {
247 	struct inode *inode = file_inode(file);
248 	struct tegra_bpmp *bpmp = inode->i_private;
249 	const size_t datasize = count;
250 	const size_t namesize = SZ_256;
251 	void *datavirt, *namevirt;
252 	dma_addr_t dataphys, namephys;
253 	char fnamebuf[256];
254 	const char *filename;
255 	size_t len;
256 	int ret;
257 
258 	filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
259 	if (!filename)
260 		return -ENOENT;
261 
262 	namevirt = dma_alloc_coherent(bpmp->dev, namesize, &namephys,
263 				      GFP_KERNEL | GFP_DMA32);
264 	if (!namevirt)
265 		return -ENOMEM;
266 
267 	datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
268 				      GFP_KERNEL | GFP_DMA32);
269 	if (!datavirt) {
270 		ret = -ENOMEM;
271 		goto free_namebuf;
272 	}
273 
274 	len = strlen(filename);
275 	strncpy(namevirt, filename, namesize);
276 
277 	if (copy_from_user(datavirt, buf, count)) {
278 		ret = -EFAULT;
279 		goto free_databuf;
280 	}
281 
282 	ret = mrq_debugfs_write(bpmp, namephys, len, dataphys,
283 				count);
284 
285 free_databuf:
286 	dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
287 free_namebuf:
288 	dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
289 
290 	return ret ?: count;
291 }
292 
293 static const struct file_operations debugfs_fops = {
294 	.open		= debugfs_open,
295 	.read		= seq_read,
296 	.llseek		= seq_lseek,
297 	.write		= debugfs_store,
298 	.release	= single_release,
299 };
300 
301 static int bpmp_populate_dir(struct tegra_bpmp *bpmp, struct seqbuf *seqbuf,
302 			     struct dentry *parent, uint32_t depth)
303 {
304 	int err;
305 	uint32_t d, t;
306 	const char *name;
307 	struct dentry *dentry;
308 
309 	while (!seqbuf_eof(seqbuf)) {
310 		err = seqbuf_read_u32(seqbuf, &d);
311 		if (err < 0)
312 			return err;
313 
314 		if (d < depth) {
315 			seqbuf_seek(seqbuf, -4);
316 			/* go up a level */
317 			return 0;
318 		} else if (d != depth) {
319 			/* malformed data received from BPMP */
320 			return -EIO;
321 		}
322 
323 		err = seqbuf_read_u32(seqbuf, &t);
324 		if (err < 0)
325 			return err;
326 		err = seqbuf_read_str(seqbuf, &name);
327 		if (err < 0)
328 			return err;
329 
330 		if (t & DEBUGFS_S_ISDIR) {
331 			dentry = debugfs_create_dir(name, parent);
332 			if (!dentry)
333 				return -ENOMEM;
334 			err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
335 			if (err < 0)
336 				return err;
337 		} else {
338 			umode_t mode;
339 
340 			mode = t & DEBUGFS_S_IRUSR ? S_IRUSR : 0;
341 			mode |= t & DEBUGFS_S_IWUSR ? S_IWUSR : 0;
342 			dentry = debugfs_create_file(name, mode,
343 						     parent, bpmp,
344 						     &debugfs_fops);
345 			if (!dentry)
346 				return -ENOMEM;
347 		}
348 	}
349 
350 	return 0;
351 }
352 
353 static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf,
354 				 size_t bufsize, struct dentry *root)
355 {
356 	struct seqbuf seqbuf;
357 	int err;
358 
359 	bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
360 	if (!bpmp->debugfs_mirror)
361 		return -ENOMEM;
362 
363 	seqbuf_init(&seqbuf, buf, bufsize);
364 	err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0);
365 	if (err < 0) {
366 		debugfs_remove_recursive(bpmp->debugfs_mirror);
367 		bpmp->debugfs_mirror = NULL;
368 	}
369 
370 	return err;
371 }
372 
373 int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
374 {
375 	dma_addr_t phys;
376 	void *virt;
377 	const size_t sz = SZ_256K;
378 	size_t nbytes;
379 	int ret;
380 	struct dentry *root;
381 
382 	if (!tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
383 		return 0;
384 
385 	root = debugfs_create_dir("bpmp", NULL);
386 	if (!root)
387 		return -ENOMEM;
388 
389 	virt = dma_alloc_coherent(bpmp->dev, sz, &phys,
390 				  GFP_KERNEL | GFP_DMA32);
391 	if (!virt) {
392 		ret = -ENOMEM;
393 		goto out;
394 	}
395 
396 	ret = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes);
397 	if (ret < 0)
398 		goto free;
399 
400 	ret = create_debugfs_mirror(bpmp, virt, nbytes, root);
401 free:
402 	dma_free_coherent(bpmp->dev, sz, virt, phys);
403 out:
404 	if (ret < 0)
405 		debugfs_remove(root);
406 
407 	return ret;
408 }
409