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