1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright 2020-2021 NXP
4 */
5
6 #include <linux/init.h>
7 #include <linux/device.h>
8 #include <linux/ioctl.h>
9 #include <linux/list.h>
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/types.h>
13 #include <linux/pm_runtime.h>
14 #include <media/v4l2-device.h>
15 #include <linux/debugfs.h>
16 #include "vpu.h"
17 #include "vpu_defs.h"
18 #include "vpu_core.h"
19 #include "vpu_helpers.h"
20 #include "vpu_cmds.h"
21 #include "vpu_rpc.h"
22 #include "vpu_v4l2.h"
23
24 struct print_buf_desc {
25 u32 start_h_phy;
26 u32 start_h_vir;
27 u32 start_m;
28 u32 bytes;
29 u32 read;
30 u32 write;
31 char buffer[];
32 };
33
34 static char *vb2_stat_name[] = {
35 [VB2_BUF_STATE_DEQUEUED] = "dequeued",
36 [VB2_BUF_STATE_IN_REQUEST] = "in_request",
37 [VB2_BUF_STATE_PREPARING] = "preparing",
38 [VB2_BUF_STATE_QUEUED] = "queued",
39 [VB2_BUF_STATE_ACTIVE] = "active",
40 [VB2_BUF_STATE_DONE] = "done",
41 [VB2_BUF_STATE_ERROR] = "error",
42 };
43
44 static char *vpu_stat_name[] = {
45 [VPU_BUF_STATE_IDLE] = "idle",
46 [VPU_BUF_STATE_INUSE] = "inuse",
47 [VPU_BUF_STATE_DECODED] = "decoded",
48 [VPU_BUF_STATE_READY] = "ready",
49 [VPU_BUF_STATE_SKIP] = "skip",
50 [VPU_BUF_STATE_ERROR] = "error",
51 };
52
to_vpu_stat_name(int state)53 static inline const char *to_vpu_stat_name(int state)
54 {
55 if (state <= VPU_BUF_STATE_ERROR)
56 return vpu_stat_name[state];
57 return "unknown";
58 }
59
vpu_dbg_instance(struct seq_file * s,void * data)60 static int vpu_dbg_instance(struct seq_file *s, void *data)
61 {
62 struct vpu_inst *inst = s->private;
63 char str[128];
64 int num;
65 struct vb2_queue *vq;
66 int i;
67
68 if (!inst->fh.m2m_ctx)
69 return 0;
70 num = scnprintf(str, sizeof(str), "[%s]\n", vpu_core_type_desc(inst->type));
71 if (seq_write(s, str, num))
72 return 0;
73
74 num = scnprintf(str, sizeof(str), "tgig = %d,pid = %d\n", inst->tgid, inst->pid);
75 if (seq_write(s, str, num))
76 return 0;
77 num = scnprintf(str, sizeof(str), "state = %s\n", vpu_codec_state_name(inst->state));
78 if (seq_write(s, str, num))
79 return 0;
80 num = scnprintf(str, sizeof(str),
81 "min_buffer_out = %d, min_buffer_cap = %d\n",
82 inst->min_buffer_out, inst->min_buffer_cap);
83 if (seq_write(s, str, num))
84 return 0;
85
86 vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
87 num = scnprintf(str, sizeof(str),
88 "output (%2d, %2d): fmt = %c%c%c%c %d x %d, %d;",
89 vb2_is_streaming(vq),
90 vq->num_buffers,
91 inst->out_format.pixfmt,
92 inst->out_format.pixfmt >> 8,
93 inst->out_format.pixfmt >> 16,
94 inst->out_format.pixfmt >> 24,
95 inst->out_format.width,
96 inst->out_format.height,
97 vq->last_buffer_dequeued);
98 if (seq_write(s, str, num))
99 return 0;
100 for (i = 0; i < inst->out_format.mem_planes; i++) {
101 num = scnprintf(str, sizeof(str), " %d(%d)",
102 vpu_get_fmt_plane_size(&inst->out_format, i),
103 inst->out_format.bytesperline[i]);
104 if (seq_write(s, str, num))
105 return 0;
106 }
107 if (seq_write(s, "\n", 1))
108 return 0;
109
110 vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
111 num = scnprintf(str, sizeof(str),
112 "capture(%2d, %2d): fmt = %c%c%c%c %d x %d, %d;",
113 vb2_is_streaming(vq),
114 vq->num_buffers,
115 inst->cap_format.pixfmt,
116 inst->cap_format.pixfmt >> 8,
117 inst->cap_format.pixfmt >> 16,
118 inst->cap_format.pixfmt >> 24,
119 inst->cap_format.width,
120 inst->cap_format.height,
121 vq->last_buffer_dequeued);
122 if (seq_write(s, str, num))
123 return 0;
124 for (i = 0; i < inst->cap_format.mem_planes; i++) {
125 num = scnprintf(str, sizeof(str), " %d(%d)",
126 vpu_get_fmt_plane_size(&inst->cap_format, i),
127 inst->cap_format.bytesperline[i]);
128 if (seq_write(s, str, num))
129 return 0;
130 }
131 if (seq_write(s, "\n", 1))
132 return 0;
133 num = scnprintf(str, sizeof(str), "crop: (%d, %d) %d x %d\n",
134 inst->crop.left,
135 inst->crop.top,
136 inst->crop.width,
137 inst->crop.height);
138 if (seq_write(s, str, num))
139 return 0;
140
141 vq = v4l2_m2m_get_src_vq(inst->fh.m2m_ctx);
142 for (i = 0; i < vq->num_buffers; i++) {
143 struct vb2_buffer *vb = vq->bufs[i];
144 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
145
146 if (vb->state == VB2_BUF_STATE_DEQUEUED)
147 continue;
148 num = scnprintf(str, sizeof(str),
149 "output [%2d] state = %10s, %8s\n",
150 i, vb2_stat_name[vb->state],
151 to_vpu_stat_name(vpu_get_buffer_state(vbuf)));
152 if (seq_write(s, str, num))
153 return 0;
154 }
155
156 vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
157 for (i = 0; i < vq->num_buffers; i++) {
158 struct vb2_buffer *vb = vq->bufs[i];
159 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
160
161 if (vb->state == VB2_BUF_STATE_DEQUEUED)
162 continue;
163 num = scnprintf(str, sizeof(str),
164 "capture[%2d] state = %10s, %8s\n",
165 i, vb2_stat_name[vb->state],
166 to_vpu_stat_name(vpu_get_buffer_state(vbuf)));
167 if (seq_write(s, str, num))
168 return 0;
169 }
170
171 num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence);
172 if (seq_write(s, str, num))
173 return 0;
174
175 if (inst->use_stream_buffer) {
176 num = scnprintf(str, sizeof(str), "stream_buffer = %d / %d, <%pad, 0x%x>\n",
177 vpu_helper_get_used_space(inst),
178 inst->stream_buffer.length,
179 &inst->stream_buffer.phys,
180 inst->stream_buffer.length);
181 if (seq_write(s, str, num))
182 return 0;
183 }
184 num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&inst->msg_fifo));
185 if (seq_write(s, str, num))
186 return 0;
187
188 num = scnprintf(str, sizeof(str), "flow :\n");
189 if (seq_write(s, str, num))
190 return 0;
191
192 mutex_lock(&inst->core->cmd_lock);
193 for (i = 0; i < ARRAY_SIZE(inst->flows); i++) {
194 u32 idx = (inst->flow_idx + i) % (ARRAY_SIZE(inst->flows));
195
196 if (!inst->flows[idx])
197 continue;
198 num = scnprintf(str, sizeof(str), "\t[%s] %s\n",
199 inst->flows[idx] >= VPU_MSG_ID_NOOP ? "M" : "C",
200 vpu_id_name(inst->flows[idx]));
201 if (seq_write(s, str, num)) {
202 mutex_unlock(&inst->core->cmd_lock);
203 return 0;
204 }
205 }
206 mutex_unlock(&inst->core->cmd_lock);
207
208 i = 0;
209 while (true) {
210 num = call_vop(inst, get_debug_info, str, sizeof(str), i++);
211 if (num <= 0)
212 break;
213 if (seq_write(s, str, num))
214 return 0;
215 }
216
217 return 0;
218 }
219
vpu_dbg_core(struct seq_file * s,void * data)220 static int vpu_dbg_core(struct seq_file *s, void *data)
221 {
222 struct vpu_core *core = s->private;
223 struct vpu_shared_addr *iface = core->iface;
224 char str[128];
225 int num;
226
227 num = scnprintf(str, sizeof(str), "[%s]\n", vpu_core_type_desc(core->type));
228 if (seq_write(s, str, num))
229 return 0;
230
231 num = scnprintf(str, sizeof(str), "boot_region = <%pad, 0x%x>\n",
232 &core->fw.phys, core->fw.length);
233 if (seq_write(s, str, num))
234 return 0;
235 num = scnprintf(str, sizeof(str), "rpc_region = <%pad, 0x%x> used = 0x%x\n",
236 &core->rpc.phys, core->rpc.length, core->rpc.bytesused);
237 if (seq_write(s, str, num))
238 return 0;
239 num = scnprintf(str, sizeof(str), "fwlog_region = <%pad, 0x%x>\n",
240 &core->log.phys, core->log.length);
241 if (seq_write(s, str, num))
242 return 0;
243
244 num = scnprintf(str, sizeof(str), "power %s\n",
245 vpu_iface_get_power_state(core) ? "on" : "off");
246 if (seq_write(s, str, num))
247 return 0;
248 num = scnprintf(str, sizeof(str), "state = %d\n", core->state);
249 if (seq_write(s, str, num))
250 return 0;
251 if (core->state == VPU_CORE_DEINIT)
252 return 0;
253 num = scnprintf(str, sizeof(str), "fw version = %d.%d.%d\n",
254 (core->fw_version >> 16) & 0xff,
255 (core->fw_version >> 8) & 0xff,
256 core->fw_version & 0xff);
257 if (seq_write(s, str, num))
258 return 0;
259 num = scnprintf(str, sizeof(str), "instances = %d/%d (0x%02lx), %d\n",
260 hweight32(core->instance_mask),
261 core->supported_instance_count,
262 core->instance_mask,
263 core->request_count);
264 if (seq_write(s, str, num))
265 return 0;
266 num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&core->msg_fifo));
267 if (seq_write(s, str, num))
268 return 0;
269 num = scnprintf(str, sizeof(str),
270 "cmd_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n",
271 iface->cmd_desc->start,
272 iface->cmd_desc->end,
273 iface->cmd_desc->wptr,
274 iface->cmd_desc->rptr);
275 if (seq_write(s, str, num))
276 return 0;
277 num = scnprintf(str, sizeof(str),
278 "msg_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n",
279 iface->msg_desc->start,
280 iface->msg_desc->end,
281 iface->msg_desc->wptr,
282 iface->msg_desc->rptr);
283 if (seq_write(s, str, num))
284 return 0;
285
286 return 0;
287 }
288
vpu_dbg_fwlog(struct seq_file * s,void * data)289 static int vpu_dbg_fwlog(struct seq_file *s, void *data)
290 {
291 struct vpu_core *core = s->private;
292 struct print_buf_desc *print_buf;
293 int length;
294 u32 rptr;
295 u32 wptr;
296 int ret = 0;
297
298 if (!core->log.virt || core->state == VPU_CORE_DEINIT)
299 return 0;
300
301 print_buf = core->log.virt;
302 rptr = print_buf->read;
303 wptr = print_buf->write;
304
305 if (rptr == wptr)
306 return 0;
307 else if (rptr < wptr)
308 length = wptr - rptr;
309 else
310 length = print_buf->bytes + wptr - rptr;
311
312 if (s->count + length >= s->size) {
313 s->count = s->size;
314 return 0;
315 }
316
317 if (rptr + length >= print_buf->bytes) {
318 int num = print_buf->bytes - rptr;
319
320 if (seq_write(s, print_buf->buffer + rptr, num))
321 ret = -1;
322 length -= num;
323 rptr = 0;
324 }
325
326 if (length) {
327 if (seq_write(s, print_buf->buffer + rptr, length))
328 ret = -1;
329 rptr += length;
330 }
331 if (!ret)
332 print_buf->read = rptr;
333
334 return 0;
335 }
336
vpu_dbg_inst_open(struct inode * inode,struct file * filp)337 static int vpu_dbg_inst_open(struct inode *inode, struct file *filp)
338 {
339 return single_open(filp, vpu_dbg_instance, inode->i_private);
340 }
341
vpu_dbg_inst_write(struct file * file,const char __user * user_buf,size_t size,loff_t * ppos)342 static ssize_t vpu_dbg_inst_write(struct file *file,
343 const char __user *user_buf, size_t size, loff_t *ppos)
344 {
345 struct seq_file *s = file->private_data;
346 struct vpu_inst *inst = s->private;
347
348 vpu_session_debug(inst);
349
350 return size;
351 }
352
vpu_dbg_core_write(struct file * file,const char __user * user_buf,size_t size,loff_t * ppos)353 static ssize_t vpu_dbg_core_write(struct file *file,
354 const char __user *user_buf, size_t size, loff_t *ppos)
355 {
356 struct seq_file *s = file->private_data;
357 struct vpu_core *core = s->private;
358
359 pm_runtime_resume_and_get(core->dev);
360 mutex_lock(&core->lock);
361 if (vpu_iface_get_power_state(core) && !core->request_count) {
362 dev_info(core->dev, "reset\n");
363 if (!vpu_core_sw_reset(core)) {
364 vpu_core_set_state(core, VPU_CORE_ACTIVE);
365 core->hang_mask = 0;
366 }
367 }
368 mutex_unlock(&core->lock);
369 pm_runtime_put_sync(core->dev);
370
371 return size;
372 }
373
vpu_dbg_core_open(struct inode * inode,struct file * filp)374 static int vpu_dbg_core_open(struct inode *inode, struct file *filp)
375 {
376 return single_open(filp, vpu_dbg_core, inode->i_private);
377 }
378
vpu_dbg_fwlog_open(struct inode * inode,struct file * filp)379 static int vpu_dbg_fwlog_open(struct inode *inode, struct file *filp)
380 {
381 return single_open(filp, vpu_dbg_fwlog, inode->i_private);
382 }
383
384 static const struct file_operations vpu_dbg_inst_fops = {
385 .owner = THIS_MODULE,
386 .open = vpu_dbg_inst_open,
387 .release = single_release,
388 .read = seq_read,
389 .write = vpu_dbg_inst_write,
390 };
391
392 static const struct file_operations vpu_dbg_core_fops = {
393 .owner = THIS_MODULE,
394 .open = vpu_dbg_core_open,
395 .release = single_release,
396 .read = seq_read,
397 .write = vpu_dbg_core_write,
398 };
399
400 static const struct file_operations vpu_dbg_fwlog_fops = {
401 .owner = THIS_MODULE,
402 .open = vpu_dbg_fwlog_open,
403 .release = single_release,
404 .read = seq_read,
405 };
406
vpu_inst_create_dbgfs_file(struct vpu_inst * inst)407 int vpu_inst_create_dbgfs_file(struct vpu_inst *inst)
408 {
409 struct vpu_dev *vpu;
410 char name[64];
411
412 if (!inst || !inst->core || !inst->core->vpu)
413 return -EINVAL;
414
415 vpu = inst->core->vpu;
416 if (!vpu->debugfs)
417 return -EINVAL;
418
419 if (inst->debugfs)
420 return 0;
421
422 scnprintf(name, sizeof(name), "instance.%d.%d", inst->core->id, inst->id);
423 inst->debugfs = debugfs_create_file((const char *)name,
424 VERIFY_OCTAL_PERMISSIONS(0644),
425 vpu->debugfs,
426 inst,
427 &vpu_dbg_inst_fops);
428
429 return 0;
430 }
431
vpu_inst_remove_dbgfs_file(struct vpu_inst * inst)432 int vpu_inst_remove_dbgfs_file(struct vpu_inst *inst)
433 {
434 if (!inst)
435 return 0;
436
437 debugfs_remove(inst->debugfs);
438 inst->debugfs = NULL;
439
440 return 0;
441 }
442
vpu_core_create_dbgfs_file(struct vpu_core * core)443 int vpu_core_create_dbgfs_file(struct vpu_core *core)
444 {
445 struct vpu_dev *vpu;
446 char name[64];
447
448 if (!core || !core->vpu)
449 return -EINVAL;
450
451 vpu = core->vpu;
452 if (!vpu->debugfs)
453 return -EINVAL;
454
455 if (!core->debugfs) {
456 scnprintf(name, sizeof(name), "core.%d", core->id);
457 core->debugfs = debugfs_create_file((const char *)name,
458 VERIFY_OCTAL_PERMISSIONS(0644),
459 vpu->debugfs,
460 core,
461 &vpu_dbg_core_fops);
462 }
463 if (!core->debugfs_fwlog) {
464 scnprintf(name, sizeof(name), "fwlog.%d", core->id);
465 core->debugfs_fwlog = debugfs_create_file((const char *)name,
466 VERIFY_OCTAL_PERMISSIONS(0444),
467 vpu->debugfs,
468 core,
469 &vpu_dbg_fwlog_fops);
470 }
471
472 return 0;
473 }
474
vpu_core_remove_dbgfs_file(struct vpu_core * core)475 int vpu_core_remove_dbgfs_file(struct vpu_core *core)
476 {
477 if (!core)
478 return 0;
479 debugfs_remove(core->debugfs);
480 core->debugfs = NULL;
481 debugfs_remove(core->debugfs_fwlog);
482 core->debugfs_fwlog = NULL;
483
484 return 0;
485 }
486
vpu_inst_record_flow(struct vpu_inst * inst,u32 flow)487 void vpu_inst_record_flow(struct vpu_inst *inst, u32 flow)
488 {
489 if (!inst)
490 return;
491
492 inst->flows[inst->flow_idx] = flow;
493 inst->flow_idx = (inst->flow_idx + 1) % (ARRAY_SIZE(inst->flows));
494 }
495