Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / firmware / tegra / bpmp-debugfs.c
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 }