brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · 940e5bd Raw
509 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2020-2021 NXP4 */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	else324		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