GNU Linux-libre 6.8.7-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_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
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
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                         vb2_get_num_buffers(vq),
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                         vb2_get_num_buffers(vq),
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 < vb2_get_num_buffers(vq); i++) {
143                 struct vb2_buffer *vb;
144                 struct vb2_v4l2_buffer *vbuf;
145
146                 vb = vb2_get_buffer(vq, i);
147                 if (!vb)
148                         continue;
149
150                 if (vb->state == VB2_BUF_STATE_DEQUEUED)
151                         continue;
152
153                 vbuf = to_vb2_v4l2_buffer(vb);
154
155                 num = scnprintf(str, sizeof(str),
156                                 "output [%2d] state = %10s, %8s\n",
157                                 i, vb2_stat_name[vb->state],
158                                 to_vpu_stat_name(vpu_get_buffer_state(vbuf)));
159                 if (seq_write(s, str, num))
160                         return 0;
161         }
162
163         vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx);
164         for (i = 0; i < vb2_get_num_buffers(vq); i++) {
165                 struct vb2_buffer *vb;
166                 struct vb2_v4l2_buffer *vbuf;
167
168                 vb = vb2_get_buffer(vq, i);
169                 if (!vb)
170                         continue;
171
172                 if (vb->state == VB2_BUF_STATE_DEQUEUED)
173                         continue;
174
175                 vbuf = to_vb2_v4l2_buffer(vb);
176
177                 num = scnprintf(str, sizeof(str),
178                                 "capture[%2d] state = %10s, %8s\n",
179                                 i, vb2_stat_name[vb->state],
180                                 to_vpu_stat_name(vpu_get_buffer_state(vbuf)));
181                 if (seq_write(s, str, num))
182                         return 0;
183         }
184
185         num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence);
186         if (seq_write(s, str, num))
187                 return 0;
188
189         if (inst->use_stream_buffer) {
190                 num = scnprintf(str, sizeof(str), "stream_buffer = %d / %d, <%pad, 0x%x>\n",
191                                 vpu_helper_get_used_space(inst),
192                                 inst->stream_buffer.length,
193                                 &inst->stream_buffer.phys,
194                                 inst->stream_buffer.length);
195                 if (seq_write(s, str, num))
196                         return 0;
197         }
198         num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&inst->msg_fifo));
199         if (seq_write(s, str, num))
200                 return 0;
201
202         num = scnprintf(str, sizeof(str), "flow :\n");
203         if (seq_write(s, str, num))
204                 return 0;
205
206         mutex_lock(&inst->core->cmd_lock);
207         for (i = 0; i < ARRAY_SIZE(inst->flows); i++) {
208                 u32 idx = (inst->flow_idx + i) % (ARRAY_SIZE(inst->flows));
209
210                 if (!inst->flows[idx])
211                         continue;
212                 num = scnprintf(str, sizeof(str), "\t[%s] %s\n",
213                                 inst->flows[idx] >= VPU_MSG_ID_NOOP ? "M" : "C",
214                                 vpu_id_name(inst->flows[idx]));
215                 if (seq_write(s, str, num)) {
216                         mutex_unlock(&inst->core->cmd_lock);
217                         return 0;
218                 }
219         }
220         mutex_unlock(&inst->core->cmd_lock);
221
222         i = 0;
223         while (true) {
224                 num = call_vop(inst, get_debug_info, str, sizeof(str), i++);
225                 if (num <= 0)
226                         break;
227                 if (seq_write(s, str, num))
228                         return 0;
229         }
230
231         return 0;
232 }
233
234 static int vpu_dbg_core(struct seq_file *s, void *data)
235 {
236         struct vpu_core *core = s->private;
237         struct vpu_shared_addr *iface = core->iface;
238         char str[128];
239         int num;
240
241         num = scnprintf(str, sizeof(str), "[%s]\n", vpu_core_type_desc(core->type));
242         if (seq_write(s, str, num))
243                 return 0;
244
245         num = scnprintf(str, sizeof(str), "boot_region  = <%pad, 0x%x>\n",
246                         &core->fw.phys, core->fw.length);
247         if (seq_write(s, str, num))
248                 return 0;
249         num = scnprintf(str, sizeof(str), "rpc_region   = <%pad, 0x%x> used = 0x%x\n",
250                         &core->rpc.phys, core->rpc.length, core->rpc.bytesused);
251         if (seq_write(s, str, num))
252                 return 0;
253         num = scnprintf(str, sizeof(str), "fwlog_region = <%pad, 0x%x>\n",
254                         &core->log.phys, core->log.length);
255         if (seq_write(s, str, num))
256                 return 0;
257
258         num = scnprintf(str, sizeof(str), "power %s\n",
259                         vpu_iface_get_power_state(core) ? "on" : "off");
260         if (seq_write(s, str, num))
261                 return 0;
262         num = scnprintf(str, sizeof(str), "state = %d\n", core->state);
263         if (seq_write(s, str, num))
264                 return 0;
265         if (core->state == VPU_CORE_DEINIT)
266                 return 0;
267         num = scnprintf(str, sizeof(str), "fw version = %d.%d.%d\n",
268                         (core->fw_version >> 16) & 0xff,
269                         (core->fw_version >> 8) & 0xff,
270                         core->fw_version & 0xff);
271         if (seq_write(s, str, num))
272                 return 0;
273         num = scnprintf(str, sizeof(str), "instances = %d/%d (0x%02lx), %d\n",
274                         hweight32(core->instance_mask),
275                         core->supported_instance_count,
276                         core->instance_mask,
277                         core->request_count);
278         if (seq_write(s, str, num))
279                 return 0;
280         num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&core->msg_fifo));
281         if (seq_write(s, str, num))
282                 return 0;
283         num = scnprintf(str, sizeof(str),
284                         "cmd_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n",
285                         iface->cmd_desc->start,
286                         iface->cmd_desc->end,
287                         iface->cmd_desc->wptr,
288                         iface->cmd_desc->rptr);
289         if (seq_write(s, str, num))
290                 return 0;
291         num = scnprintf(str, sizeof(str),
292                         "msg_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n",
293                         iface->msg_desc->start,
294                         iface->msg_desc->end,
295                         iface->msg_desc->wptr,
296                         iface->msg_desc->rptr);
297         if (seq_write(s, str, num))
298                 return 0;
299
300         return 0;
301 }
302
303 static int vpu_dbg_fwlog(struct seq_file *s, void *data)
304 {
305         struct vpu_core *core = s->private;
306         struct print_buf_desc *print_buf;
307         int length;
308         u32 rptr;
309         u32 wptr;
310         int ret = 0;
311
312         if (!core->log.virt || core->state == VPU_CORE_DEINIT)
313                 return 0;
314
315         print_buf = core->log.virt;
316         rptr = print_buf->read;
317         wptr = print_buf->write;
318
319         if (rptr == wptr)
320                 return 0;
321         else if (rptr < wptr)
322                 length = wptr - rptr;
323         else
324                 length = print_buf->bytes + wptr - rptr;
325
326         if (s->count + length >= s->size) {
327                 s->count = s->size;
328                 return 0;
329         }
330
331         if (rptr + length >= print_buf->bytes) {
332                 int num = print_buf->bytes - rptr;
333
334                 if (seq_write(s, print_buf->buffer + rptr, num))
335                         ret = -1;
336                 length -= num;
337                 rptr = 0;
338         }
339
340         if (length) {
341                 if (seq_write(s, print_buf->buffer + rptr, length))
342                         ret = -1;
343                 rptr += length;
344         }
345         if (!ret)
346                 print_buf->read = rptr;
347
348         return 0;
349 }
350
351 static int vpu_dbg_inst_open(struct inode *inode, struct file *filp)
352 {
353         return single_open(filp, vpu_dbg_instance, inode->i_private);
354 }
355
356 static ssize_t vpu_dbg_inst_write(struct file *file,
357                                   const char __user *user_buf, size_t size, loff_t *ppos)
358 {
359         struct seq_file *s = file->private_data;
360         struct vpu_inst *inst = s->private;
361
362         vpu_session_debug(inst);
363
364         return size;
365 }
366
367 static ssize_t vpu_dbg_core_write(struct file *file,
368                                   const char __user *user_buf, size_t size, loff_t *ppos)
369 {
370         struct seq_file *s = file->private_data;
371         struct vpu_core *core = s->private;
372
373         pm_runtime_resume_and_get(core->dev);
374         mutex_lock(&core->lock);
375         if (vpu_iface_get_power_state(core) && !core->request_count) {
376                 dev_info(core->dev, "reset\n");
377                 if (!vpu_core_sw_reset(core)) {
378                         vpu_core_set_state(core, VPU_CORE_ACTIVE);
379                         core->hang_mask = 0;
380                 }
381         }
382         mutex_unlock(&core->lock);
383         pm_runtime_put_sync(core->dev);
384
385         return size;
386 }
387
388 static int vpu_dbg_core_open(struct inode *inode, struct file *filp)
389 {
390         return single_open(filp, vpu_dbg_core, inode->i_private);
391 }
392
393 static int vpu_dbg_fwlog_open(struct inode *inode, struct file *filp)
394 {
395         return single_open(filp, vpu_dbg_fwlog, inode->i_private);
396 }
397
398 static const struct file_operations vpu_dbg_inst_fops = {
399         .owner = THIS_MODULE,
400         .open = vpu_dbg_inst_open,
401         .release = single_release,
402         .read = seq_read,
403         .write = vpu_dbg_inst_write,
404 };
405
406 static const struct file_operations vpu_dbg_core_fops = {
407         .owner = THIS_MODULE,
408         .open = vpu_dbg_core_open,
409         .release = single_release,
410         .read = seq_read,
411         .write = vpu_dbg_core_write,
412 };
413
414 static const struct file_operations vpu_dbg_fwlog_fops = {
415         .owner = THIS_MODULE,
416         .open = vpu_dbg_fwlog_open,
417         .release = single_release,
418         .read = seq_read,
419 };
420
421 int vpu_inst_create_dbgfs_file(struct vpu_inst *inst)
422 {
423         struct vpu_dev *vpu;
424         char name[64];
425
426         if (!inst || !inst->core || !inst->core->vpu)
427                 return -EINVAL;
428
429         vpu = inst->core->vpu;
430         if (!vpu->debugfs)
431                 return -EINVAL;
432
433         if (inst->debugfs)
434                 return 0;
435
436         scnprintf(name, sizeof(name), "instance.%d.%d", inst->core->id, inst->id);
437         inst->debugfs = debugfs_create_file((const char *)name,
438                                             VERIFY_OCTAL_PERMISSIONS(0644),
439                                             vpu->debugfs,
440                                             inst,
441                                             &vpu_dbg_inst_fops);
442
443         return 0;
444 }
445
446 int vpu_inst_remove_dbgfs_file(struct vpu_inst *inst)
447 {
448         if (!inst)
449                 return 0;
450
451         debugfs_remove(inst->debugfs);
452         inst->debugfs = NULL;
453
454         return 0;
455 }
456
457 int vpu_core_create_dbgfs_file(struct vpu_core *core)
458 {
459         struct vpu_dev *vpu;
460         char name[64];
461
462         if (!core || !core->vpu)
463                 return -EINVAL;
464
465         vpu = core->vpu;
466         if (!vpu->debugfs)
467                 return -EINVAL;
468
469         if (!core->debugfs) {
470                 scnprintf(name, sizeof(name), "core.%d", core->id);
471                 core->debugfs = debugfs_create_file((const char *)name,
472                                                     VERIFY_OCTAL_PERMISSIONS(0644),
473                                                     vpu->debugfs,
474                                                     core,
475                                                     &vpu_dbg_core_fops);
476         }
477         if (!core->debugfs_fwlog) {
478                 scnprintf(name, sizeof(name), "fwlog.%d", core->id);
479                 core->debugfs_fwlog = debugfs_create_file((const char *)name,
480                                                           VERIFY_OCTAL_PERMISSIONS(0444),
481                                                           vpu->debugfs,
482                                                           core,
483                                                           &vpu_dbg_fwlog_fops);
484         }
485
486         return 0;
487 }
488
489 int vpu_core_remove_dbgfs_file(struct vpu_core *core)
490 {
491         if (!core)
492                 return 0;
493         debugfs_remove(core->debugfs);
494         core->debugfs = NULL;
495         debugfs_remove(core->debugfs_fwlog);
496         core->debugfs_fwlog = NULL;
497
498         return 0;
499 }
500
501 void vpu_inst_record_flow(struct vpu_inst *inst, u32 flow)
502 {
503         if (!inst)
504                 return;
505
506         inst->flows[inst->flow_idx] = flow;
507         inst->flow_idx = (inst->flow_idx + 1) % (ARRAY_SIZE(inst->flows));
508 }