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