File Index
Files and directories
Sign in
FILE

vpu_dbg.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/platform/amphion/vpu_dbg.c 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
 24struct 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
 34static 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
 44static 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
 54static 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
 61static 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
247static 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
316static 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
364static 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
369static 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
380static 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
401static 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
406static 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
411static 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
419static 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
427static 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
434int 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
459int 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
470int 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
502int 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
514void 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}
~/ Read-only file preview.