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_jsm_msg.h" 18 #include "ivpu_pm.h" 19 20 static inline struct ivpu_device *seq_to_ivpu(struct seq_file *s) 21 { 22 struct drm_debugfs_entry *entry = s->private; 23 24 return to_ivpu_device(entry->dev); 25 } 26 27 static int bo_list_show(struct seq_file *s, void *v) 28 { 29 struct drm_printer p = drm_seq_file_printer(s); 30 struct ivpu_device *vdev = seq_to_ivpu(s); 31 32 ivpu_bo_list(&vdev->drm, &p); 33 34 return 0; 35 } 36 37 static int fw_name_show(struct seq_file *s, void *v) 38 { 39 struct ivpu_device *vdev = seq_to_ivpu(s); 40 41 seq_printf(s, "%s\n", vdev->fw->name); 42 return 0; 43 } 44 45 static int fw_trace_capability_show(struct seq_file *s, void *v) 46 { 47 struct ivpu_device *vdev = seq_to_ivpu(s); 48 u64 trace_hw_component_mask; 49 u32 trace_destination_mask; 50 int ret; 51 52 ret = ivpu_jsm_trace_get_capability(vdev, &trace_destination_mask, 53 &trace_hw_component_mask); 54 if (!ret) { 55 seq_printf(s, 56 "trace_destination_mask: %#18x\n" 57 "trace_hw_component_mask: %#18llx\n", 58 trace_destination_mask, trace_hw_component_mask); 59 } 60 return 0; 61 } 62 63 static int fw_trace_config_show(struct seq_file *s, void *v) 64 { 65 struct ivpu_device *vdev = seq_to_ivpu(s); 66 /** 67 * WA: VPU_JSM_MSG_TRACE_GET_CONFIG command is not working yet, 68 * so we use values from vdev->fw instead of calling ivpu_jsm_trace_get_config() 69 */ 70 u32 trace_level = vdev->fw->trace_level; 71 u32 trace_destination_mask = vdev->fw->trace_destination_mask; 72 u64 trace_hw_component_mask = vdev->fw->trace_hw_component_mask; 73 74 seq_printf(s, 75 "trace_level: %#18x\n" 76 "trace_destination_mask: %#18x\n" 77 "trace_hw_component_mask: %#18llx\n", 78 trace_level, trace_destination_mask, trace_hw_component_mask); 79 80 return 0; 81 } 82 83 static int last_bootmode_show(struct seq_file *s, void *v) 84 { 85 struct ivpu_device *vdev = seq_to_ivpu(s); 86 87 seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot"); 88 89 return 0; 90 } 91 92 static int reset_counter_show(struct seq_file *s, void *v) 93 { 94 struct ivpu_device *vdev = seq_to_ivpu(s); 95 96 seq_printf(s, "%d\n", atomic_read(&vdev->pm->reset_counter)); 97 return 0; 98 } 99 100 static int reset_pending_show(struct seq_file *s, void *v) 101 { 102 struct ivpu_device *vdev = seq_to_ivpu(s); 103 104 seq_printf(s, "%d\n", atomic_read(&vdev->pm->in_reset)); 105 return 0; 106 } 107 108 static const struct drm_debugfs_info vdev_debugfs_list[] = { 109 {"bo_list", bo_list_show, 0}, 110 {"fw_name", fw_name_show, 0}, 111 {"fw_trace_capability", fw_trace_capability_show, 0}, 112 {"fw_trace_config", fw_trace_config_show, 0}, 113 {"last_bootmode", last_bootmode_show, 0}, 114 {"reset_counter", reset_counter_show, 0}, 115 {"reset_pending", reset_pending_show, 0}, 116 }; 117 118 static int fw_log_show(struct seq_file *s, void *v) 119 { 120 struct ivpu_device *vdev = s->private; 121 struct drm_printer p = drm_seq_file_printer(s); 122 123 ivpu_fw_log_print(vdev, true, &p); 124 return 0; 125 } 126 127 static int fw_log_fops_open(struct inode *inode, struct file *file) 128 { 129 return single_open(file, fw_log_show, inode->i_private); 130 } 131 132 static ssize_t 133 fw_log_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 134 { 135 struct seq_file *s = file->private_data; 136 struct ivpu_device *vdev = s->private; 137 138 if (!size) 139 return -EINVAL; 140 141 ivpu_fw_log_clear(vdev); 142 return size; 143 } 144 145 static const struct file_operations fw_log_fops = { 146 .owner = THIS_MODULE, 147 .open = fw_log_fops_open, 148 .write = fw_log_fops_write, 149 .read = seq_read, 150 .llseek = seq_lseek, 151 .release = single_release, 152 }; 153 154 static ssize_t 155 fw_trace_destination_mask_fops_write(struct file *file, const char __user *user_buf, 156 size_t size, loff_t *pos) 157 { 158 struct ivpu_device *vdev = file->private_data; 159 struct ivpu_fw_info *fw = vdev->fw; 160 u32 trace_destination_mask; 161 int ret; 162 163 ret = kstrtou32_from_user(user_buf, size, 0, &trace_destination_mask); 164 if (ret < 0) 165 return ret; 166 167 fw->trace_destination_mask = trace_destination_mask; 168 169 ivpu_jsm_trace_set_config(vdev, fw->trace_level, trace_destination_mask, 170 fw->trace_hw_component_mask); 171 172 return size; 173 } 174 175 static const struct file_operations fw_trace_destination_mask_fops = { 176 .owner = THIS_MODULE, 177 .open = simple_open, 178 .write = fw_trace_destination_mask_fops_write, 179 }; 180 181 static ssize_t 182 fw_trace_hw_comp_mask_fops_write(struct file *file, const char __user *user_buf, 183 size_t size, loff_t *pos) 184 { 185 struct ivpu_device *vdev = file->private_data; 186 struct ivpu_fw_info *fw = vdev->fw; 187 u64 trace_hw_component_mask; 188 int ret; 189 190 ret = kstrtou64_from_user(user_buf, size, 0, &trace_hw_component_mask); 191 if (ret < 0) 192 return ret; 193 194 fw->trace_hw_component_mask = trace_hw_component_mask; 195 196 ivpu_jsm_trace_set_config(vdev, fw->trace_level, fw->trace_destination_mask, 197 trace_hw_component_mask); 198 199 return size; 200 } 201 202 static const struct file_operations fw_trace_hw_comp_mask_fops = { 203 .owner = THIS_MODULE, 204 .open = simple_open, 205 .write = fw_trace_hw_comp_mask_fops_write, 206 }; 207 208 static ssize_t 209 fw_trace_level_fops_write(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 210 { 211 struct ivpu_device *vdev = file->private_data; 212 struct ivpu_fw_info *fw = vdev->fw; 213 u32 trace_level; 214 int ret; 215 216 ret = kstrtou32_from_user(user_buf, size, 0, &trace_level); 217 if (ret < 0) 218 return ret; 219 220 fw->trace_level = trace_level; 221 222 ivpu_jsm_trace_set_config(vdev, trace_level, fw->trace_destination_mask, 223 fw->trace_hw_component_mask); 224 225 return size; 226 } 227 228 static const struct file_operations fw_trace_level_fops = { 229 .owner = THIS_MODULE, 230 .open = simple_open, 231 .write = fw_trace_level_fops_write, 232 }; 233 234 static ssize_t 235 ivpu_reset_engine_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 236 { 237 struct ivpu_device *vdev = file->private_data; 238 239 if (!size) 240 return -EINVAL; 241 242 if (ivpu_jsm_reset_engine(vdev, DRM_IVPU_ENGINE_COMPUTE)) 243 return -ENODEV; 244 if (ivpu_jsm_reset_engine(vdev, DRM_IVPU_ENGINE_COPY)) 245 return -ENODEV; 246 247 return size; 248 } 249 250 static ssize_t 251 ivpu_force_recovery_fn(struct file *file, const char __user *user_buf, size_t size, loff_t *pos) 252 { 253 struct ivpu_device *vdev = file->private_data; 254 255 if (!size) 256 return -EINVAL; 257 258 ivpu_pm_schedule_recovery(vdev); 259 return size; 260 } 261 262 static const struct file_operations ivpu_force_recovery_fops = { 263 .owner = THIS_MODULE, 264 .open = simple_open, 265 .write = ivpu_force_recovery_fn, 266 }; 267 268 static const struct file_operations ivpu_reset_engine_fops = { 269 .owner = THIS_MODULE, 270 .open = simple_open, 271 .write = ivpu_reset_engine_fn, 272 }; 273 274 void ivpu_debugfs_init(struct ivpu_device *vdev) 275 { 276 struct dentry *debugfs_root = vdev->drm.debugfs_root; 277 278 drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list)); 279 280 debugfs_create_file("force_recovery", 0200, debugfs_root, vdev, 281 &ivpu_force_recovery_fops); 282 283 debugfs_create_file("fw_log", 0644, debugfs_root, vdev, 284 &fw_log_fops); 285 debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev, 286 &fw_trace_destination_mask_fops); 287 debugfs_create_file("fw_trace_hw_comp_mask", 0200, debugfs_root, vdev, 288 &fw_trace_hw_comp_mask_fops); 289 debugfs_create_file("fw_trace_level", 0200, debugfs_root, vdev, 290 &fw_trace_level_fops); 291 292 debugfs_create_file("reset_engine", 0200, debugfs_root, vdev, 293 &ivpu_reset_engine_fops); 294 } 295