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