Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 524 lines 14 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2020-2026 Intel Corporation 4 */ 5 6#include <linux/debugfs.h> 7#include <linux/fault-inject.h> 8 9#include <drm/drm_debugfs.h> 10#include <drm/drm_file.h> 11#include <drm/drm_print.h> 12 13#include <uapi/drm/ivpu_accel.h> 14 15#include "ivpu_debugfs.h" 16#include "ivpu_drv.h" 17#include "ivpu_fw.h" 18#include "ivpu_fw_log.h" 19#include "ivpu_gem.h" 20#include "ivpu_hw.h" 21#include "ivpu_jsm_msg.h" 22#include "ivpu_pm.h" 23#include "vpu_boot_api.h" 24 25static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) 26{ 27 struct drm_debugfs_entry *entry = s->private; 28 29 return to_ivpu_device(entry->dev); 30} 31 32static int bo_list_show(struct seq_file *s, void *v) 33{ 34 struct drm_printer p = drm_seq_file_printer(s); 35 struct ivpu_device *vdev = seq_to_ivpu(s); 36 37 ivpu_bo_list(&vdev->drm, &p); 38 39 return 0; 40} 41 42static int fw_name_show(struct seq_file *s, void *v) 43{ 44 struct ivpu_device *vdev = seq_to_ivpu(s); 45 46 seq_printf(s, "%s\n", vdev->fw->name); 47 return 0; 48} 49 50static int fw_version_show(struct seq_file *s, void *v) 51{ 52 struct ivpu_device *vdev = seq_to_ivpu(s); 53 54 seq_printf(s, "%s\n", vdev->fw->version); 55 return 0; 56} 57 58static int fw_trace_capability_show(struct seq_file *s, void *v) 59{ 60 struct ivpu_device *vdev = seq_to_ivpu(s); 61 u64 trace_hw_component_mask; 62 u32 trace_destination_mask; 63 int ret; 64 65 ret = ivpu_jsm_trace_get_capability(vdev, &trace_destination_mask, 66 &trace_hw_component_mask); 67 if (!ret) { 68 seq_printf(s, 69 "trace_destination_mask: %#18x\n" 70 "trace_hw_component_mask: %#18llx\n", 71 trace_destination_mask, trace_hw_component_mask); 72 } 73 return 0; 74} 75 76static int fw_trace_config_show(struct seq_file *s, void *v) 77{ 78 struct ivpu_device *vdev = seq_to_ivpu(s); 79 /** 80 * WA: VPU_JSM_MSG_TRACE_GET_CONFIG command is not working yet, 81 * so we use values from vdev->fw instead of calling ivpu_jsm_trace_get_config() 82 */ 83 u32 trace_level = vdev->fw->trace_level; 84 u32 trace_destination_mask = vdev->fw->trace_destination_mask; 85 u64 trace_hw_component_mask = vdev->fw->trace_hw_component_mask; 86 87 seq_printf(s, 88 "trace_level: %#18x\n" 89 "trace_destination_mask: %#18x\n" 90 "trace_hw_component_mask: %#18llx\n", 91 trace_level, trace_destination_mask, trace_hw_component_mask); 92 93 return 0; 94} 95 96static int last_bootmode_show(struct seq_file *s, void *v) 97{ 98 struct ivpu_device *vdev = seq_to_ivpu(s); 99 100 seq_printf(s, "%s\n", (vdev->fw->last_boot_mode == VPU_BOOT_TYPE_WARMBOOT) ? 101 "warm boot" : "cold boot"); 102 103 return 0; 104} 105 106static int reset_counter_show(struct seq_file *s, void *v) 107{ 108 struct ivpu_device *vdev = seq_to_ivpu(s); 109 110 seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_counter)); 111 return 0; 112} 113 114static int reset_pending_show(struct seq_file *s, void *v) 115{ 116 struct ivpu_device *vdev = seq_to_ivpu(s); 117 118 seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_pending)); 119 return 0; 120} 121 122static int firewall_irq_counter_show(struct seq_file *s, void *v) 123{ 124 struct ivpu_device *vdev = seq_to_ivpu(s); 125 126 seq_printf(s, "%d\n", atomic_read(&vdev->hw->firewall_irq_counter)); 127 return 0; 128} 129 130static int engine_reset_counter_show(struct seq_file *s, void *v) 131{ 132 struct ivpu_device *vdev = seq_to_ivpu(s); 133 134 seq_printf(s, "%d\n", atomic_read(&vdev->pm->engine_reset_counter)); 135 return 0; 136} 137 138static const struct drm_debugfs_info vdev_debugfs_list[] = { 139 {"bo_list", bo_list_show, 0}, 140 {"fw_name", fw_name_show, 0}, 141 {"fw_version", fw_version_show, 0}, 142 {"fw_trace_capability", fw_trace_capability_show, 0}, 143 {"fw_trace_config", fw_trace_config_show, 0}, 144 {"last_bootmode", last_bootmode_show, 0}, 145 {"reset_counter", reset_counter_show, 0}, 146 {"reset_pending", reset_pending_show, 0}, 147 {"firewall_irq_counter", firewall_irq_counter_show, 0}, 148 {"engine_reset_counter", engine_reset_counter_show, 0}, 149}; 150 151static int dvfs_mode_get(void *data, u64 *dvfs_mode) 152{ 153 struct ivpu_device *vdev = (struct ivpu_device *)data; 154 155 *dvfs_mode = vdev->fw->dvfs_mode; 156 return 0; 157} 158 159static int dvfs_mode_set(void *data, u64 dvfs_mode) 160{ 161 struct ivpu_device *vdev = (struct ivpu_device *)data; 162 163 vdev->fw->dvfs_mode = (u32)dvfs_mode; 164 return pci_try_reset_function(to_pci_dev(vdev->drm.dev)); 165} 166 167DEFINE_DEBUGFS_ATTRIBUTE(dvfs_mode_fops, dvfs_mode_get, dvfs_mode_set, "%llu\n"); 168 169static ssize_t 170fw_dyndbg_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 171{ 172 struct ivpu_device *vdev = file->private_data; 173 char buffer[VPU_DYNDBG_CMD_MAX_LEN] = {}; 174 int ret; 175 176 if (size >= VPU_DYNDBG_CMD_MAX_LEN) 177 return -EINVAL; 178 179 ret = strncpy_from_user(buffer, user_buf, size); 180 if (ret < 0) 181 return ret; 182 183 ivpu_jsm_dyndbg_control(vdev, buffer, size); 184 return size; 185} 186 187static const struct file_operations fw_dyndbg_fops = { 188 .owner = THIS_MODULE, 189 .open = simple_open, 190 .write = fw_dyndbg_fops_write, 191}; 192 193static int fw_log_show(struct seq_file *s, void *v) 194{ 195 struct ivpu_device *vdev = s->private; 196 struct drm_printer p = drm_seq_file_printer(s); 197 198 ivpu_fw_log_print(vdev, true, &p); 199 return 0; 200} 201 202static int fw_log_fops_open(struct inode *inode, struct file *file) 203{ 204 return single_open(file, fw_log_show, inode->i_private); 205} 206 207static ssize_t 208fw_log_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 209{ 210 struct seq_file *s = file->private_data; 211 struct ivpu_device *vdev = s->private; 212 213 if (!size) 214 return -EINVAL; 215 216 ivpu_fw_log_mark_read(vdev); 217 return size; 218} 219 220static const struct file_operations fw_log_fops = { 221 .owner = THIS_MODULE, 222 .open = fw_log_fops_open, 223 .write = fw_log_fops_write, 224 .read = seq_read, 225 .llseek = seq_lseek, 226 .release = single_release, 227}; 228 229static ssize_t 230fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, 231 size_t size, loff_t *pos) 232{ 233 struct ivpu_device *vdev = file->private_data; 234 bool enable; 235 int ret; 236 237 ret = kstrtobool_from_user(user_buf, size, &enable); 238 if (ret < 0) 239 return ret; 240 241 ivpu_hw_profiling_freq_drive(vdev, enable); 242 243 ret = pci_try_reset_function(to_pci_dev(vdev->drm.dev)); 244 if (ret) 245 return ret; 246 247 return size; 248} 249 250static const struct file_operations fw_profiling_freq_fops = { 251 .owner = THIS_MODULE, 252 .open = simple_open, 253 .write = fw_profiling_freq_fops_write, 254}; 255 256static ssize_t 257fw_trace_destination_mask_fops_write(struct file *file, const char __user *user_buf, 258 size_t size, loff_t *pos) 259{ 260 struct ivpu_device *vdev = file->private_data; 261 struct ivpu_fw_info *fw = vdev->fw; 262 u32 trace_destination_mask; 263 int ret; 264 265 ret = kstrtou32_from_user(user_buf, size, 0, &trace_destination_mask); 266 if (ret < 0) 267 return ret; 268 269 fw->trace_destination_mask = trace_destination_mask; 270 271 ivpu_jsm_trace_set_config(vdev, fw->trace_level, trace_destination_mask, 272 fw->trace_hw_component_mask); 273 274 return size; 275} 276 277static const struct file_operations fw_trace_destination_mask_fops = { 278 .owner = THIS_MODULE, 279 .open = simple_open, 280 .write = fw_trace_destination_mask_fops_write, 281}; 282 283static ssize_t 284fw_trace_hw_comp_mask_fops_write(struct file *file, const char __user *user_buf, 285 size_t size, loff_t *pos) 286{ 287 struct ivpu_device *vdev = file->private_data; 288 struct ivpu_fw_info *fw = vdev->fw; 289 u64 trace_hw_component_mask; 290 int ret; 291 292 ret = kstrtou64_from_user(user_buf, size, 0, &trace_hw_component_mask); 293 if (ret < 0) 294 return ret; 295 296 fw->trace_hw_component_mask = trace_hw_component_mask; 297 298 ivpu_jsm_trace_set_config(vdev, fw->trace_level, fw->trace_destination_mask, 299 trace_hw_component_mask); 300 301 return size; 302} 303 304static const struct file_operations fw_trace_hw_comp_mask_fops = { 305 .owner = THIS_MODULE, 306 .open = simple_open, 307 .write = fw_trace_hw_comp_mask_fops_write, 308}; 309 310static ssize_t 311fw_trace_level_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 312{ 313 struct ivpu_device *vdev = file->private_data; 314 struct ivpu_fw_info *fw = vdev->fw; 315 u32 trace_level; 316 int ret; 317 318 ret = kstrtou32_from_user(user_buf, size, 0, &trace_level); 319 if (ret < 0) 320 return ret; 321 322 fw->trace_level = trace_level; 323 324 ivpu_jsm_trace_set_config(vdev, trace_level, fw->trace_destination_mask, 325 fw->trace_hw_component_mask); 326 327 return size; 328} 329 330static const struct file_operations fw_trace_level_fops = { 331 .owner = THIS_MODULE, 332 .open = simple_open, 333 .write = fw_trace_level_fops_write, 334}; 335 336static ssize_t 337ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 338{ 339 struct ivpu_device *vdev = file->private_data; 340 int ret; 341 342 if (!size) 343 return -EINVAL; 344 345 ret = ivpu_rpm_get(vdev); 346 if (ret < 0) 347 return ret; 348 349 ivpu_pm_trigger_recovery(vdev, "debugfs"); 350 flush_work(&vdev->pm->recovery_work); 351 ivpu_rpm_put(vdev); 352 return size; 353} 354 355static const struct file_operations ivpu_force_recovery_fops = { 356 .owner = THIS_MODULE, 357 .open = simple_open, 358 .write = ivpu_force_recovery_fn, 359}; 360 361static int ivpu_reset_engine_fn(void *data, u64 val) 362{ 363 struct ivpu_device *vdev = (struct ivpu_device *)data; 364 struct vpu_jsm_msg resp; 365 366 return ivpu_jsm_reset_engine(vdev, (u32)val, &resp); 367} 368 369DEFINE_DEBUGFS_ATTRIBUTE(ivpu_reset_engine_fops, NULL, ivpu_reset_engine_fn, "0x%02llx\n"); 370 371static int ivpu_resume_engine_fn(void *data, u64 val) 372{ 373 struct ivpu_device *vdev = (struct ivpu_device *)data; 374 375 return ivpu_jsm_hws_resume_engine(vdev, (u32)val); 376} 377 378DEFINE_DEBUGFS_ATTRIBUTE(ivpu_resume_engine_fops, NULL, ivpu_resume_engine_fn, "0x%02llx\n"); 379 380static int dct_active_get(void *data, u64 *active_percent) 381{ 382 struct ivpu_device *vdev = data; 383 384 *active_percent = vdev->pm->dct_active_percent; 385 386 return 0; 387} 388 389static int dct_active_set(void *data, u64 active_percent) 390{ 391 struct ivpu_device *vdev = data; 392 int ret; 393 394 if (active_percent > 100) 395 return -EINVAL; 396 397 ret = ivpu_rpm_get(vdev); 398 if (ret < 0) 399 return ret; 400 401 if (active_percent) 402 ret = ivpu_pm_dct_enable(vdev, active_percent); 403 else 404 ret = ivpu_pm_dct_disable(vdev); 405 406 ivpu_rpm_put(vdev); 407 408 return ret; 409} 410 411DEFINE_DEBUGFS_ATTRIBUTE(ivpu_dct_fops, dct_active_get, dct_active_set, "%llu\n"); 412 413static void print_priority_band(struct seq_file *s, struct ivpu_hw_info *hw, 414 int band, const char *name) 415{ 416 seq_printf(s, "%-9s: grace_period %9u process_grace_period %9u process_quantum %9u\n", 417 name, 418 hw->hws.grace_period[band], 419 hw->hws.process_grace_period[band], 420 hw->hws.process_quantum[band]); 421} 422 423static int priority_bands_show(struct seq_file *s, void *v) 424{ 425 struct ivpu_device *vdev = s->private; 426 struct ivpu_hw_info *hw = vdev->hw; 427 428 print_priority_band(s, hw, VPU_JOB_SCHEDULING_PRIORITY_BAND_IDLE, "Idle"); 429 print_priority_band(s, hw, VPU_JOB_SCHEDULING_PRIORITY_BAND_NORMAL, "Normal"); 430 print_priority_band(s, hw, VPU_JOB_SCHEDULING_PRIORITY_BAND_FOCUS, "Focus"); 431 print_priority_band(s, hw, VPU_JOB_SCHEDULING_PRIORITY_BAND_REALTIME, "Realtime"); 432 433 return 0; 434} 435 436static int priority_bands_fops_open(struct inode *inode, struct file *file) 437{ 438 return single_open(file, priority_bands_show, inode->i_private); 439} 440 441static ssize_t 442priority_bands_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 443{ 444 struct seq_file *s = file->private_data; 445 struct ivpu_device *vdev = s->private; 446 char buf[64]; 447 u32 grace_period; 448 u32 process_grace_period; 449 u32 process_quantum; 450 u32 band; 451 int ret; 452 453 if (size >= sizeof(buf)) 454 return -EINVAL; 455 456 ret = simple_write_to_buffer(buf, sizeof(buf) - 1, pos, user_buf, size); 457 if (ret < 0) 458 return ret; 459 460 buf[ret] = '\0'; 461 ret = sscanf(buf, "%u %u %u %u", &band, &grace_period, &process_grace_period, 462 &process_quantum); 463 if (ret != 4) 464 return -EINVAL; 465 466 if (band >= VPU_JOB_SCHEDULING_PRIORITY_BAND_COUNT) 467 return -EINVAL; 468 469 vdev->hw->hws.grace_period[band] = grace_period; 470 vdev->hw->hws.process_grace_period[band] = process_grace_period; 471 vdev->hw->hws.process_quantum[band] = process_quantum; 472 473 return size; 474} 475 476static const struct file_operations ivpu_hws_priority_bands_fops = { 477 .owner = THIS_MODULE, 478 .open = priority_bands_fops_open, 479 .write = priority_bands_fops_write, 480 .read = seq_read, 481 .llseek = seq_lseek, 482 .release = single_release, 483}; 484 485void ivpu_debugfs_init(struct ivpu_device *vdev) 486{ 487 struct dentry *debugfs_root = vdev->drm.debugfs_root; 488 489 drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list)); 490 491 debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, 492 &ivpu_force_recovery_fops); 493 494 debugfs_create_file("dvfs_mode", 0644, debugfs_root, vdev, 495 &dvfs_mode_fops); 496 497 debugfs_create_file("fw_dyndbg", 0200, debugfs_root, vdev, 498 &fw_dyndbg_fops); 499 debugfs_create_file("fw_log", 0644, debugfs_root, vdev, 500 &fw_log_fops); 501 debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, 502 &fw_trace_destination_mask_fops); 503 debugfs_create_file("fw_trace_hw_comp_mask", 0200, debugfs_root, vdev, 504 &fw_trace_hw_comp_mask_fops); 505 debugfs_create_file("fw_trace_level", 0200, debugfs_root, vdev, 506 &fw_trace_level_fops); 507 debugfs_create_file("hws_priority_bands", 0200, debugfs_root, vdev, 508 &ivpu_hws_priority_bands_fops); 509 510 debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, 511 &ivpu_reset_engine_fops); 512 debugfs_create_file("resume_engine", 0200, debugfs_root, vdev, 513 &ivpu_resume_engine_fops); 514 515 if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX) { 516 debugfs_create_file("fw_profiling_freq_drive", 0200, 517 debugfs_root, vdev, &fw_profiling_freq_fops); 518 debugfs_create_file("dct", 0644, debugfs_root, vdev, &ivpu_dct_fops); 519 } 520 521#ifdef CONFIG_FAULT_INJECTION 522 fault_create_debugfs_attr("fail_hw", debugfs_root, &ivpu_hw_failure); 523#endif 524}