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 24 struct 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 34 static 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 44 static 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 54 static 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 61 static 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 247 static 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 316 static 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 364 static 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 369 static 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 380 static 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 401 static 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 406 static 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 411 static 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 419 static 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 427 static 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 434 int 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 459 int 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 470 int 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 502 int 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 514 void 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 } 522