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 vq->num_buffers, 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 vq->num_buffers, 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 < vq->num_buffers; i++) { 143 struct vb2_buffer *vb = vq->bufs[i]; 144 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 145 146 if (vb->state == VB2_BUF_STATE_DEQUEUED) 147 continue; 148 num = scnprintf(str, sizeof(str), 149 "output [%2d] state = %10s, %8s\n", 150 i, vb2_stat_name[vb->state], 151 to_vpu_stat_name(vpu_get_buffer_state(vbuf))); 152 if (seq_write(s, str, num)) 153 return 0; 154 } 155 156 vq = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); 157 for (i = 0; i < vq->num_buffers; i++) { 158 struct vb2_buffer *vb = vq->bufs[i]; 159 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 160 161 if (vb->state == VB2_BUF_STATE_DEQUEUED) 162 continue; 163 num = scnprintf(str, sizeof(str), 164 "capture[%2d] state = %10s, %8s\n", 165 i, vb2_stat_name[vb->state], 166 to_vpu_stat_name(vpu_get_buffer_state(vbuf))); 167 if (seq_write(s, str, num)) 168 return 0; 169 } 170 171 num = scnprintf(str, sizeof(str), "sequence = %d\n", inst->sequence); 172 if (seq_write(s, str, num)) 173 return 0; 174 175 if (inst->use_stream_buffer) { 176 num = scnprintf(str, sizeof(str), "stream_buffer = %d / %d, <%pad, 0x%x>\n", 177 vpu_helper_get_used_space(inst), 178 inst->stream_buffer.length, 179 &inst->stream_buffer.phys, 180 inst->stream_buffer.length); 181 if (seq_write(s, str, num)) 182 return 0; 183 } 184 num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&inst->msg_fifo)); 185 if (seq_write(s, str, num)) 186 return 0; 187 188 num = scnprintf(str, sizeof(str), "flow :\n"); 189 if (seq_write(s, str, num)) 190 return 0; 191 192 mutex_lock(&inst->core->cmd_lock); 193 for (i = 0; i < ARRAY_SIZE(inst->flows); i++) { 194 u32 idx = (inst->flow_idx + i) % (ARRAY_SIZE(inst->flows)); 195 196 if (!inst->flows[idx]) 197 continue; 198 num = scnprintf(str, sizeof(str), "\t[%s] %s\n", 199 inst->flows[idx] >= VPU_MSG_ID_NOOP ? "M" : "C", 200 vpu_id_name(inst->flows[idx])); 201 if (seq_write(s, str, num)) { 202 mutex_unlock(&inst->core->cmd_lock); 203 return 0; 204 } 205 } 206 mutex_unlock(&inst->core->cmd_lock); 207 208 i = 0; 209 while (true) { 210 num = call_vop(inst, get_debug_info, str, sizeof(str), i++); 211 if (num <= 0) 212 break; 213 if (seq_write(s, str, num)) 214 return 0; 215 } 216 217 return 0; 218 } 219 220 static int vpu_dbg_core(struct seq_file *s, void *data) 221 { 222 struct vpu_core *core = s->private; 223 struct vpu_shared_addr *iface = core->iface; 224 char str[128]; 225 int num; 226 227 num = scnprintf(str, sizeof(str), "[%s]\n", vpu_core_type_desc(core->type)); 228 if (seq_write(s, str, num)) 229 return 0; 230 231 num = scnprintf(str, sizeof(str), "boot_region = <%pad, 0x%x>\n", 232 &core->fw.phys, core->fw.length); 233 if (seq_write(s, str, num)) 234 return 0; 235 num = scnprintf(str, sizeof(str), "rpc_region = <%pad, 0x%x> used = 0x%x\n", 236 &core->rpc.phys, core->rpc.length, core->rpc.bytesused); 237 if (seq_write(s, str, num)) 238 return 0; 239 num = scnprintf(str, sizeof(str), "fwlog_region = <%pad, 0x%x>\n", 240 &core->log.phys, core->log.length); 241 if (seq_write(s, str, num)) 242 return 0; 243 244 num = scnprintf(str, sizeof(str), "power %s\n", 245 vpu_iface_get_power_state(core) ? "on" : "off"); 246 if (seq_write(s, str, num)) 247 return 0; 248 num = scnprintf(str, sizeof(str), "state = %d\n", core->state); 249 if (seq_write(s, str, num)) 250 return 0; 251 if (core->state == VPU_CORE_DEINIT) 252 return 0; 253 num = scnprintf(str, sizeof(str), "fw version = %d.%d.%d\n", 254 (core->fw_version >> 16) & 0xff, 255 (core->fw_version >> 8) & 0xff, 256 core->fw_version & 0xff); 257 if (seq_write(s, str, num)) 258 return 0; 259 num = scnprintf(str, sizeof(str), "instances = %d/%d (0x%02lx), %d\n", 260 hweight32(core->instance_mask), 261 core->supported_instance_count, 262 core->instance_mask, 263 core->request_count); 264 if (seq_write(s, str, num)) 265 return 0; 266 num = scnprintf(str, sizeof(str), "kfifo len = 0x%x\n", kfifo_len(&core->msg_fifo)); 267 if (seq_write(s, str, num)) 268 return 0; 269 num = scnprintf(str, sizeof(str), 270 "cmd_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n", 271 iface->cmd_desc->start, 272 iface->cmd_desc->end, 273 iface->cmd_desc->wptr, 274 iface->cmd_desc->rptr); 275 if (seq_write(s, str, num)) 276 return 0; 277 num = scnprintf(str, sizeof(str), 278 "msg_buf:[0x%x, 0x%x], wptr = 0x%x, rptr = 0x%x\n", 279 iface->msg_desc->start, 280 iface->msg_desc->end, 281 iface->msg_desc->wptr, 282 iface->msg_desc->rptr); 283 if (seq_write(s, str, num)) 284 return 0; 285 286 return 0; 287 } 288 289 static int vpu_dbg_fwlog(struct seq_file *s, void *data) 290 { 291 struct vpu_core *core = s->private; 292 struct print_buf_desc *print_buf; 293 int length; 294 u32 rptr; 295 u32 wptr; 296 int ret = 0; 297 298 if (!core->log.virt || core->state == VPU_CORE_DEINIT) 299 return 0; 300 301 print_buf = core->log.virt; 302 rptr = print_buf->read; 303 wptr = print_buf->write; 304 305 if (rptr == wptr) 306 return 0; 307 else if (rptr < wptr) 308 length = wptr - rptr; 309 else 310 length = print_buf->bytes + wptr - rptr; 311 312 if (s->count + length >= s->size) { 313 s->count = s->size; 314 return 0; 315 } 316 317 if (rptr + length >= print_buf->bytes) { 318 int num = print_buf->bytes - rptr; 319 320 if (seq_write(s, print_buf->buffer + rptr, num)) 321 ret = -1; 322 length -= num; 323 rptr = 0; 324 } 325 326 if (length) { 327 if (seq_write(s, print_buf->buffer + rptr, length)) 328 ret = -1; 329 rptr += length; 330 } 331 if (!ret) 332 print_buf->read = rptr; 333 334 return 0; 335 } 336 337 static int vpu_dbg_inst_open(struct inode *inode, struct file *filp) 338 { 339 return single_open(filp, vpu_dbg_instance, inode->i_private); 340 } 341 342 static ssize_t vpu_dbg_inst_write(struct file *file, 343 const char __user *user_buf, size_t size, loff_t *ppos) 344 { 345 struct seq_file *s = file->private_data; 346 struct vpu_inst *inst = s->private; 347 348 vpu_session_debug(inst); 349 350 return size; 351 } 352 353 static ssize_t vpu_dbg_core_write(struct file *file, 354 const char __user *user_buf, size_t size, loff_t *ppos) 355 { 356 struct seq_file *s = file->private_data; 357 struct vpu_core *core = s->private; 358 359 pm_runtime_resume_and_get(core->dev); 360 mutex_lock(&core->lock); 361 if (vpu_iface_get_power_state(core) && !core->request_count) { 362 dev_info(core->dev, "reset\n"); 363 if (!vpu_core_sw_reset(core)) { 364 vpu_core_set_state(core, VPU_CORE_ACTIVE); 365 core->hang_mask = 0; 366 } 367 } 368 mutex_unlock(&core->lock); 369 pm_runtime_put_sync(core->dev); 370 371 return size; 372 } 373 374 static int vpu_dbg_core_open(struct inode *inode, struct file *filp) 375 { 376 return single_open(filp, vpu_dbg_core, inode->i_private); 377 } 378 379 static int vpu_dbg_fwlog_open(struct inode *inode, struct file *filp) 380 { 381 return single_open(filp, vpu_dbg_fwlog, inode->i_private); 382 } 383 384 static const struct file_operations vpu_dbg_inst_fops = { 385 .owner = THIS_MODULE, 386 .open = vpu_dbg_inst_open, 387 .release = single_release, 388 .read = seq_read, 389 .write = vpu_dbg_inst_write, 390 }; 391 392 static const struct file_operations vpu_dbg_core_fops = { 393 .owner = THIS_MODULE, 394 .open = vpu_dbg_core_open, 395 .release = single_release, 396 .read = seq_read, 397 .write = vpu_dbg_core_write, 398 }; 399 400 static const struct file_operations vpu_dbg_fwlog_fops = { 401 .owner = THIS_MODULE, 402 .open = vpu_dbg_fwlog_open, 403 .release = single_release, 404 .read = seq_read, 405 }; 406 407 int vpu_inst_create_dbgfs_file(struct vpu_inst *inst) 408 { 409 struct vpu_dev *vpu; 410 char name[64]; 411 412 if (!inst || !inst->core || !inst->core->vpu) 413 return -EINVAL; 414 415 vpu = inst->core->vpu; 416 if (!vpu->debugfs) 417 return -EINVAL; 418 419 if (inst->debugfs) 420 return 0; 421 422 scnprintf(name, sizeof(name), "instance.%d.%d", inst->core->id, inst->id); 423 inst->debugfs = debugfs_create_file((const char *)name, 424 VERIFY_OCTAL_PERMISSIONS(0644), 425 vpu->debugfs, 426 inst, 427 &vpu_dbg_inst_fops); 428 429 return 0; 430 } 431 432 int vpu_inst_remove_dbgfs_file(struct vpu_inst *inst) 433 { 434 if (!inst) 435 return 0; 436 437 debugfs_remove(inst->debugfs); 438 inst->debugfs = NULL; 439 440 return 0; 441 } 442 443 int vpu_core_create_dbgfs_file(struct vpu_core *core) 444 { 445 struct vpu_dev *vpu; 446 char name[64]; 447 448 if (!core || !core->vpu) 449 return -EINVAL; 450 451 vpu = core->vpu; 452 if (!vpu->debugfs) 453 return -EINVAL; 454 455 if (!core->debugfs) { 456 scnprintf(name, sizeof(name), "core.%d", core->id); 457 core->debugfs = debugfs_create_file((const char *)name, 458 VERIFY_OCTAL_PERMISSIONS(0644), 459 vpu->debugfs, 460 core, 461 &vpu_dbg_core_fops); 462 } 463 if (!core->debugfs_fwlog) { 464 scnprintf(name, sizeof(name), "fwlog.%d", core->id); 465 core->debugfs_fwlog = debugfs_create_file((const char *)name, 466 VERIFY_OCTAL_PERMISSIONS(0444), 467 vpu->debugfs, 468 core, 469 &vpu_dbg_fwlog_fops); 470 } 471 472 return 0; 473 } 474 475 int vpu_core_remove_dbgfs_file(struct vpu_core *core) 476 { 477 if (!core) 478 return 0; 479 debugfs_remove(core->debugfs); 480 core->debugfs = NULL; 481 debugfs_remove(core->debugfs_fwlog); 482 core->debugfs_fwlog = NULL; 483 484 return 0; 485 } 486 487 void vpu_inst_record_flow(struct vpu_inst *inst, u32 flow) 488 { 489 if (!inst) 490 return; 491 492 inst->flows[inst->flow_idx] = flow; 493 inst->flow_idx = (inst->flow_idx + 1) % (ARRAY_SIZE(inst->flows)); 494 } 495