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