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};
52
53static 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
60static 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
234static 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
303static 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
351static 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
356static 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
367static 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
388static 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
393static 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
398static 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
406static 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
414static 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
421int 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
446int 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
457int 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
489int 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
501void 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