1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020-2023 Intel Corporation 4 */ 5 6 #include <drm/drm_debugfs.h> 7 #include <drm/drm_file.h> 8 #include <drm/drm_print.h> 9 10 #include <uapi/drm/ivpu_accel.h> 11 12 #include "ivpu_debugfs.h" 13 #include "ivpu_drv.h" 14 #include "ivpu_fw.h" 15 #include "ivpu_fw_log.h" 16 #include "ivpu_gem.h" 17 #include "ivpu_hw.h" 18 #include "ivpu_jsm_msg.h" 19 #include "ivpu_pm.h" 20 21 static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) 22 { 23 struct drm_debugfs_entry *entry = s->private; 24 25 return to_ivpu_device(entry->dev); 26 } 27 28 static int bo_list_show(struct seq_file *s, void *v) 29 { 30 struct drm_printer p = drm_seq_file_printer(s); 31 struct ivpu_device *vdev = seq_to_ivpu(s); 32 33 ivpu_bo_list(&vdev->drm, &p); 34 35 return 0; 36 } 37 38 static int fw_name_show(struct seq_file *s, void *v) 39 { 40 struct ivpu_device *vdev = seq_to_ivpu(s); 41 42 seq_printf(s, "%s\n", vdev->fw->name); 43 return 0; 44 } 45 46 static int fw_trace_capability_show(struct seq_file *s, void *v) 47 { 48 struct ivpu_device *vdev = seq_to_ivpu(s); 49 u64 trace_hw_component_mask; 50 u32 trace_destination_mask; 51 int ret; 52 53 ret = ivpu_jsm_trace_get_capability(vdev, &trace_destination_mask, 54 &trace_hw_component_mask); 55 if (!ret) { 56 seq_printf(s, 57 "trace_destination_mask: %#18x\n" 58 "trace_hw_component_mask: %#18llx\n", 59 trace_destination_mask, trace_hw_component_mask); 60 } 61 return 0; 62 } 63 64 static int fw_trace_config_show(struct seq_file *s, void *v) 65 { 66 struct ivpu_device *vdev = seq_to_ivpu(s); 67 /** 68 * WA: VPU_JSM_MSG_TRACE_GET_CONFIG command is not working yet, 69 * so we use values from vdev->fw instead of calling ivpu_jsm_trace_get_config() 70 */ 71 u32 trace_level = vdev->fw->trace_level; 72 u32 trace_destination_mask = vdev->fw->trace_destination_mask; 73 u64 trace_hw_component_mask = vdev->fw->trace_hw_component_mask; 74 75 seq_printf(s, 76 "trace_level: %#18x\n" 77 "trace_destination_mask: %#18x\n" 78 "trace_hw_component_mask: %#18llx\n", 79 trace_level, trace_destination_mask, trace_hw_component_mask); 80 81 return 0; 82 } 83 84 static int last_bootmode_show(struct seq_file *s, void *v) 85 { 86 struct ivpu_device *vdev = seq_to_ivpu(s); 87 88 seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot"); 89 90 return 0; 91 } 92 93 static int reset_counter_show(struct seq_file *s, void *v) 94 { 95 struct ivpu_device *vdev = seq_to_ivpu(s); 96 97 seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_counter)); 98 return 0; 99 } 100 101 static int reset_pending_show(struct seq_file *s, void *v) 102 { 103 struct ivpu_device *vdev = seq_to_ivpu(s); 104 105 seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); 106 return 0; 107 } 108 109 static const struct drm_debugfs_info vdev_debugfs_list[] = { 110 {"bo_list", bo_list_show, 0}, 111 {"fw_name", fw_name_show, 0}, 112 {"fw_trace_capability", fw_trace_capability_show, 0}, 113 {"fw_trace_config", fw_trace_config_show, 0}, 114 {"last_bootmode", last_bootmode_show, 0}, 115 {"reset_counter", reset_counter_show, 0}, 116 {"reset_pending", reset_pending_show, 0}, 117 }; 118 119 static ssize_t 120 dvfs_mode_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 121 { 122 struct ivpu_device *vdev = file->private_data; 123 struct ivpu_fw_info *fw = vdev->fw; 124 u32 dvfs_mode; 125 int ret; 126 127 ret = kstrtou32_from_user(user_buf, size, 0, &dvfs_mode); 128 if (ret < 0) 129 return ret; 130 131 fw->dvfs_mode = dvfs_mode; 132 133 ivpu_pm_schedule_recovery(vdev); 134 135 return size; 136 } 137 138 static const struct file_operations dvfs_mode_fops = { 139 .owner = THIS_MODULE, 140 .open = simple_open, 141 .write = dvfs_mode_fops_write, 142 }; 143 144 static int fw_log_show(struct seq_file *s, void *v) 145 { 146 struct ivpu_device *vdev = s->private; 147 struct drm_printer p = drm_seq_file_printer(s); 148 149 ivpu_fw_log_print(vdev, true, &p); 150 return 0; 151 } 152 153 static int fw_log_fops_open(struct inode *inode, struct file *file) 154 { 155 return single_open(file, fw_log_show, inode->i_private); 156 } 157 158 static ssize_t 159 fw_log_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 160 { 161 struct seq_file *s = file->private_data; 162 struct ivpu_device *vdev = s->private; 163 164 if (!size) 165 return -EINVAL; 166 167 ivpu_fw_log_clear(vdev); 168 return size; 169 } 170 171 static const struct file_operations fw_log_fops = { 172 .owner = THIS_MODULE, 173 .open = fw_log_fops_open, 174 .write = fw_log_fops_write, 175 .read = seq_read, 176 .llseek = seq_lseek, 177 .release = single_release, 178 }; 179 180 static ssize_t 181 fw_profiling_freq_fops_write(struct file *file, const char __user *user_buf, 182 size_t size, loff_t *pos) 183 { 184 struct ivpu_device *vdev = file->private_data; 185 bool enable; 186 int ret; 187 188 ret = kstrtobool_from_user(user_buf, size, &enable); 189 if (ret < 0) 190 return ret; 191 192 ivpu_hw_profiling_freq_drive(vdev, enable); 193 ivpu_pm_schedule_recovery(vdev); 194 195 return size; 196 } 197 198 static const struct file_operations fw_profiling_freq_fops = { 199 .owner = THIS_MODULE, 200 .open = simple_open, 201 .write = fw_profiling_freq_fops_write, 202 }; 203 204 static ssize_t 205 fw_trace_destination_mask_fops_write(struct file *file, const char __user *user_buf, 206 size_t size, loff_t *pos) 207 { 208 struct ivpu_device *vdev = file->private_data; 209 struct ivpu_fw_info *fw = vdev->fw; 210 u32 trace_destination_mask; 211 int ret; 212 213 ret = kstrtou32_from_user(user_buf, size, 0, &trace_destination_mask); 214 if (ret < 0) 215 return ret; 216 217 fw->trace_destination_mask = trace_destination_mask; 218 219 ivpu_jsm_trace_set_config(vdev, fw->trace_level, trace_destination_mask, 220 fw->trace_hw_component_mask); 221 222 return size; 223 } 224 225 static const struct file_operations fw_trace_destination_mask_fops = { 226 .owner = THIS_MODULE, 227 .open = simple_open, 228 .write = fw_trace_destination_mask_fops_write, 229 }; 230 231 static ssize_t 232 fw_trace_hw_comp_mask_fops_write(struct file *file, const char __user *user_buf, 233 size_t size, loff_t *pos) 234 { 235 struct ivpu_device *vdev = file->private_data; 236 struct ivpu_fw_info *fw = vdev->fw; 237 u64 trace_hw_component_mask; 238 int ret; 239 240 ret = kstrtou64_from_user(user_buf, size, 0, &trace_hw_component_mask); 241 if (ret < 0) 242 return ret; 243 244 fw->trace_hw_component_mask = trace_hw_component_mask; 245 246 ivpu_jsm_trace_set_config(vdev, fw->trace_level, fw->trace_destination_mask, 247 trace_hw_component_mask); 248 249 return size; 250 } 251 252 static const struct file_operations fw_trace_hw_comp_mask_fops = { 253 .owner = THIS_MODULE, 254 .open = simple_open, 255 .write = fw_trace_hw_comp_mask_fops_write, 256 }; 257 258 static ssize_t 259 fw_trace_level_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 260 { 261 struct ivpu_device *vdev = file->private_data; 262 struct ivpu_fw_info *fw = vdev->fw; 263 u32 trace_level; 264 int ret; 265 266 ret = kstrtou32_from_user(user_buf, size, 0, &trace_level); 267 if (ret < 0) 268 return ret; 269 270 fw->trace_level = trace_level; 271 272 ivpu_jsm_trace_set_config(vdev, trace_level, fw->trace_destination_mask, 273 fw->trace_hw_component_mask); 274 275 return size; 276 } 277 278 static const struct file_operations fw_trace_level_fops = { 279 .owner = THIS_MODULE, 280 .open = simple_open, 281 .write = fw_trace_level_fops_write, 282 }; 283 284 static ssize_t 285 ivpu_reset_engine_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 286 { 287 struct ivpu_device *vdev = file->private_data; 288 289 if (!size) 290 return -EINVAL; 291 292 if (ivpu_jsm_reset_engine(vdev, DRM_IVPU_ENGINE_COMPUTE)) 293 return -ENODEV; 294 if (ivpu_jsm_reset_engine(vdev, DRM_IVPU_ENGINE_COPY)) 295 return -ENODEV; 296 297 return size; 298 } 299 300 static ssize_t 301 ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 302 { 303 struct ivpu_device *vdev = file->private_data; 304 305 if (!size) 306 return -EINVAL; 307 308 ivpu_pm_schedule_recovery(vdev); 309 return size; 310 } 311 312 static const struct file_operations ivpu_force_recovery_fops = { 313 .owner = THIS_MODULE, 314 .open = simple_open, 315 .write = ivpu_force_recovery_fn, 316 }; 317 318 static const struct file_operations ivpu_reset_engine_fops = { 319 .owner = THIS_MODULE, 320 .open = simple_open, 321 .write = ivpu_reset_engine_fn, 322 }; 323 324 void ivpu_debugfs_init(struct ivpu_device *vdev) 325 { 326 struct dentry *debugfs_root = vdev->drm.debugfs_root; 327 328 drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list)); 329 330 debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, 331 &ivpu_force_recovery_fops); 332 333 debugfs_create_file("dvfs_mode", 0200, debugfs_root, vdev, 334 &dvfs_mode_fops); 335 336 debugfs_create_file("fw_log", 0644, debugfs_root, vdev, 337 &fw_log_fops); 338 debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, 339 &fw_trace_destination_mask_fops); 340 debugfs_create_file("fw_trace_hw_comp_mask", 0200, debugfs_root, vdev, 341 &fw_trace_hw_comp_mask_fops); 342 debugfs_create_file("fw_trace_level", 0200, debugfs_root, vdev, 343 &fw_trace_level_fops); 344 345 debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, 346 &ivpu_reset_engine_fops); 347 348 if (ivpu_hw_gen(vdev) >= IVPU_HW_40XX) 349 debugfs_create_file("fw_profiling_freq_drive", 0200, 350 debugfs_root, vdev, &fw_profiling_freq_fops); 351 } 352