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