xref: /linux/drivers/media/platform/amphion/vpu_dbg.c (revision ae22a94997b8a03dcb3c922857c203246711f9d4)
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 }
509