forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-09 b22da3d8526a935aa31e086e63f60ff3246cb61c
kernel/drivers/firmware/tegra/bpmp-debugfs.c
....@@ -1,22 +1,16 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
3
- *
4
- * This program is free software; you can redistribute it and/or modify it
5
- * under the terms and conditions of the GNU General Public License,
6
- * version 2, as published by the Free Software Foundation.
7
- *
8
- * This program is distributed in the hope it will be useful, but WITHOUT
9
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
- * more details.
12
- *
134 */
145 #include <linux/debugfs.h>
156 #include <linux/dma-mapping.h>
7
+#include <linux/slab.h>
168 #include <linux/uaccess.h>
179
1810 #include <soc/tegra/bpmp.h>
1911 #include <soc/tegra/bpmp-abi.h>
12
+
13
+static DEFINE_MUTEX(bpmp_debug_lock);
2014
2115 struct seqbuf {
2216 char *buf;
....@@ -80,29 +74,381 @@
8074 static const char *get_filename(struct tegra_bpmp *bpmp,
8175 const struct file *file, char *buf, int size)
8276 {
83
- char root_path_buf[512];
84
- const char *root_path;
85
- const char *filename;
77
+ const char *root_path, *filename = NULL;
78
+ char *root_path_buf;
8679 size_t root_len;
80
+
81
+ root_path_buf = kzalloc(512, GFP_KERNEL);
82
+ if (!root_path_buf)
83
+ goto out;
8784
8885 root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
8986 sizeof(root_path_buf));
9087 if (IS_ERR(root_path))
91
- return NULL;
88
+ goto out;
9289
9390 root_len = strlen(root_path);
9491
9592 filename = dentry_path(file->f_path.dentry, buf, size);
96
- if (IS_ERR(filename))
97
- return NULL;
93
+ if (IS_ERR(filename)) {
94
+ filename = NULL;
95
+ goto out;
96
+ }
9897
99
- if (strlen(filename) < root_len ||
100
- strncmp(filename, root_path, root_len))
101
- return NULL;
98
+ if (strlen(filename) < root_len || strncmp(filename, root_path, root_len)) {
99
+ filename = NULL;
100
+ goto out;
101
+ }
102102
103103 filename += root_len;
104104
105
+out:
106
+ kfree(root_path_buf);
105107 return filename;
108
+}
109
+
110
+static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
111
+ uint32_t *fd, uint32_t *len, bool write)
112
+{
113
+ struct mrq_debug_request req = {
114
+ .cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO),
115
+ };
116
+ struct mrq_debug_response resp;
117
+ struct tegra_bpmp_message msg = {
118
+ .mrq = MRQ_DEBUG,
119
+ .tx = {
120
+ .data = &req,
121
+ .size = sizeof(req),
122
+ },
123
+ .rx = {
124
+ .data = &resp,
125
+ .size = sizeof(resp),
126
+ },
127
+ };
128
+ ssize_t sz_name;
129
+ int err = 0;
130
+
131
+ sz_name = strscpy(req.fop.name, name, sizeof(req.fop.name));
132
+ if (sz_name < 0) {
133
+ pr_err("File name too large: %s\n", name);
134
+ return -EINVAL;
135
+ }
136
+
137
+ err = tegra_bpmp_transfer(bpmp, &msg);
138
+ if (err < 0)
139
+ return err;
140
+ else if (msg.rx.ret < 0)
141
+ return -EINVAL;
142
+
143
+ *len = resp.fop.datalen;
144
+ *fd = resp.fop.fd;
145
+
146
+ return 0;
147
+}
148
+
149
+static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
150
+{
151
+ struct mrq_debug_request req = {
152
+ .cmd = cpu_to_le32(CMD_DEBUG_CLOSE),
153
+ .frd = {
154
+ .fd = fd,
155
+ },
156
+ };
157
+ struct mrq_debug_response resp;
158
+ struct tegra_bpmp_message msg = {
159
+ .mrq = MRQ_DEBUG,
160
+ .tx = {
161
+ .data = &req,
162
+ .size = sizeof(req),
163
+ },
164
+ .rx = {
165
+ .data = &resp,
166
+ .size = sizeof(resp),
167
+ },
168
+ };
169
+ int err = 0;
170
+
171
+ err = tegra_bpmp_transfer(bpmp, &msg);
172
+ if (err < 0)
173
+ return err;
174
+ else if (msg.rx.ret < 0)
175
+ return -EINVAL;
176
+
177
+ return 0;
178
+}
179
+
180
+static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
181
+ char *data, size_t sz_data, uint32_t *nbytes)
182
+{
183
+ struct mrq_debug_request req = {
184
+ .cmd = cpu_to_le32(CMD_DEBUG_READ),
185
+ };
186
+ struct mrq_debug_response resp;
187
+ struct tegra_bpmp_message msg = {
188
+ .mrq = MRQ_DEBUG,
189
+ .tx = {
190
+ .data = &req,
191
+ .size = sizeof(req),
192
+ },
193
+ .rx = {
194
+ .data = &resp,
195
+ .size = sizeof(resp),
196
+ },
197
+ };
198
+ uint32_t fd = 0, len = 0;
199
+ int remaining, err;
200
+
201
+ mutex_lock(&bpmp_debug_lock);
202
+ err = mrq_debug_open(bpmp, name, &fd, &len, 0);
203
+ if (err)
204
+ goto out;
205
+
206
+ if (len > sz_data) {
207
+ err = -EFBIG;
208
+ goto close;
209
+ }
210
+
211
+ req.frd.fd = fd;
212
+ remaining = len;
213
+
214
+ while (remaining > 0) {
215
+ err = tegra_bpmp_transfer(bpmp, &msg);
216
+ if (err < 0) {
217
+ goto close;
218
+ } else if (msg.rx.ret < 0) {
219
+ err = -EINVAL;
220
+ goto close;
221
+ }
222
+
223
+ if (resp.frd.readlen > remaining) {
224
+ pr_err("%s: read data length invalid\n", __func__);
225
+ err = -EINVAL;
226
+ goto close;
227
+ }
228
+
229
+ memcpy(data, resp.frd.data, resp.frd.readlen);
230
+ data += resp.frd.readlen;
231
+ remaining -= resp.frd.readlen;
232
+ }
233
+
234
+ *nbytes = len;
235
+
236
+close:
237
+ err = mrq_debug_close(bpmp, fd);
238
+out:
239
+ mutex_unlock(&bpmp_debug_lock);
240
+ return err;
241
+}
242
+
243
+static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
244
+ uint8_t *data, size_t sz_data)
245
+{
246
+ struct mrq_debug_request req = {
247
+ .cmd = cpu_to_le32(CMD_DEBUG_WRITE)
248
+ };
249
+ struct mrq_debug_response resp;
250
+ struct tegra_bpmp_message msg = {
251
+ .mrq = MRQ_DEBUG,
252
+ .tx = {
253
+ .data = &req,
254
+ .size = sizeof(req),
255
+ },
256
+ .rx = {
257
+ .data = &resp,
258
+ .size = sizeof(resp),
259
+ },
260
+ };
261
+ uint32_t fd = 0, len = 0;
262
+ size_t remaining;
263
+ int err;
264
+
265
+ mutex_lock(&bpmp_debug_lock);
266
+ err = mrq_debug_open(bpmp, name, &fd, &len, 1);
267
+ if (err)
268
+ goto out;
269
+
270
+ if (sz_data > len) {
271
+ err = -EINVAL;
272
+ goto close;
273
+ }
274
+
275
+ req.fwr.fd = fd;
276
+ remaining = sz_data;
277
+
278
+ while (remaining > 0) {
279
+ len = min(remaining, sizeof(req.fwr.data));
280
+ memcpy(req.fwr.data, data, len);
281
+ req.fwr.datalen = len;
282
+
283
+ err = tegra_bpmp_transfer(bpmp, &msg);
284
+ if (err < 0) {
285
+ goto close;
286
+ } else if (msg.rx.ret < 0) {
287
+ err = -EINVAL;
288
+ goto close;
289
+ }
290
+
291
+ data += req.fwr.datalen;
292
+ remaining -= req.fwr.datalen;
293
+ }
294
+
295
+close:
296
+ err = mrq_debug_close(bpmp, fd);
297
+out:
298
+ mutex_unlock(&bpmp_debug_lock);
299
+ return err;
300
+}
301
+
302
+static int bpmp_debug_show(struct seq_file *m, void *p)
303
+{
304
+ struct file *file = m->private;
305
+ struct inode *inode = file_inode(file);
306
+ struct tegra_bpmp *bpmp = inode->i_private;
307
+ char *databuf = NULL;
308
+ char fnamebuf[256];
309
+ const char *filename;
310
+ uint32_t nbytes = 0;
311
+ size_t len;
312
+ int err;
313
+
314
+ len = seq_get_buf(m, &databuf);
315
+ if (!databuf)
316
+ return -ENOMEM;
317
+
318
+ filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
319
+ if (!filename)
320
+ return -ENOENT;
321
+
322
+ err = mrq_debug_read(bpmp, filename, databuf, len, &nbytes);
323
+ if (!err)
324
+ seq_commit(m, nbytes);
325
+
326
+ return err;
327
+}
328
+
329
+static ssize_t bpmp_debug_store(struct file *file, const char __user *buf,
330
+ size_t count, loff_t *f_pos)
331
+{
332
+ struct inode *inode = file_inode(file);
333
+ struct tegra_bpmp *bpmp = inode->i_private;
334
+ char *databuf = NULL;
335
+ char fnamebuf[256];
336
+ const char *filename;
337
+ ssize_t err;
338
+
339
+ filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
340
+ if (!filename)
341
+ return -ENOENT;
342
+
343
+ databuf = kmalloc(count, GFP_KERNEL);
344
+ if (!databuf)
345
+ return -ENOMEM;
346
+
347
+ if (copy_from_user(databuf, buf, count)) {
348
+ err = -EFAULT;
349
+ goto free_ret;
350
+ }
351
+
352
+ err = mrq_debug_write(bpmp, filename, databuf, count);
353
+
354
+free_ret:
355
+ kfree(databuf);
356
+
357
+ return err ?: count;
358
+}
359
+
360
+static int bpmp_debug_open(struct inode *inode, struct file *file)
361
+{
362
+ return single_open_size(file, bpmp_debug_show, file, SZ_256K);
363
+}
364
+
365
+static const struct file_operations bpmp_debug_fops = {
366
+ .open = bpmp_debug_open,
367
+ .read = seq_read,
368
+ .llseek = seq_lseek,
369
+ .write = bpmp_debug_store,
370
+ .release = single_release,
371
+};
372
+
373
+static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
374
+ struct dentry *parent,
375
+ char *ppath)
376
+{
377
+ const size_t pathlen = SZ_256;
378
+ const size_t bufsize = SZ_16K;
379
+ uint32_t dsize, attrs = 0;
380
+ struct dentry *dentry;
381
+ struct seqbuf seqbuf;
382
+ char *buf, *pathbuf;
383
+ const char *name;
384
+ int err = 0;
385
+
386
+ if (!bpmp || !parent || !ppath)
387
+ return -EINVAL;
388
+
389
+ buf = kmalloc(bufsize, GFP_KERNEL);
390
+ if (!buf)
391
+ return -ENOMEM;
392
+
393
+ pathbuf = kzalloc(pathlen, GFP_KERNEL);
394
+ if (!pathbuf) {
395
+ kfree(buf);
396
+ return -ENOMEM;
397
+ }
398
+
399
+ err = mrq_debug_read(bpmp, ppath, buf, bufsize, &dsize);
400
+ if (err)
401
+ goto out;
402
+
403
+ seqbuf_init(&seqbuf, buf, dsize);
404
+
405
+ while (!seqbuf_eof(&seqbuf)) {
406
+ err = seqbuf_read_u32(&seqbuf, &attrs);
407
+ if (err)
408
+ goto out;
409
+
410
+ err = seqbuf_read_str(&seqbuf, &name);
411
+ if (err < 0)
412
+ goto out;
413
+
414
+ if (attrs & DEBUGFS_S_ISDIR) {
415
+ size_t len;
416
+
417
+ dentry = debugfs_create_dir(name, parent);
418
+ if (IS_ERR(dentry)) {
419
+ err = PTR_ERR(dentry);
420
+ goto out;
421
+ }
422
+
423
+ len = snprintf(pathbuf, pathlen, "%s%s/", ppath, name);
424
+ if (len >= pathlen) {
425
+ err = -EINVAL;
426
+ goto out;
427
+ }
428
+
429
+ err = bpmp_populate_debugfs_inband(bpmp, dentry,
430
+ pathbuf);
431
+ if (err < 0)
432
+ goto out;
433
+ } else {
434
+ umode_t mode;
435
+
436
+ mode = attrs & DEBUGFS_S_IRUSR ? 0400 : 0;
437
+ mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0;
438
+ dentry = debugfs_create_file(name, mode, parent, bpmp,
439
+ &bpmp_debug_fops);
440
+ if (IS_ERR(dentry)) {
441
+ err = -ENOMEM;
442
+ goto out;
443
+ }
444
+ }
445
+ }
446
+
447
+out:
448
+ kfree(pathbuf);
449
+ kfree(buf);
450
+
451
+ return err;
106452 }
107453
108454 static int mrq_debugfs_read(struct tegra_bpmp *bpmp,
....@@ -136,6 +482,8 @@
136482 err = tegra_bpmp_transfer(bpmp, &msg);
137483 if (err < 0)
138484 return err;
485
+ else if (msg.rx.ret < 0)
486
+ return -EINVAL;
139487
140488 *nbytes = (size_t)resp.fop.nbytes;
141489
....@@ -193,6 +541,8 @@
193541 err = tegra_bpmp_transfer(bpmp, &msg);
194542 if (err < 0)
195543 return err;
544
+ else if (msg.rx.ret < 0)
545
+ return -EINVAL;
196546
197547 *nbytes = (size_t)resp.dumpdir.nbytes;
198548
....@@ -211,7 +561,7 @@
211561 char buf[256];
212562 const char *filename;
213563 size_t len, nbytes;
214
- int ret;
564
+ int err;
215565
216566 filename = get_filename(bpmp, file, buf, sizeof(buf));
217567 if (!filename)
....@@ -225,24 +575,24 @@
225575 datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
226576 GFP_KERNEL | GFP_DMA32);
227577 if (!datavirt) {
228
- ret = -ENOMEM;
578
+ err = -ENOMEM;
229579 goto free_namebuf;
230580 }
231581
232582 len = strlen(filename);
233583 strncpy(namevirt, filename, namesize);
234584
235
- ret = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
585
+ err = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
236586 &nbytes);
237587
238
- if (!ret)
588
+ if (!err)
239589 seq_write(m, datavirt, nbytes);
240590
241591 dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
242592 free_namebuf:
243593 dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
244594
245
- return ret;
595
+ return err;
246596 }
247597
248598 static int debugfs_open(struct inode *inode, struct file *file)
....@@ -262,7 +612,7 @@
262612 char fnamebuf[256];
263613 const char *filename;
264614 size_t len;
265
- int ret;
615
+ int err;
266616
267617 filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
268618 if (!filename)
....@@ -276,7 +626,7 @@
276626 datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
277627 GFP_KERNEL | GFP_DMA32);
278628 if (!datavirt) {
279
- ret = -ENOMEM;
629
+ err = -ENOMEM;
280630 goto free_namebuf;
281631 }
282632
....@@ -284,11 +634,11 @@
284634 strncpy(namevirt, filename, namesize);
285635
286636 if (copy_from_user(datavirt, buf, count)) {
287
- ret = -EFAULT;
637
+ err = -EFAULT;
288638 goto free_databuf;
289639 }
290640
291
- ret = mrq_debugfs_write(bpmp, namephys, len, dataphys,
641
+ err = mrq_debugfs_write(bpmp, namephys, len, dataphys,
292642 count);
293643
294644 free_databuf:
....@@ -296,7 +646,7 @@
296646 free_namebuf:
297647 dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
298648
299
- return ret ?: count;
649
+ return err ?: count;
300650 }
301651
302652 static const struct file_operations debugfs_fops = {
....@@ -338,7 +688,7 @@
338688
339689 if (t & DEBUGFS_S_ISDIR) {
340690 dentry = debugfs_create_dir(name, parent);
341
- if (!dentry)
691
+ if (IS_ERR(dentry))
342692 return -ENOMEM;
343693 err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
344694 if (err < 0)
....@@ -351,7 +701,7 @@
351701 dentry = debugfs_create_file(name, mode,
352702 parent, bpmp,
353703 &debugfs_fops);
354
- if (!dentry)
704
+ if (IS_ERR(dentry))
355705 return -ENOMEM;
356706 }
357707 }
....@@ -359,86 +709,66 @@
359709 return 0;
360710 }
361711
362
-static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf,
363
- size_t bufsize, struct dentry *root)
712
+static int bpmp_populate_debugfs_shmem(struct tegra_bpmp *bpmp)
364713 {
365714 struct seqbuf seqbuf;
715
+ const size_t sz = SZ_512K;
716
+ dma_addr_t phys;
717
+ size_t nbytes;
718
+ void *virt;
366719 int err;
367720
368
- bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
369
- if (!bpmp->debugfs_mirror)
721
+ virt = dma_alloc_coherent(bpmp->dev, sz, &phys,
722
+ GFP_KERNEL | GFP_DMA32);
723
+ if (!virt)
370724 return -ENOMEM;
371725
372
- seqbuf_init(&seqbuf, buf, bufsize);
373
- err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0);
726
+ err = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes);
374727 if (err < 0) {
375
- debugfs_remove_recursive(bpmp->debugfs_mirror);
376
- bpmp->debugfs_mirror = NULL;
728
+ goto free;
729
+ } else if (nbytes > sz) {
730
+ err = -EINVAL;
731
+ goto free;
377732 }
733
+
734
+ seqbuf_init(&seqbuf, virt, nbytes);
735
+ err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0);
736
+free:
737
+ dma_free_coherent(bpmp->dev, sz, virt, phys);
378738
379739 return err;
380740 }
381741
382
-static int mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq)
383
-{
384
- struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) };
385
- struct mrq_query_abi_response resp;
386
- struct tegra_bpmp_message msg = {
387
- .mrq = MRQ_QUERY_ABI,
388
- .tx = {
389
- .data = &req,
390
- .size = sizeof(req),
391
- },
392
- .rx = {
393
- .data = &resp,
394
- .size = sizeof(resp),
395
- },
396
- };
397
- int ret;
398
-
399
- ret = tegra_bpmp_transfer(bpmp, &msg);
400
- if (ret < 0) {
401
- /* something went wrong; assume not supported */
402
- dev_warn(bpmp->dev, "tegra_bpmp_transfer failed (%d)\n", ret);
403
- return 0;
404
- }
405
-
406
- return resp.status ? 0 : 1;
407
-}
408
-
409742 int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
410743 {
411
- dma_addr_t phys;
412
- void *virt;
413
- const size_t sz = SZ_256K;
414
- size_t nbytes;
415
- int ret;
416744 struct dentry *root;
745
+ bool inband;
746
+ int err;
417747
418
- if (!mrq_is_supported(bpmp, MRQ_DEBUGFS))
748
+ inband = tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUG);
749
+
750
+ if (!inband && !tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
419751 return 0;
420752
421753 root = debugfs_create_dir("bpmp", NULL);
422
- if (!root)
754
+ if (IS_ERR(root))
423755 return -ENOMEM;
424756
425
- virt = dma_alloc_coherent(bpmp->dev, sz, &phys,
426
- GFP_KERNEL | GFP_DMA32);
427
- if (!virt) {
428
- ret = -ENOMEM;
757
+ bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
758
+ if (IS_ERR(bpmp->debugfs_mirror)) {
759
+ err = -ENOMEM;
429760 goto out;
430761 }
431762
432
- ret = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes);
433
- if (ret < 0)
434
- goto free;
763
+ if (inband)
764
+ err = bpmp_populate_debugfs_inband(bpmp, bpmp->debugfs_mirror,
765
+ "/");
766
+ else
767
+ err = bpmp_populate_debugfs_shmem(bpmp);
435768
436
- ret = create_debugfs_mirror(bpmp, virt, nbytes, root);
437
-free:
438
- dma_free_coherent(bpmp->dev, sz, virt, phys);
439769 out:
440
- if (ret < 0)
441
- debugfs_remove(root);
770
+ if (err < 0)
771
+ debugfs_remove_recursive(root);
442772
443
- return ret;
773
+ return err;
444774 }