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