Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/tegra/bpmp-debugfs.c
26428 views
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
13
static DEFINE_MUTEX(bpmp_debug_lock);
14
15
struct seqbuf {
16
char *buf;
17
size_t pos;
18
size_t size;
19
};
20
21
static 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
28
static size_t seqbuf_avail(struct seqbuf *seqbuf)
29
{
30
return seqbuf->pos < seqbuf->size ? seqbuf->size - seqbuf->pos : 0;
31
}
32
33
static size_t seqbuf_status(struct seqbuf *seqbuf)
34
{
35
return seqbuf->pos <= seqbuf->size ? 0 : -EOVERFLOW;
36
}
37
38
static int seqbuf_eof(struct seqbuf *seqbuf)
39
{
40
return seqbuf->pos >= seqbuf->size;
41
}
42
43
static 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
51
static int seqbuf_read_u32(struct seqbuf *seqbuf, u32 *v)
52
{
53
return seqbuf_read(seqbuf, v, 4);
54
}
55
56
static 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
64
static 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 */
70
static 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
102
out:
103
kfree(root_path_buf);
104
return filename;
105
}
106
107
static 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
146
static 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
177
static 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
233
close:
234
close_err = mrq_debug_close(bpmp, fd);
235
if (!err)
236
err = close_err;
237
out:
238
mutex_unlock(&bpmp_debug_lock);
239
return err;
240
}
241
242
static 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
294
close:
295
err = mrq_debug_close(bpmp, fd);
296
out:
297
mutex_unlock(&bpmp_debug_lock);
298
return err;
299
}
300
301
static 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
357
close:
358
close_err = mrq_debug_close(bpmp, fd);
359
if (!err)
360
err = close_err;
361
out:
362
mutex_unlock(&bpmp_debug_lock);
363
return err;
364
}
365
366
static 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
390
static 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
395
static 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
403
static 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
477
out:
478
kfree(pathbuf);
479
kfree(buf);
480
481
return err;
482
}
483
484
static 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
523
static 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
547
static 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
582
static 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);
622
free_namebuf:
623
dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
624
625
return err;
626
}
627
628
static int debugfs_open(struct inode *inode, struct file *file)
629
{
630
return single_open_size(file, debugfs_show, file, SZ_128K);
631
}
632
633
static 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
674
free_databuf:
675
dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
676
free_namebuf:
677
dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
678
679
return err ?: count;
680
}
681
682
static 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
690
static 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
742
static 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);
766
free:
767
dma_free_coherent(bpmp->dev, sz, virt, phys);
768
769
return err;
770
}
771
772
int 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
799
out:
800
if (err < 0)
801
debugfs_remove_recursive(root);
802
803
return err;
804
}
805
806