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