xref: /linux/drivers/gpu/drm/xe/xe_gt_sriov_pf_debugfs.c (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2023-2024 Intel Corporation
4  */
5 
6 #include <linux/debugfs.h>
7 
8 #include <drm/drm_print.h>
9 #include <drm/drm_debugfs.h>
10 
11 #include "xe_bo.h"
12 #include "xe_debugfs.h"
13 #include "xe_device.h"
14 #include "xe_gt.h"
15 #include "xe_gt_debugfs.h"
16 #include "xe_gt_sriov_pf_config.h"
17 #include "xe_gt_sriov_pf_control.h"
18 #include "xe_gt_sriov_pf_debugfs.h"
19 #include "xe_gt_sriov_pf_helpers.h"
20 #include "xe_gt_sriov_pf_migration.h"
21 #include "xe_gt_sriov_pf_monitor.h"
22 #include "xe_gt_sriov_pf_policy.h"
23 #include "xe_gt_sriov_pf_service.h"
24 #include "xe_pm.h"
25 #include "xe_sriov_pf.h"
26 #include "xe_sriov_pf_provision.h"
27 
28 /*
29  *      /sys/kernel/debug/dri/BDF/
30  *      ├── sriov		# d_inode->i_private = (xe_device*)
31  *      │   ├── pf		# d_inode->i_private = (xe_device*)
32  *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
33  *      │   │   │   ├── gt0	# d_inode->i_private = (xe_gt*)
34  *      │   │   │   ├── gt1	# d_inode->i_private = (xe_gt*)
35  *      │   │   ├── tile1
36  *      │   │   │   :
37  *      │   ├── vf1		# d_inode->i_private = VFID(1)
38  *      │   │   ├── tile0	# d_inode->i_private = (xe_tile*)
39  *      │   │   │   ├── gt0	# d_inode->i_private = (xe_gt*)
40  *      │   │   │   ├── gt1	# d_inode->i_private = (xe_gt*)
41  *      │   │   ├── tile1
42  *      │   │   │   :
43  *      :   :
44  *      │   ├── vfN		# d_inode->i_private = VFID(N)
45  */
46 
47 static void *extract_priv(struct dentry *d)
48 {
49 	return d->d_inode->i_private;
50 }
51 
52 static struct xe_gt *extract_gt(struct dentry *d)
53 {
54 	return extract_priv(d);
55 }
56 
57 static struct xe_device *extract_xe(struct dentry *d)
58 {
59 	return extract_priv(d->d_parent->d_parent->d_parent);
60 }
61 
62 static unsigned int extract_vfid(struct dentry *d)
63 {
64 	void *priv = extract_priv(d->d_parent->d_parent);
65 
66 	return priv == extract_xe(d) ? PFID : (uintptr_t)priv;
67 }
68 
69 /*
70  *      /sys/kernel/debug/dri/BDF/
71  *      ├── sriov
72  *      :   ├── pf
73  *          :   ├── tile0
74  *              :   ├── gt0
75  *                  :   ├── contexts_provisioned
76  *                      ├── doorbells_provisioned
77  *                      ├── runtime_registers
78  *                      ├── adverse_events
79  */
80 
81 static const struct drm_info_list pf_info[] = {
82 	{
83 		"contexts_provisioned",
84 		.show = xe_gt_debugfs_simple_show,
85 		.data = xe_gt_sriov_pf_config_print_ctxs,
86 	},
87 	{
88 		"doorbells_provisioned",
89 		.show = xe_gt_debugfs_simple_show,
90 		.data = xe_gt_sriov_pf_config_print_dbs,
91 	},
92 	{
93 		"runtime_registers",
94 		.show = xe_gt_debugfs_simple_show,
95 		.data = xe_gt_sriov_pf_service_print_runtime,
96 	},
97 	{
98 		"adverse_events",
99 		.show = xe_gt_debugfs_simple_show,
100 		.data = xe_gt_sriov_pf_monitor_print_events,
101 	},
102 };
103 
104 /*
105  *      /sys/kernel/debug/dri/BDF/
106  *      ├── sriov
107  *      :   ├── pf
108  *          :   ├── tile0
109  *              :   ├── gt0
110  *                  :   ├── reset_engine
111  *                      ├── sample_period
112  *                      ├── sched_if_idle
113  */
114 
115 #define DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(POLICY, TYPE, FORMAT)		\
116 										\
117 static int POLICY##_set(void *data, u64 val)					\
118 {										\
119 	struct xe_gt *gt = extract_gt(data);					\
120 	struct xe_device *xe = gt_to_xe(gt);					\
121 	int err;								\
122 										\
123 	if (val > (TYPE)~0ull)							\
124 		return -EOVERFLOW;						\
125 										\
126 	xe_pm_runtime_get(xe);							\
127 	err = xe_gt_sriov_pf_policy_set_##POLICY(gt, val);			\
128 	if (!err)								\
129 		xe_sriov_pf_provision_set_custom_mode(xe);			\
130 	xe_pm_runtime_put(xe);							\
131 										\
132 	return err;								\
133 }										\
134 										\
135 static int POLICY##_get(void *data, u64 *val)					\
136 {										\
137 	struct xe_gt *gt = extract_gt(data);					\
138 										\
139 	*val = xe_gt_sriov_pf_policy_get_##POLICY(gt);				\
140 	return 0;								\
141 }										\
142 										\
143 DEFINE_DEBUGFS_ATTRIBUTE(POLICY##_fops, POLICY##_get, POLICY##_set, FORMAT)
144 
145 DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(reset_engine, bool, "%llu\n");
146 DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(sched_if_idle, bool, "%llu\n");
147 DEFINE_SRIOV_GT_POLICY_DEBUGFS_ATTRIBUTE(sample_period, u32, "%llu\n");
148 
149 static void pf_add_policy_attrs(struct xe_gt *gt, struct dentry *parent)
150 {
151 	xe_gt_assert(gt, gt == extract_gt(parent));
152 	xe_gt_assert(gt, PFID == extract_vfid(parent));
153 
154 	debugfs_create_file_unsafe("reset_engine", 0644, parent, parent, &reset_engine_fops);
155 	debugfs_create_file_unsafe("sched_if_idle", 0644, parent, parent, &sched_if_idle_fops);
156 	debugfs_create_file_unsafe("sample_period_ms", 0644, parent, parent, &sample_period_fops);
157 }
158 
159 /*
160  *      /sys/kernel/debug/dri/BDF/
161  *      ├── sriov
162  *      :   ├── pf
163  *          │   ├── tile0
164  *          │   :   ├── gt0
165  *          │       :   ├── doorbells_spare
166  *          │           ├── contexts_spare
167  *          │           ├── exec_quantum_ms
168  *          │           ├── preempt_timeout_us
169  *          │           ├── sched_priority
170  *          ├── vf1
171  *          :   ├── tile0
172  *              :   ├── gt0
173  *                  :   ├── doorbells_quota
174  *                      ├── contexts_quota
175  *                      ├── exec_quantum_ms
176  *                      ├── preempt_timeout_us
177  *                      ├── sched_priority
178  */
179 
180 #define DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(CONFIG, TYPE, FORMAT)		\
181 										\
182 static int CONFIG##_set(void *data, u64 val)					\
183 {										\
184 	struct xe_gt *gt = extract_gt(data);					\
185 	unsigned int vfid = extract_vfid(data);					\
186 	struct xe_device *xe = gt_to_xe(gt);					\
187 	int err;								\
188 										\
189 	if (val > (TYPE)~0ull)							\
190 		return -EOVERFLOW;						\
191 										\
192 	xe_pm_runtime_get(xe);							\
193 	err = xe_sriov_pf_wait_ready(xe) ?:					\
194 	      xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val);		\
195 	if (!err)								\
196 		xe_sriov_pf_provision_set_custom_mode(xe);			\
197 	xe_pm_runtime_put(xe);							\
198 										\
199 	return err;								\
200 }										\
201 										\
202 static int CONFIG##_get(void *data, u64 *val)					\
203 {										\
204 	struct xe_gt *gt = extract_gt(data);					\
205 	unsigned int vfid = extract_vfid(data);					\
206 										\
207 	*val = xe_gt_sriov_pf_config_get_##CONFIG(gt, vfid);			\
208 	return 0;								\
209 }										\
210 										\
211 DEFINE_DEBUGFS_ATTRIBUTE(CONFIG##_fops, CONFIG##_get, CONFIG##_set, FORMAT)
212 
213 DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(ctxs, u32, "%llu\n");
214 DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(dbs, u32, "%llu\n");
215 DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(exec_quantum, u32, "%llu\n");
216 DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(preempt_timeout, u32, "%llu\n");
217 DEFINE_SRIOV_GT_CONFIG_DEBUGFS_ATTRIBUTE(sched_priority, u32, "%llu\n");
218 
219 /*
220  *      /sys/kernel/debug/dri/BDF/
221  *      ├── sriov
222  *      :   ├── pf
223  *          │   ├── tile0
224  *          │   :   ├── gt0
225  *          │       :   ├── threshold_cat_error_count
226  *          │           ├── threshold_doorbell_time_us
227  *          │           ├── threshold_engine_reset_count
228  *          │           ├── threshold_guc_time_us
229  *          │           ├── threshold_irq_time_us
230  *          │           ├── threshold_page_fault_count
231  *          ├── vf1
232  *          :   ├── tile0
233  *              :   ├── gt0
234  *                  :   ├── threshold_cat_error_count
235  *                      ├── threshold_doorbell_time_us
236  *                      ├── threshold_engine_reset_count
237  *                      ├── threshold_guc_time_us
238  *                      ├── threshold_irq_time_us
239  *                      ├── threshold_page_fault_count
240  */
241 
242 static int set_threshold(void *data, u64 val, enum xe_guc_klv_threshold_index index)
243 {
244 	struct xe_gt *gt = extract_gt(data);
245 	unsigned int vfid = extract_vfid(data);
246 	struct xe_device *xe = gt_to_xe(gt);
247 	int err;
248 
249 	if (val > (u32)~0ull)
250 		return -EOVERFLOW;
251 
252 	xe_pm_runtime_get(xe);
253 	err = xe_gt_sriov_pf_config_set_threshold(gt, vfid, index, val);
254 	if (!err)
255 		xe_sriov_pf_provision_set_custom_mode(xe);
256 	xe_pm_runtime_put(xe);
257 
258 	return err;
259 }
260 
261 static int get_threshold(void *data, u64 *val, enum xe_guc_klv_threshold_index index)
262 {
263 	struct xe_gt *gt = extract_gt(data);
264 	unsigned int vfid = extract_vfid(data);
265 
266 	*val = xe_gt_sriov_pf_config_get_threshold(gt, vfid, index);
267 	return 0;
268 }
269 
270 #define DEFINE_SRIOV_GT_THRESHOLD_DEBUGFS_ATTRIBUTE(THRESHOLD, INDEX)		\
271 										\
272 static int THRESHOLD##_set(void *data, u64 val)					\
273 {										\
274 	return set_threshold(data, val, INDEX);					\
275 }										\
276 										\
277 static int THRESHOLD##_get(void *data, u64 *val)				\
278 {										\
279 	return get_threshold(data, val, INDEX);					\
280 }										\
281 										\
282 DEFINE_DEBUGFS_ATTRIBUTE(THRESHOLD##_fops, THRESHOLD##_get, THRESHOLD##_set, "%llu\n")
283 
284 /* generate all threshold attributes */
285 #define define_threshold_attribute(TAG, NAME, ...) \
286 	DEFINE_SRIOV_GT_THRESHOLD_DEBUGFS_ATTRIBUTE(NAME, MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG));
287 MAKE_XE_GUC_KLV_THRESHOLDS_SET(define_threshold_attribute)
288 #undef define_threshold_attribute
289 
290 static void pf_add_config_attrs(struct xe_gt *gt, struct dentry *parent, unsigned int vfid)
291 {
292 	xe_gt_assert(gt, gt == extract_gt(parent));
293 	xe_gt_assert(gt, vfid == extract_vfid(parent));
294 
295 	debugfs_create_file_unsafe(vfid ? "doorbells_quota" : "doorbells_spare",
296 				   0644, parent, parent, &dbs_fops);
297 	debugfs_create_file_unsafe(vfid ? "contexts_quota" : "contexts_spare",
298 				   0644, parent, parent, &ctxs_fops);
299 	debugfs_create_file_unsafe("exec_quantum_ms", 0644, parent, parent,
300 				   &exec_quantum_fops);
301 	debugfs_create_file_unsafe("preempt_timeout_us", 0644, parent, parent,
302 				   &preempt_timeout_fops);
303 	debugfs_create_file_unsafe("sched_priority", 0644, parent, parent,
304 				   &sched_priority_fops);
305 
306 	/* register all threshold attributes */
307 #define register_threshold_attribute(TAG, NAME, ...) \
308 	debugfs_create_file_unsafe("threshold_" #NAME, 0644, parent, parent, \
309 				   &NAME##_fops);
310 	MAKE_XE_GUC_KLV_THRESHOLDS_SET(register_threshold_attribute)
311 #undef register_threshold_attribute
312 }
313 
314 /*
315  *      /sys/kernel/debug/dri/BDF/
316  *      ├── sriov
317  *      :   ├── vf1
318  *          :   ├── tile0
319  *              :   ├── gt0
320  *                  :   ├── control { stop, pause, resume }
321  */
322 
323 static const struct {
324 	const char *cmd;
325 	int (*fn)(struct xe_gt *gt, unsigned int vfid);
326 } control_cmds[] = {
327 	{ "stop", xe_gt_sriov_pf_control_stop_vf },
328 	{ "pause", xe_gt_sriov_pf_control_pause_vf },
329 	{ "resume", xe_gt_sriov_pf_control_resume_vf },
330 };
331 
332 static ssize_t control_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
333 {
334 	struct dentry *dent = file_dentry(file);
335 	struct dentry *parent = dent->d_parent;
336 	struct xe_gt *gt = extract_gt(parent);
337 	struct xe_device *xe = gt_to_xe(gt);
338 	unsigned int vfid = extract_vfid(parent);
339 	int ret = -EINVAL;
340 	char cmd[32];
341 	size_t n;
342 
343 	xe_gt_assert(gt, vfid);
344 	xe_gt_sriov_pf_assert_vfid(gt, vfid);
345 
346 	if (*pos)
347 		return -ESPIPE;
348 
349 	if (count > sizeof(cmd) - 1)
350 		return -EINVAL;
351 
352 	ret = simple_write_to_buffer(cmd, sizeof(cmd) - 1, pos, buf, count);
353 	if (ret < 0)
354 		return ret;
355 	cmd[ret] = '\0';
356 
357 	for (n = 0; n < ARRAY_SIZE(control_cmds); n++) {
358 		xe_gt_assert(gt, sizeof(cmd) > strlen(control_cmds[n].cmd));
359 
360 		if (sysfs_streq(cmd, control_cmds[n].cmd)) {
361 			xe_pm_runtime_get(xe);
362 			ret = control_cmds[n].fn ? (*control_cmds[n].fn)(gt, vfid) : 0;
363 			xe_pm_runtime_put(xe);
364 			break;
365 		}
366 	}
367 
368 	return (ret < 0) ? ret : count;
369 }
370 
371 static ssize_t control_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
372 {
373 	char help[128];
374 	size_t n;
375 
376 	help[0] = '\0';
377 	for (n = 0; n < ARRAY_SIZE(control_cmds); n++) {
378 		strlcat(help, control_cmds[n].cmd, sizeof(help));
379 		strlcat(help, "\n", sizeof(help));
380 	}
381 
382 	return simple_read_from_buffer(buf, count, ppos, help, strlen(help));
383 }
384 
385 static const struct file_operations control_ops = {
386 	.owner		= THIS_MODULE,
387 	.open		= simple_open,
388 	.write		= control_write,
389 	.read		= control_read,
390 	.llseek		= default_llseek,
391 };
392 
393 /*
394  *      /sys/kernel/debug/dri/BDF/
395  *      ├── sriov
396  *      :   ├── vf1
397  *          :   ├── tile0
398  *              :   ├── gt0
399  *                  :   ├── config_blob
400  */
401 
402 struct config_blob_data {
403 	size_t size;
404 	u8 blob[];
405 };
406 
407 static int config_blob_open(struct inode *inode, struct file *file)
408 {
409 	struct dentry *dent = file_dentry(file);
410 	struct dentry *parent = dent->d_parent;
411 	struct xe_gt *gt = extract_gt(parent);
412 	unsigned int vfid = extract_vfid(parent);
413 	struct config_blob_data *cbd;
414 	ssize_t ret;
415 
416 	ret = xe_gt_sriov_pf_config_save(gt, vfid, NULL, 0);
417 	if (!ret)
418 		return -ENODATA;
419 	if (ret < 0)
420 		return ret;
421 
422 	cbd = kzalloc(struct_size(cbd, blob, ret), GFP_KERNEL);
423 	if (!cbd)
424 		return -ENOMEM;
425 
426 	ret = xe_gt_sriov_pf_config_save(gt, vfid, cbd->blob, ret);
427 	if (ret < 0) {
428 		kfree(cbd);
429 		return ret;
430 	}
431 
432 	cbd->size = ret;
433 	file->private_data = cbd;
434 	return nonseekable_open(inode, file);
435 }
436 
437 static ssize_t config_blob_read(struct file *file, char __user *buf,
438 				size_t count, loff_t *pos)
439 {
440 	struct config_blob_data *cbd = file->private_data;
441 
442 	return simple_read_from_buffer(buf, count, pos, cbd->blob, cbd->size);
443 }
444 
445 static ssize_t config_blob_write(struct file *file, const char __user *buf,
446 				 size_t count, loff_t *pos)
447 {
448 	struct dentry *dent = file_dentry(file);
449 	struct dentry *parent = dent->d_parent;
450 	struct xe_gt *gt = extract_gt(parent);
451 	unsigned int vfid = extract_vfid(parent);
452 	ssize_t ret;
453 	void *tmp;
454 
455 	if (*pos)
456 		return -EINVAL;
457 
458 	if (!count)
459 		return -ENODATA;
460 
461 	if (count > SZ_4K)
462 		return -EINVAL;
463 
464 	tmp = kzalloc(count, GFP_KERNEL);
465 	if (!tmp)
466 		return -ENOMEM;
467 
468 	if (copy_from_user(tmp, buf, count)) {
469 		ret = -EFAULT;
470 	} else {
471 		ret = xe_gt_sriov_pf_config_restore(gt, vfid, tmp, count);
472 		if (!ret)
473 			ret = count;
474 	}
475 	kfree(tmp);
476 	return ret;
477 }
478 
479 static int config_blob_release(struct inode *inode, struct file *file)
480 {
481 	kfree(file->private_data);
482 	return 0;
483 }
484 
485 static const struct file_operations config_blob_ops = {
486 	.owner		= THIS_MODULE,
487 	.open		= config_blob_open,
488 	.read		= config_blob_read,
489 	.write		= config_blob_write,
490 	.release	= config_blob_release,
491 };
492 
493 static void pf_add_compat_attrs(struct xe_gt *gt, struct dentry *dent, unsigned int vfid)
494 {
495 	struct xe_device *xe = gt_to_xe(gt);
496 
497 	if (!xe_gt_is_main_type(gt))
498 		return;
499 
500 	if (vfid) {
501 		debugfs_create_symlink("ggtt_quota", dent, "../ggtt_quota");
502 		if (xe_device_has_lmtt(xe))
503 			debugfs_create_symlink("lmem_quota", dent, "../vram_quota");
504 	} else {
505 		debugfs_create_symlink("ggtt_spare", dent, "../ggtt_spare");
506 		debugfs_create_symlink("ggtt_available", dent, "../ggtt_available");
507 		debugfs_create_symlink("ggtt_provisioned", dent, "../ggtt_provisioned");
508 		if (xe_device_has_lmtt(xe)) {
509 			debugfs_create_symlink("lmem_spare", dent, "../vram_spare");
510 			debugfs_create_symlink("lmem_provisioned", dent, "../vram_provisioned");
511 		}
512 	}
513 }
514 
515 static void pf_populate_gt(struct xe_gt *gt, struct dentry *dent, unsigned int vfid)
516 {
517 	struct xe_device *xe = gt_to_xe(gt);
518 	struct drm_minor *minor = xe->drm.primary;
519 
520 	if (vfid) {
521 		pf_add_config_attrs(gt, dent, vfid);
522 
523 		debugfs_create_file("control", 0600, dent, NULL, &control_ops);
524 
525 		/* for testing/debugging purposes only! */
526 		if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) {
527 			debugfs_create_file("config_blob",
528 					    IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV) ? 0600 : 0400,
529 					    dent, NULL, &config_blob_ops);
530 		}
531 
532 	} else {
533 		pf_add_config_attrs(gt, dent, PFID);
534 		pf_add_policy_attrs(gt, dent);
535 
536 		drm_debugfs_create_files(pf_info, ARRAY_SIZE(pf_info), dent, minor);
537 	}
538 
539 	/* for backward compatibility only */
540 	pf_add_compat_attrs(gt, dent, vfid);
541 }
542 
543 /**
544  * xe_gt_sriov_pf_debugfs_populate() - Create SR-IOV GT-level debugfs directories and files.
545  * @gt: the &xe_gt to register
546  * @parent: the parent &dentry that represents a &xe_tile
547  * @vfid: the VF identifier
548  *
549  * Add to the @parent directory new debugfs directory that will represent a @gt and
550  * populate it with GT files that are related to the SR-IOV @vfid function.
551  *
552  * This function can only be called on PF.
553  */
554 void xe_gt_sriov_pf_debugfs_populate(struct xe_gt *gt, struct dentry *parent, unsigned int vfid)
555 {
556 	struct dentry *dent;
557 	char name[8]; /* should be enough up to "gt%u\0" for 2^8 - 1 */
558 
559 	xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
560 	xe_gt_assert(gt, extract_priv(parent) == gt->tile);
561 	xe_gt_assert(gt, extract_priv(parent->d_parent) == gt_to_xe(gt) ||
562 		     (uintptr_t)extract_priv(parent->d_parent) == vfid);
563 
564 	/*
565 	 *      /sys/kernel/debug/dri/BDF/
566 	 *      ├── sriov
567 	 *      │   ├── pf
568 	 *      │   │   ├── tile0		# parent
569 	 *      │   │   │   ├── gt0		# d_inode->i_private = (xe_gt*)
570 	 *      │   │   │   ├── gt1
571 	 *      │   │   :   :
572 	 *      │   ├── vf1
573 	 *      │   │   ├── tile0		# parent
574 	 *      │   │   │   ├── gt0		# d_inode->i_private = (xe_gt*)
575 	 *      │   │   │   ├── gt1
576 	 *      │   :   :   :
577 	 */
578 	snprintf(name, sizeof(name), "gt%u", gt->info.id);
579 	dent = debugfs_create_dir(name, parent);
580 	if (IS_ERR(dent))
581 		return;
582 	dent->d_inode->i_private = gt;
583 
584 	xe_gt_assert(gt, extract_gt(dent) == gt);
585 	xe_gt_assert(gt, extract_vfid(dent) == vfid);
586 
587 	pf_populate_gt(gt, dent, vfid);
588 }
589 
590 static void pf_add_links(struct xe_gt *gt, struct dentry *dent)
591 {
592 	unsigned int totalvfs = xe_gt_sriov_pf_get_totalvfs(gt);
593 	unsigned int vfid;
594 	char name[16];		/* should be more than enough for "vf%u\0" and VFID(UINT_MAX) */
595 	char symlink[64];	/* should be more enough for "../../sriov/vf%u/tile%u/gt%u\0" */
596 
597 	for (vfid = 0; vfid <= totalvfs; vfid++) {
598 		if (vfid)
599 			snprintf(name, sizeof(name), "vf%u", vfid);
600 		else
601 			snprintf(name, sizeof(name), "pf");
602 		snprintf(symlink, sizeof(symlink), "../../sriov/%s/tile%u/gt%u",
603 			 name, gt->tile->id, gt->info.id);
604 		debugfs_create_symlink(name, dent, symlink);
605 	}
606 }
607 
608 /**
609  * xe_gt_sriov_pf_debugfs_register - Register SR-IOV PF specific entries in GT debugfs.
610  * @gt: the &xe_gt to register
611  * @dent: the &dentry that represents the GT directory
612  *
613  * Instead of actual files, create symlinks for PF and each VF to their GT specific
614  * attributes that should be already exposed in the dedicated debugfs SR-IOV tree.
615  */
616 void xe_gt_sriov_pf_debugfs_register(struct xe_gt *gt, struct dentry *dent)
617 {
618 	xe_gt_assert(gt, IS_SRIOV_PF(gt_to_xe(gt)));
619 	xe_gt_assert(gt, dent->d_inode->i_private == gt);
620 
621 	pf_add_links(gt, dent);
622 }
623