xref: /linux/drivers/accel/ivpu/ivpu_debugfs.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2020-2024 Intel Corporation
4  */
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 
23 static 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 
30 static 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 
40 static 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 
48 static int fw_version_show(struct seq_file *s, void *v)
49 {
50 	struct ivpu_device *vdev = seq_to_ivpu(s);
51 
52 	seq_printf(s, "%s\n", vdev->fw->version);
53 	return 0;
54 }
55 
56 static int fw_trace_capability_show(struct seq_file *s, void *v)
57 {
58 	struct ivpu_device *vdev = seq_to_ivpu(s);
59 	u64 trace_hw_component_mask;
60 	u32 trace_destination_mask;
61 	int ret;
62 
63 	ret = ivpu_jsm_trace_get_capability(vdev, &trace_destination_mask,
64 					    &trace_hw_component_mask);
65 	if (!ret) {
66 		seq_printf(s,
67 			   "trace_destination_mask:  %#18x\n"
68 			   "trace_hw_component_mask: %#18llx\n",
69 			   trace_destination_mask, trace_hw_component_mask);
70 	}
71 	return 0;
72 }
73 
74 static int fw_trace_config_show(struct seq_file *s, void *v)
75 {
76 	struct ivpu_device *vdev = seq_to_ivpu(s);
77 	/**
78 	 * WA: VPU_JSM_MSG_TRACE_GET_CONFIG command is not working yet,
79 	 * so we use values from vdev->fw instead of calling ivpu_jsm_trace_get_config()
80 	 */
81 	u32 trace_level = vdev->fw->trace_level;
82 	u32 trace_destination_mask = vdev->fw->trace_destination_mask;
83 	u64 trace_hw_component_mask = vdev->fw->trace_hw_component_mask;
84 
85 	seq_printf(s,
86 		   "trace_level:             %#18x\n"
87 		   "trace_destination_mask:  %#18x\n"
88 		   "trace_hw_component_mask: %#18llx\n",
89 		   trace_level, trace_destination_mask, trace_hw_component_mask);
90 
91 	return 0;
92 }
93 
94 static int last_bootmode_show(struct seq_file *s, void *v)
95 {
96 	struct ivpu_device *vdev = seq_to_ivpu(s);
97 
98 	seq_printf(s, "%s\n", (vdev->pm->is_warmboot) ? "warmboot" : "coldboot");
99 
100 	return 0;
101 }
102 
103 static int reset_counter_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_counter));
108 	return 0;
109 }
110 
111 static int reset_pending_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->pm->reset_pending));
116 	return 0;
117 }
118 
119 static int firewall_irq_counter_show(struct seq_file *s, void *v)
120 {
121 	struct ivpu_device *vdev = seq_to_ivpu(s);
122 
123 	seq_printf(s, "%d\n", atomic_read(&vdev->hw->firewall_irq_counter));
124 	return 0;
125 }
126 
127 static const struct drm_debugfs_info vdev_debugfs_list[] = {
128 	{"bo_list", bo_list_show, 0},
129 	{"fw_name", fw_name_show, 0},
130 	{"fw_version", fw_version_show, 0},
131 	{"fw_trace_capability", fw_trace_capability_show, 0},
132 	{"fw_trace_config", fw_trace_config_show, 0},
133 	{"last_bootmode", last_bootmode_show, 0},
134 	{"reset_counter", reset_counter_show, 0},
135 	{"reset_pending", reset_pending_show, 0},
136 	{"firewall_irq_counter", firewall_irq_counter_show, 0},
137 };
138 
139 static int dvfs_mode_get(void *data, u64 *dvfs_mode)
140 {
141 	struct ivpu_device *vdev = (struct ivpu_device *)data;
142 
143 	*dvfs_mode = vdev->fw->dvfs_mode;
144 	return 0;
145 }
146 
147 static int dvfs_mode_set(void *data, u64 dvfs_mode)
148 {
149 	struct ivpu_device *vdev = (struct ivpu_device *)data;
150 
151 	vdev->fw->dvfs_mode = (u32)dvfs_mode;
152 	return pci_try_reset_function(to_pci_dev(vdev->drm.dev));
153 }
154 
155 DEFINE_DEBUGFS_ATTRIBUTE(dvfs_mode_fops, dvfs_mode_get, dvfs_mode_set, "%llu\n");
156 
157 static ssize_t
158 fw_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 
175 static const struct file_operations fw_dyndbg_fops = {
176 	.owner = THIS_MODULE,
177 	.open = simple_open,
178 	.write = fw_dyndbg_fops_write,
179 };
180 
181 static 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 
190 static 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 
195 static ssize_t
196 fw_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_mark_read(vdev);
205 	return size;
206 }
207 
208 static 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 
217 static ssize_t
218 fw_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 
238 static 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 
244 static ssize_t
245 fw_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 
265 static 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 
271 static ssize_t
272 fw_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 
292 static 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 
298 static ssize_t
299 fw_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 
318 static 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 
324 static ssize_t
325 ivpu_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 
343 static const struct file_operations ivpu_force_recovery_fops = {
344 	.owner = THIS_MODULE,
345 	.open = simple_open,
346 	.write = ivpu_force_recovery_fn,
347 };
348 
349 static int ivpu_reset_engine_fn(void *data, u64 val)
350 {
351 	struct ivpu_device *vdev = (struct ivpu_device *)data;
352 
353 	return ivpu_jsm_reset_engine(vdev, (u32)val);
354 }
355 
356 DEFINE_DEBUGFS_ATTRIBUTE(ivpu_reset_engine_fops, NULL, ivpu_reset_engine_fn, "0x%02llx\n");
357 
358 static int ivpu_resume_engine_fn(void *data, u64 val)
359 {
360 	struct ivpu_device *vdev = (struct ivpu_device *)data;
361 
362 	return ivpu_jsm_hws_resume_engine(vdev, (u32)val);
363 }
364 
365 DEFINE_DEBUGFS_ATTRIBUTE(ivpu_resume_engine_fops, NULL, ivpu_resume_engine_fn, "0x%02llx\n");
366 
367 static int dct_active_get(void *data, u64 *active_percent)
368 {
369 	struct ivpu_device *vdev = data;
370 
371 	*active_percent = vdev->pm->dct_active_percent;
372 
373 	return 0;
374 }
375 
376 static int dct_active_set(void *data, u64 active_percent)
377 {
378 	struct ivpu_device *vdev = data;
379 	int ret;
380 
381 	if (active_percent > 100)
382 		return -EINVAL;
383 
384 	ret = ivpu_rpm_get(vdev);
385 	if (ret)
386 		return ret;
387 
388 	if (active_percent)
389 		ret = ivpu_pm_dct_enable(vdev, active_percent);
390 	else
391 		ret = ivpu_pm_dct_disable(vdev);
392 
393 	ivpu_rpm_put(vdev);
394 
395 	return ret;
396 }
397 
398 DEFINE_DEBUGFS_ATTRIBUTE(ivpu_dct_fops, dct_active_get, dct_active_set, "%llu\n");
399 
400 void ivpu_debugfs_init(struct ivpu_device *vdev)
401 {
402 	struct dentry *debugfs_root = vdev->drm.debugfs_root;
403 
404 	drm_debugfs_add_files(&vdev->drm, vdev_debugfs_list, ARRAY_SIZE(vdev_debugfs_list));
405 
406 	debugfs_create_file("force_recovery", 0200, debugfs_root, vdev,
407 			    &ivpu_force_recovery_fops);
408 
409 	debugfs_create_file("dvfs_mode", 0644, debugfs_root, vdev,
410 			    &dvfs_mode_fops);
411 
412 	debugfs_create_file("fw_dyndbg", 0200, debugfs_root, vdev,
413 			    &fw_dyndbg_fops);
414 	debugfs_create_file("fw_log", 0644, debugfs_root, vdev,
415 			    &fw_log_fops);
416 	debugfs_create_file("fw_trace_destination_mask", 0200, debugfs_root, vdev,
417 			    &fw_trace_destination_mask_fops);
418 	debugfs_create_file("fw_trace_hw_comp_mask", 0200, debugfs_root, vdev,
419 			    &fw_trace_hw_comp_mask_fops);
420 	debugfs_create_file("fw_trace_level", 0200, debugfs_root, vdev,
421 			    &fw_trace_level_fops);
422 
423 	debugfs_create_file("reset_engine", 0200, debugfs_root, vdev,
424 			    &ivpu_reset_engine_fops);
425 	debugfs_create_file("resume_engine", 0200, debugfs_root, vdev,
426 			    &ivpu_resume_engine_fops);
427 
428 	if (ivpu_hw_ip_gen(vdev) >= IVPU_HW_IP_40XX) {
429 		debugfs_create_file("fw_profiling_freq_drive", 0200,
430 				    debugfs_root, vdev, &fw_profiling_freq_fops);
431 		debugfs_create_file("dct", 0644, debugfs_root, vdev, &ivpu_dct_fops);
432 	}
433 }
434