forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
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,382 @@
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
+ size_t root_path_buf_len = 512;
81
+
82
+ root_path_buf = kzalloc(root_path_buf_len, GFP_KERNEL);
83
+ if (!root_path_buf)
84
+ goto out;
8785
8886 root_path = dentry_path(bpmp->debugfs_mirror, root_path_buf,
89
- sizeof(root_path_buf));
87
+ root_path_buf_len);
9088 if (IS_ERR(root_path))
91
- return NULL;
89
+ goto out;
9290
9391 root_len = strlen(root_path);
9492
9593 filename = dentry_path(file->f_path.dentry, buf, size);
96
- if (IS_ERR(filename))
97
- return NULL;
94
+ if (IS_ERR(filename)) {
95
+ filename = NULL;
96
+ goto out;
97
+ }
9898
99
- if (strlen(filename) < root_len ||
100
- strncmp(filename, root_path, root_len))
101
- return NULL;
99
+ if (strlen(filename) < root_len || strncmp(filename, root_path, root_len)) {
100
+ filename = NULL;
101
+ goto out;
102
+ }
102103
103104 filename += root_len;
104105
106
+out:
107
+ kfree(root_path_buf);
105108 return filename;
109
+}
110
+
111
+static int mrq_debug_open(struct tegra_bpmp *bpmp, const char *name,
112
+ uint32_t *fd, uint32_t *len, bool write)
113
+{
114
+ struct mrq_debug_request req = {
115
+ .cmd = cpu_to_le32(write ? CMD_DEBUG_OPEN_WO : CMD_DEBUG_OPEN_RO),
116
+ };
117
+ struct mrq_debug_response resp;
118
+ struct tegra_bpmp_message msg = {
119
+ .mrq = MRQ_DEBUG,
120
+ .tx = {
121
+ .data = &req,
122
+ .size = sizeof(req),
123
+ },
124
+ .rx = {
125
+ .data = &resp,
126
+ .size = sizeof(resp),
127
+ },
128
+ };
129
+ ssize_t sz_name;
130
+ int err = 0;
131
+
132
+ sz_name = strscpy(req.fop.name, name, sizeof(req.fop.name));
133
+ if (sz_name < 0) {
134
+ pr_err("File name too large: %s\n", name);
135
+ return -EINVAL;
136
+ }
137
+
138
+ err = tegra_bpmp_transfer(bpmp, &msg);
139
+ if (err < 0)
140
+ return err;
141
+ else if (msg.rx.ret < 0)
142
+ return -EINVAL;
143
+
144
+ *len = resp.fop.datalen;
145
+ *fd = resp.fop.fd;
146
+
147
+ return 0;
148
+}
149
+
150
+static int mrq_debug_close(struct tegra_bpmp *bpmp, uint32_t fd)
151
+{
152
+ struct mrq_debug_request req = {
153
+ .cmd = cpu_to_le32(CMD_DEBUG_CLOSE),
154
+ .frd = {
155
+ .fd = fd,
156
+ },
157
+ };
158
+ struct mrq_debug_response resp;
159
+ struct tegra_bpmp_message msg = {
160
+ .mrq = MRQ_DEBUG,
161
+ .tx = {
162
+ .data = &req,
163
+ .size = sizeof(req),
164
+ },
165
+ .rx = {
166
+ .data = &resp,
167
+ .size = sizeof(resp),
168
+ },
169
+ };
170
+ int err = 0;
171
+
172
+ err = tegra_bpmp_transfer(bpmp, &msg);
173
+ if (err < 0)
174
+ return err;
175
+ else if (msg.rx.ret < 0)
176
+ return -EINVAL;
177
+
178
+ return 0;
179
+}
180
+
181
+static int mrq_debug_read(struct tegra_bpmp *bpmp, const char *name,
182
+ char *data, size_t sz_data, uint32_t *nbytes)
183
+{
184
+ struct mrq_debug_request req = {
185
+ .cmd = cpu_to_le32(CMD_DEBUG_READ),
186
+ };
187
+ struct mrq_debug_response resp;
188
+ struct tegra_bpmp_message msg = {
189
+ .mrq = MRQ_DEBUG,
190
+ .tx = {
191
+ .data = &req,
192
+ .size = sizeof(req),
193
+ },
194
+ .rx = {
195
+ .data = &resp,
196
+ .size = sizeof(resp),
197
+ },
198
+ };
199
+ uint32_t fd = 0, len = 0;
200
+ int remaining, err;
201
+
202
+ mutex_lock(&bpmp_debug_lock);
203
+ err = mrq_debug_open(bpmp, name, &fd, &len, 0);
204
+ if (err)
205
+ goto out;
206
+
207
+ if (len > sz_data) {
208
+ err = -EFBIG;
209
+ goto close;
210
+ }
211
+
212
+ req.frd.fd = fd;
213
+ remaining = len;
214
+
215
+ while (remaining > 0) {
216
+ err = tegra_bpmp_transfer(bpmp, &msg);
217
+ if (err < 0) {
218
+ goto close;
219
+ } else if (msg.rx.ret < 0) {
220
+ err = -EINVAL;
221
+ goto close;
222
+ }
223
+
224
+ if (resp.frd.readlen > remaining) {
225
+ pr_err("%s: read data length invalid\n", __func__);
226
+ err = -EINVAL;
227
+ goto close;
228
+ }
229
+
230
+ memcpy(data, resp.frd.data, resp.frd.readlen);
231
+ data += resp.frd.readlen;
232
+ remaining -= resp.frd.readlen;
233
+ }
234
+
235
+ *nbytes = len;
236
+
237
+close:
238
+ err = mrq_debug_close(bpmp, fd);
239
+out:
240
+ mutex_unlock(&bpmp_debug_lock);
241
+ return err;
242
+}
243
+
244
+static int mrq_debug_write(struct tegra_bpmp *bpmp, const char *name,
245
+ uint8_t *data, size_t sz_data)
246
+{
247
+ struct mrq_debug_request req = {
248
+ .cmd = cpu_to_le32(CMD_DEBUG_WRITE)
249
+ };
250
+ struct mrq_debug_response resp;
251
+ struct tegra_bpmp_message msg = {
252
+ .mrq = MRQ_DEBUG,
253
+ .tx = {
254
+ .data = &req,
255
+ .size = sizeof(req),
256
+ },
257
+ .rx = {
258
+ .data = &resp,
259
+ .size = sizeof(resp),
260
+ },
261
+ };
262
+ uint32_t fd = 0, len = 0;
263
+ size_t remaining;
264
+ int err;
265
+
266
+ mutex_lock(&bpmp_debug_lock);
267
+ err = mrq_debug_open(bpmp, name, &fd, &len, 1);
268
+ if (err)
269
+ goto out;
270
+
271
+ if (sz_data > len) {
272
+ err = -EINVAL;
273
+ goto close;
274
+ }
275
+
276
+ req.fwr.fd = fd;
277
+ remaining = sz_data;
278
+
279
+ while (remaining > 0) {
280
+ len = min(remaining, sizeof(req.fwr.data));
281
+ memcpy(req.fwr.data, data, len);
282
+ req.fwr.datalen = len;
283
+
284
+ err = tegra_bpmp_transfer(bpmp, &msg);
285
+ if (err < 0) {
286
+ goto close;
287
+ } else if (msg.rx.ret < 0) {
288
+ err = -EINVAL;
289
+ goto close;
290
+ }
291
+
292
+ data += req.fwr.datalen;
293
+ remaining -= req.fwr.datalen;
294
+ }
295
+
296
+close:
297
+ err = mrq_debug_close(bpmp, fd);
298
+out:
299
+ mutex_unlock(&bpmp_debug_lock);
300
+ return err;
301
+}
302
+
303
+static int bpmp_debug_show(struct seq_file *m, void *p)
304
+{
305
+ struct file *file = m->private;
306
+ struct inode *inode = file_inode(file);
307
+ struct tegra_bpmp *bpmp = inode->i_private;
308
+ char *databuf = NULL;
309
+ char fnamebuf[256];
310
+ const char *filename;
311
+ uint32_t nbytes = 0;
312
+ size_t len;
313
+ int err;
314
+
315
+ len = seq_get_buf(m, &databuf);
316
+ if (!databuf)
317
+ return -ENOMEM;
318
+
319
+ filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
320
+ if (!filename)
321
+ return -ENOENT;
322
+
323
+ err = mrq_debug_read(bpmp, filename, databuf, len, &nbytes);
324
+ if (!err)
325
+ seq_commit(m, nbytes);
326
+
327
+ return err;
328
+}
329
+
330
+static ssize_t bpmp_debug_store(struct file *file, const char __user *buf,
331
+ size_t count, loff_t *f_pos)
332
+{
333
+ struct inode *inode = file_inode(file);
334
+ struct tegra_bpmp *bpmp = inode->i_private;
335
+ char *databuf = NULL;
336
+ char fnamebuf[256];
337
+ const char *filename;
338
+ ssize_t err;
339
+
340
+ filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
341
+ if (!filename)
342
+ return -ENOENT;
343
+
344
+ databuf = kmalloc(count, GFP_KERNEL);
345
+ if (!databuf)
346
+ return -ENOMEM;
347
+
348
+ if (copy_from_user(databuf, buf, count)) {
349
+ err = -EFAULT;
350
+ goto free_ret;
351
+ }
352
+
353
+ err = mrq_debug_write(bpmp, filename, databuf, count);
354
+
355
+free_ret:
356
+ kfree(databuf);
357
+
358
+ return err ?: count;
359
+}
360
+
361
+static int bpmp_debug_open(struct inode *inode, struct file *file)
362
+{
363
+ return single_open_size(file, bpmp_debug_show, file, SZ_256K);
364
+}
365
+
366
+static const struct file_operations bpmp_debug_fops = {
367
+ .open = bpmp_debug_open,
368
+ .read = seq_read,
369
+ .llseek = seq_lseek,
370
+ .write = bpmp_debug_store,
371
+ .release = single_release,
372
+};
373
+
374
+static int bpmp_populate_debugfs_inband(struct tegra_bpmp *bpmp,
375
+ struct dentry *parent,
376
+ char *ppath)
377
+{
378
+ const size_t pathlen = SZ_256;
379
+ const size_t bufsize = SZ_16K;
380
+ uint32_t dsize, attrs = 0;
381
+ struct dentry *dentry;
382
+ struct seqbuf seqbuf;
383
+ char *buf, *pathbuf;
384
+ const char *name;
385
+ int err = 0;
386
+
387
+ if (!bpmp || !parent || !ppath)
388
+ return -EINVAL;
389
+
390
+ buf = kmalloc(bufsize, GFP_KERNEL);
391
+ if (!buf)
392
+ return -ENOMEM;
393
+
394
+ pathbuf = kzalloc(pathlen, GFP_KERNEL);
395
+ if (!pathbuf) {
396
+ kfree(buf);
397
+ return -ENOMEM;
398
+ }
399
+
400
+ err = mrq_debug_read(bpmp, ppath, buf, bufsize, &dsize);
401
+ if (err)
402
+ goto out;
403
+
404
+ seqbuf_init(&seqbuf, buf, dsize);
405
+
406
+ while (!seqbuf_eof(&seqbuf)) {
407
+ err = seqbuf_read_u32(&seqbuf, &attrs);
408
+ if (err)
409
+ goto out;
410
+
411
+ err = seqbuf_read_str(&seqbuf, &name);
412
+ if (err < 0)
413
+ goto out;
414
+
415
+ if (attrs & DEBUGFS_S_ISDIR) {
416
+ size_t len;
417
+
418
+ dentry = debugfs_create_dir(name, parent);
419
+ if (IS_ERR(dentry)) {
420
+ err = PTR_ERR(dentry);
421
+ goto out;
422
+ }
423
+
424
+ len = snprintf(pathbuf, pathlen, "%s%s/", ppath, name);
425
+ if (len >= pathlen) {
426
+ err = -EINVAL;
427
+ goto out;
428
+ }
429
+
430
+ err = bpmp_populate_debugfs_inband(bpmp, dentry,
431
+ pathbuf);
432
+ if (err < 0)
433
+ goto out;
434
+ } else {
435
+ umode_t mode;
436
+
437
+ mode = attrs & DEBUGFS_S_IRUSR ? 0400 : 0;
438
+ mode |= attrs & DEBUGFS_S_IWUSR ? 0200 : 0;
439
+ dentry = debugfs_create_file(name, mode, parent, bpmp,
440
+ &bpmp_debug_fops);
441
+ if (IS_ERR(dentry)) {
442
+ err = -ENOMEM;
443
+ goto out;
444
+ }
445
+ }
446
+ }
447
+
448
+out:
449
+ kfree(pathbuf);
450
+ kfree(buf);
451
+
452
+ return err;
106453 }
107454
108455 static int mrq_debugfs_read(struct tegra_bpmp *bpmp,
....@@ -136,6 +483,8 @@
136483 err = tegra_bpmp_transfer(bpmp, &msg);
137484 if (err < 0)
138485 return err;
486
+ else if (msg.rx.ret < 0)
487
+ return -EINVAL;
139488
140489 *nbytes = (size_t)resp.fop.nbytes;
141490
....@@ -193,6 +542,8 @@
193542 err = tegra_bpmp_transfer(bpmp, &msg);
194543 if (err < 0)
195544 return err;
545
+ else if (msg.rx.ret < 0)
546
+ return -EINVAL;
196547
197548 *nbytes = (size_t)resp.dumpdir.nbytes;
198549
....@@ -211,7 +562,7 @@
211562 char buf[256];
212563 const char *filename;
213564 size_t len, nbytes;
214
- int ret;
565
+ int err;
215566
216567 filename = get_filename(bpmp, file, buf, sizeof(buf));
217568 if (!filename)
....@@ -225,24 +576,24 @@
225576 datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
226577 GFP_KERNEL | GFP_DMA32);
227578 if (!datavirt) {
228
- ret = -ENOMEM;
579
+ err = -ENOMEM;
229580 goto free_namebuf;
230581 }
231582
232583 len = strlen(filename);
233584 strncpy(namevirt, filename, namesize);
234585
235
- ret = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
586
+ err = mrq_debugfs_read(bpmp, namephys, len, dataphys, datasize,
236587 &nbytes);
237588
238
- if (!ret)
589
+ if (!err)
239590 seq_write(m, datavirt, nbytes);
240591
241592 dma_free_coherent(bpmp->dev, datasize, datavirt, dataphys);
242593 free_namebuf:
243594 dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
244595
245
- return ret;
596
+ return err;
246597 }
247598
248599 static int debugfs_open(struct inode *inode, struct file *file)
....@@ -262,7 +613,7 @@
262613 char fnamebuf[256];
263614 const char *filename;
264615 size_t len;
265
- int ret;
616
+ int err;
266617
267618 filename = get_filename(bpmp, file, fnamebuf, sizeof(fnamebuf));
268619 if (!filename)
....@@ -276,7 +627,7 @@
276627 datavirt = dma_alloc_coherent(bpmp->dev, datasize, &dataphys,
277628 GFP_KERNEL | GFP_DMA32);
278629 if (!datavirt) {
279
- ret = -ENOMEM;
630
+ err = -ENOMEM;
280631 goto free_namebuf;
281632 }
282633
....@@ -284,11 +635,11 @@
284635 strncpy(namevirt, filename, namesize);
285636
286637 if (copy_from_user(datavirt, buf, count)) {
287
- ret = -EFAULT;
638
+ err = -EFAULT;
288639 goto free_databuf;
289640 }
290641
291
- ret = mrq_debugfs_write(bpmp, namephys, len, dataphys,
642
+ err = mrq_debugfs_write(bpmp, namephys, len, dataphys,
292643 count);
293644
294645 free_databuf:
....@@ -296,7 +647,7 @@
296647 free_namebuf:
297648 dma_free_coherent(bpmp->dev, namesize, namevirt, namephys);
298649
299
- return ret ?: count;
650
+ return err ?: count;
300651 }
301652
302653 static const struct file_operations debugfs_fops = {
....@@ -338,7 +689,7 @@
338689
339690 if (t & DEBUGFS_S_ISDIR) {
340691 dentry = debugfs_create_dir(name, parent);
341
- if (!dentry)
692
+ if (IS_ERR(dentry))
342693 return -ENOMEM;
343694 err = bpmp_populate_dir(bpmp, seqbuf, dentry, depth+1);
344695 if (err < 0)
....@@ -351,7 +702,7 @@
351702 dentry = debugfs_create_file(name, mode,
352703 parent, bpmp,
353704 &debugfs_fops);
354
- if (!dentry)
705
+ if (IS_ERR(dentry))
355706 return -ENOMEM;
356707 }
357708 }
....@@ -359,86 +710,66 @@
359710 return 0;
360711 }
361712
362
-static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf,
363
- size_t bufsize, struct dentry *root)
713
+static int bpmp_populate_debugfs_shmem(struct tegra_bpmp *bpmp)
364714 {
365715 struct seqbuf seqbuf;
716
+ const size_t sz = SZ_512K;
717
+ dma_addr_t phys;
718
+ size_t nbytes;
719
+ void *virt;
366720 int err;
367721
368
- bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
369
- if (!bpmp->debugfs_mirror)
722
+ virt = dma_alloc_coherent(bpmp->dev, sz, &phys,
723
+ GFP_KERNEL | GFP_DMA32);
724
+ if (!virt)
370725 return -ENOMEM;
371726
372
- seqbuf_init(&seqbuf, buf, bufsize);
373
- err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0);
727
+ err = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes);
374728 if (err < 0) {
375
- debugfs_remove_recursive(bpmp->debugfs_mirror);
376
- bpmp->debugfs_mirror = NULL;
729
+ goto free;
730
+ } else if (nbytes > sz) {
731
+ err = -EINVAL;
732
+ goto free;
377733 }
734
+
735
+ seqbuf_init(&seqbuf, virt, nbytes);
736
+ err = bpmp_populate_dir(bpmp, &seqbuf, bpmp->debugfs_mirror, 0);
737
+free:
738
+ dma_free_coherent(bpmp->dev, sz, virt, phys);
378739
379740 return err;
380741 }
381742
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
-
409743 int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp)
410744 {
411
- dma_addr_t phys;
412
- void *virt;
413
- const size_t sz = SZ_256K;
414
- size_t nbytes;
415
- int ret;
416745 struct dentry *root;
746
+ bool inband;
747
+ int err;
417748
418
- if (!mrq_is_supported(bpmp, MRQ_DEBUGFS))
749
+ inband = tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUG);
750
+
751
+ if (!inband && !tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS))
419752 return 0;
420753
421754 root = debugfs_create_dir("bpmp", NULL);
422
- if (!root)
755
+ if (IS_ERR(root))
423756 return -ENOMEM;
424757
425
- virt = dma_alloc_coherent(bpmp->dev, sz, &phys,
426
- GFP_KERNEL | GFP_DMA32);
427
- if (!virt) {
428
- ret = -ENOMEM;
758
+ bpmp->debugfs_mirror = debugfs_create_dir("debug", root);
759
+ if (IS_ERR(bpmp->debugfs_mirror)) {
760
+ err = -ENOMEM;
429761 goto out;
430762 }
431763
432
- ret = mrq_debugfs_dumpdir(bpmp, phys, sz, &nbytes);
433
- if (ret < 0)
434
- goto free;
764
+ if (inband)
765
+ err = bpmp_populate_debugfs_inband(bpmp, bpmp->debugfs_mirror,
766
+ "/");
767
+ else
768
+ err = bpmp_populate_debugfs_shmem(bpmp);
435769
436
- ret = create_debugfs_mirror(bpmp, virt, nbytes, root);
437
-free:
438
- dma_free_coherent(bpmp->dev, sz, virt, phys);
439770 out:
440
- if (ret < 0)
441
- debugfs_remove(root);
771
+ if (err < 0)
772
+ debugfs_remove_recursive(root);
442773
443
- return ret;
774
+ return err;
444775 }