vpu_dbg.c (11911B)
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 23struct 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 33static 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 43static 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 52static 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 212static 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 277static 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 325static 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 330static 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 341static 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 362static 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 367static 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 372static 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 380static 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 388static 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 395int 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 420int 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 431int 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 463int 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 475void 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}