1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Debugfs tracing for bitstream buffers. This is similar to VA-API's |
4 | * LIBVA_TRACE_BUFDATA in that the raw bitstream can be dumped as a debugging |
5 | * aid. |
6 | * |
7 | * Produces one file per OUTPUT buffer. Files are automatically cleared on |
8 | * STREAMOFF unless the module parameter "keep_bitstream_buffers" is set. |
9 | */ |
10 | |
11 | #include <linux/debugfs.h> |
12 | #include <linux/list.h> |
13 | #include <linux/mutex.h> |
14 | #include <media/v4l2-mem2mem.h> |
15 | |
16 | #include "visl-debugfs.h" |
17 | |
18 | int visl_debugfs_init(struct visl_dev *dev) |
19 | { |
20 | dev->debugfs_root = debugfs_create_dir(name: "visl" , NULL); |
21 | INIT_LIST_HEAD(list: &dev->bitstream_blobs); |
22 | mutex_init(&dev->bitstream_lock); |
23 | |
24 | if (IS_ERR(ptr: dev->debugfs_root)) |
25 | return PTR_ERR(ptr: dev->debugfs_root); |
26 | |
27 | return visl_debugfs_bitstream_init(dev); |
28 | } |
29 | |
30 | int visl_debugfs_bitstream_init(struct visl_dev *dev) |
31 | { |
32 | dev->bitstream_debugfs = debugfs_create_dir(name: "bitstream" , |
33 | parent: dev->debugfs_root); |
34 | if (IS_ERR(ptr: dev->bitstream_debugfs)) |
35 | return PTR_ERR(ptr: dev->bitstream_debugfs); |
36 | |
37 | return 0; |
38 | } |
39 | |
40 | void visl_trace_bitstream(struct visl_ctx *ctx, struct visl_run *run) |
41 | { |
42 | u8 *vaddr = vb2_plane_vaddr(vb: &run->src->vb2_buf, plane_no: 0); |
43 | struct visl_blob *blob; |
44 | size_t data_sz = vb2_get_plane_payload(vb: &run->src->vb2_buf, plane_no: 0); |
45 | struct dentry *dentry; |
46 | char name[32]; |
47 | |
48 | blob = kzalloc(size: sizeof(*blob), GFP_KERNEL); |
49 | if (!blob) |
50 | return; |
51 | |
52 | blob->blob.data = vzalloc(size: data_sz); |
53 | if (!blob->blob.data) |
54 | goto err_vmalloc; |
55 | |
56 | blob->blob.size = data_sz; |
57 | snprintf(buf: name, size: 32, fmt: "bitstream%d" , run->src->sequence); |
58 | |
59 | memcpy(blob->blob.data, vaddr, data_sz); |
60 | |
61 | dentry = debugfs_create_blob(name, mode: 0444, parent: ctx->dev->bitstream_debugfs, |
62 | blob: &blob->blob); |
63 | if (IS_ERR(ptr: dentry)) |
64 | goto err_debugfs; |
65 | |
66 | blob->dentry = dentry; |
67 | |
68 | mutex_lock(&ctx->dev->bitstream_lock); |
69 | list_add_tail(new: &blob->list, head: &ctx->dev->bitstream_blobs); |
70 | mutex_unlock(lock: &ctx->dev->bitstream_lock); |
71 | |
72 | return; |
73 | |
74 | err_debugfs: |
75 | vfree(addr: blob->blob.data); |
76 | err_vmalloc: |
77 | kfree(objp: blob); |
78 | } |
79 | |
80 | void visl_debugfs_clear_bitstream(struct visl_dev *dev) |
81 | { |
82 | struct visl_blob *blob; |
83 | struct visl_blob *tmp; |
84 | |
85 | mutex_lock(&dev->bitstream_lock); |
86 | if (list_empty(head: &dev->bitstream_blobs)) |
87 | goto unlock; |
88 | |
89 | list_for_each_entry_safe(blob, tmp, &dev->bitstream_blobs, list) { |
90 | list_del(entry: &blob->list); |
91 | debugfs_remove(dentry: blob->dentry); |
92 | vfree(addr: blob->blob.data); |
93 | kfree(objp: blob); |
94 | } |
95 | |
96 | unlock: |
97 | mutex_unlock(lock: &dev->bitstream_lock); |
98 | } |
99 | |
100 | void visl_debugfs_bitstream_deinit(struct visl_dev *dev) |
101 | { |
102 | visl_debugfs_clear_bitstream(dev); |
103 | debugfs_remove_recursive(dentry: dev->bitstream_debugfs); |
104 | dev->bitstream_debugfs = NULL; |
105 | } |
106 | |
107 | void visl_debugfs_deinit(struct visl_dev *dev) |
108 | { |
109 | visl_debugfs_bitstream_deinit(dev); |
110 | debugfs_remove_recursive(dentry: dev->debugfs_root); |
111 | dev->debugfs_root = NULL; |
112 | } |
113 | |