xref: /linux/drivers/gpu/drm/xe/xe_sriov_pf_sysfs.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2025 Intel Corporation
4  */
5 
6 #include <linux/kobject.h>
7 #include <linux/sysfs.h>
8 
9 #include <drm/drm_managed.h>
10 
11 #include "xe_assert.h"
12 #include "xe_pci_sriov.h"
13 #include "xe_pm.h"
14 #include "xe_sriov.h"
15 #include "xe_sriov_pf.h"
16 #include "xe_sriov_pf_control.h"
17 #include "xe_sriov_pf_helpers.h"
18 #include "xe_sriov_pf_provision.h"
19 #include "xe_sriov_pf_sysfs.h"
20 #include "xe_sriov_printk.h"
21 
22 static int emit_choice(char *buf, int choice, const char * const *array, size_t size)
23 {
24 	int pos = 0;
25 	int n;
26 
27 	for (n = 0; n < size; n++) {
28 		pos += sysfs_emit_at(buf, pos, "%s%s%s%s",
29 				    n ? " " : "",
30 				    n == choice ? "[" : "",
31 				    array[n],
32 				    n == choice ? "]" : "");
33 	}
34 	pos += sysfs_emit_at(buf, pos, "\n");
35 
36 	return pos;
37 }
38 
39 /*
40  * /sys/bus/pci/drivers/xe/BDF/
41  * :
42  * ├── sriov_admin/
43  *     ├── ...
44  *     ├── .bulk_profile
45  *     │   ├── exec_quantum_ms
46  *     │   ├── preempt_timeout_us
47  *     │   └── sched_priority
48  *     ├── pf/
49  *     │   ├── ...
50  *     │   ├── device -> ../../../BDF
51  *     │   └── profile
52  *     │       ├── exec_quantum_ms
53  *     │       ├── preempt_timeout_us
54  *     │       └── sched_priority
55  *     ├── vf1/
56  *     │   ├── ...
57  *     │   ├── device -> ../../../BDF.1
58  *     │   ├── stop
59  *     │   └── profile
60  *     │       ├── exec_quantum_ms
61  *     │       ├── preempt_timeout_us
62  *     │       └── sched_priority
63  *     ├── vf2/
64  *     :
65  *     └── vfN/
66  */
67 
68 struct xe_sriov_kobj {
69 	struct kobject base;
70 	struct xe_device *xe;
71 	unsigned int vfid;
72 };
73 #define to_xe_sriov_kobj(p) container_of_const((p), struct xe_sriov_kobj, base)
74 
75 struct xe_sriov_dev_attr {
76 	struct attribute attr;
77 	ssize_t (*show)(struct xe_device *xe, char *buf);
78 	ssize_t (*store)(struct xe_device *xe, const char *buf, size_t count);
79 };
80 #define to_xe_sriov_dev_attr(p) container_of_const((p), struct xe_sriov_dev_attr, attr)
81 
82 #define XE_SRIOV_DEV_ATTR(NAME) \
83 struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \
84 	__ATTR(NAME, 0644, xe_sriov_dev_attr_##NAME##_show, xe_sriov_dev_attr_##NAME##_store)
85 
86 #define XE_SRIOV_DEV_ATTR_RO(NAME) \
87 struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \
88 	__ATTR(NAME, 0444, xe_sriov_dev_attr_##NAME##_show, NULL)
89 
90 #define XE_SRIOV_DEV_ATTR_WO(NAME) \
91 struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \
92 	__ATTR(NAME, 0200, NULL, xe_sriov_dev_attr_##NAME##_store)
93 
94 struct xe_sriov_vf_attr {
95 	struct attribute attr;
96 	ssize_t (*show)(struct xe_device *xe, unsigned int vfid, char *buf);
97 	ssize_t (*store)(struct xe_device *xe, unsigned int vfid, const char *buf, size_t count);
98 };
99 #define to_xe_sriov_vf_attr(p) container_of_const((p), struct xe_sriov_vf_attr, attr)
100 
101 #define XE_SRIOV_VF_ATTR(NAME) \
102 struct xe_sriov_vf_attr xe_sriov_vf_attr_##NAME = \
103 	__ATTR(NAME, 0644, xe_sriov_vf_attr_##NAME##_show, xe_sriov_vf_attr_##NAME##_store)
104 
105 #define XE_SRIOV_VF_ATTR_RO(NAME) \
106 struct xe_sriov_vf_attr xe_sriov_vf_attr_##NAME = \
107 	__ATTR(NAME, 0444, xe_sriov_vf_attr_##NAME##_show, NULL)
108 
109 #define XE_SRIOV_VF_ATTR_WO(NAME) \
110 struct xe_sriov_vf_attr xe_sriov_vf_attr_##NAME = \
111 	__ATTR(NAME, 0200, NULL, xe_sriov_vf_attr_##NAME##_store)
112 
113 /* device level attributes go here */
114 
115 #define DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(NAME, ITEM, TYPE)		\
116 											\
117 static ssize_t xe_sriov_dev_attr_##NAME##_store(struct xe_device *xe,			\
118 						const char *buf, size_t count)		\
119 {											\
120 	TYPE value;									\
121 	int err;									\
122 											\
123 	err = kstrto##TYPE(buf, 0, &value);						\
124 	if (err)									\
125 		return err;								\
126 											\
127 	err = xe_sriov_pf_provision_bulk_apply_##ITEM(xe, value);			\
128 	return err ?: count;								\
129 }											\
130 											\
131 static XE_SRIOV_DEV_ATTR_WO(NAME)
132 
133 DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(exec_quantum_ms, eq, u32);
134 DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(preempt_timeout_us, pt, u32);
135 
136 static const char * const sched_priority_names[] = {
137 	[GUC_SCHED_PRIORITY_LOW] = "low",
138 	[GUC_SCHED_PRIORITY_NORMAL] = "normal",
139 	[GUC_SCHED_PRIORITY_HIGH] = "high",
140 };
141 
142 static bool sched_priority_change_allowed(unsigned int vfid)
143 {
144 	/* As of today GuC FW allows to selectively change only the PF priority. */
145 	return vfid == PFID;
146 }
147 
148 static bool sched_priority_high_allowed(unsigned int vfid)
149 {
150 	/* As of today GuC FW allows to select 'high' priority only for the PF. */
151 	return vfid == PFID;
152 }
153 
154 static bool sched_priority_bulk_high_allowed(struct xe_device *xe)
155 {
156 	/* all VFs are equal - it's sufficient to check VF1 only */
157 	return sched_priority_high_allowed(VFID(1));
158 }
159 
160 static ssize_t xe_sriov_dev_attr_sched_priority_store(struct xe_device *xe,
161 						      const char *buf, size_t count)
162 {
163 	size_t num_priorities = ARRAY_SIZE(sched_priority_names);
164 	int match;
165 	int err;
166 
167 	if (!sched_priority_bulk_high_allowed(xe))
168 		num_priorities--;
169 
170 	match = __sysfs_match_string(sched_priority_names, num_priorities, buf);
171 	if (match < 0)
172 		return -EINVAL;
173 
174 	err = xe_sriov_pf_provision_bulk_apply_priority(xe, match);
175 	return err ?: count;
176 }
177 
178 static XE_SRIOV_DEV_ATTR_WO(sched_priority);
179 
180 static struct attribute *bulk_profile_dev_attrs[] = {
181 	&xe_sriov_dev_attr_exec_quantum_ms.attr,
182 	&xe_sriov_dev_attr_preempt_timeout_us.attr,
183 	&xe_sriov_dev_attr_sched_priority.attr,
184 	NULL
185 };
186 
187 static const struct attribute_group bulk_profile_dev_attr_group = {
188 	.name = ".bulk_profile",
189 	.attrs = bulk_profile_dev_attrs,
190 };
191 
192 static const struct attribute_group *xe_sriov_dev_attr_groups[] = {
193 	&bulk_profile_dev_attr_group,
194 	NULL
195 };
196 
197 /* and VF-level attributes go here */
198 
199 #define DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(NAME, ITEM, TYPE, FORMAT)		\
200 static ssize_t xe_sriov_vf_attr_##NAME##_show(struct xe_device *xe, unsigned int vfid,	\
201 					      char *buf)				\
202 {											\
203 	TYPE value = 0;									\
204 	int err;									\
205 											\
206 	err = xe_sriov_pf_provision_query_vf_##ITEM(xe, vfid, &value);			\
207 	if (err)									\
208 		return err;								\
209 											\
210 	return sysfs_emit(buf, FORMAT, value);						\
211 }											\
212 											\
213 static ssize_t xe_sriov_vf_attr_##NAME##_store(struct xe_device *xe, unsigned int vfid,	\
214 					       const char *buf, size_t count)		\
215 {											\
216 	TYPE value;									\
217 	int err;									\
218 											\
219 	err = kstrto##TYPE(buf, 0, &value);						\
220 	if (err)									\
221 		return err;								\
222 											\
223 	err = xe_sriov_pf_provision_apply_vf_##ITEM(xe, vfid, value);			\
224 	return err ?: count;								\
225 }											\
226 											\
227 static XE_SRIOV_VF_ATTR(NAME)
228 
229 DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(exec_quantum_ms, eq, u32, "%u\n");
230 DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(preempt_timeout_us, pt, u32, "%u\n");
231 
232 static ssize_t xe_sriov_vf_attr_sched_priority_show(struct xe_device *xe, unsigned int vfid,
233 						    char *buf)
234 {
235 	size_t num_priorities = ARRAY_SIZE(sched_priority_names);
236 	u32 priority;
237 	int err;
238 
239 	err = xe_sriov_pf_provision_query_vf_priority(xe, vfid, &priority);
240 	if (err)
241 		return err;
242 
243 	if (!sched_priority_high_allowed(vfid))
244 		num_priorities--;
245 
246 	xe_assert(xe, priority < num_priorities);
247 	return emit_choice(buf, priority, sched_priority_names, num_priorities);
248 }
249 
250 static ssize_t xe_sriov_vf_attr_sched_priority_store(struct xe_device *xe, unsigned int vfid,
251 						     const char *buf, size_t count)
252 {
253 	size_t num_priorities = ARRAY_SIZE(sched_priority_names);
254 	int match;
255 	int err;
256 
257 	if (!sched_priority_change_allowed(vfid))
258 		return -EOPNOTSUPP;
259 
260 	if (!sched_priority_high_allowed(vfid))
261 		num_priorities--;
262 
263 	match = __sysfs_match_string(sched_priority_names, num_priorities, buf);
264 	if (match < 0)
265 		return -EINVAL;
266 
267 	err = xe_sriov_pf_provision_apply_vf_priority(xe, vfid, match);
268 	return err ?: count;
269 }
270 
271 static XE_SRIOV_VF_ATTR(sched_priority);
272 
273 static struct attribute *profile_vf_attrs[] = {
274 	&xe_sriov_vf_attr_exec_quantum_ms.attr,
275 	&xe_sriov_vf_attr_preempt_timeout_us.attr,
276 	&xe_sriov_vf_attr_sched_priority.attr,
277 	NULL
278 };
279 
280 static umode_t profile_vf_attr_is_visible(struct kobject *kobj,
281 					  struct attribute *attr, int index)
282 {
283 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
284 
285 	if (attr == &xe_sriov_vf_attr_sched_priority.attr &&
286 	    !sched_priority_change_allowed(vkobj->vfid))
287 		return attr->mode & 0444;
288 
289 	return attr->mode;
290 }
291 
292 static const struct attribute_group profile_vf_attr_group = {
293 	.name = "profile",
294 	.attrs = profile_vf_attrs,
295 	.is_visible = profile_vf_attr_is_visible,
296 };
297 
298 #define DEFINE_SIMPLE_CONTROL_SRIOV_VF_ATTR(NAME)					\
299 											\
300 static ssize_t xe_sriov_vf_attr_##NAME##_store(struct xe_device *xe, unsigned int vfid,	\
301 					       const char *buf, size_t count)		\
302 {											\
303 	bool yes;									\
304 	int err;									\
305 											\
306 	if (!vfid)									\
307 		return -EPERM;								\
308 											\
309 	err = kstrtobool(buf, &yes);							\
310 	if (err)									\
311 		return err;								\
312 	if (!yes)									\
313 		return count;								\
314 											\
315 	err = xe_sriov_pf_control_##NAME##_vf(xe, vfid);				\
316 	return err ?: count;								\
317 }											\
318 											\
319 static XE_SRIOV_VF_ATTR_WO(NAME)
320 
321 DEFINE_SIMPLE_CONTROL_SRIOV_VF_ATTR(stop);
322 
323 static struct attribute *control_vf_attrs[] = {
324 	&xe_sriov_vf_attr_stop.attr,
325 	NULL
326 };
327 
328 static umode_t control_vf_attr_is_visible(struct kobject *kobj,
329 					  struct attribute *attr, int index)
330 {
331 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
332 
333 	if (vkobj->vfid == PFID)
334 		return 0;
335 
336 	return attr->mode;
337 }
338 
339 static const struct attribute_group control_vf_attr_group = {
340 	.attrs = control_vf_attrs,
341 	.is_visible = control_vf_attr_is_visible,
342 };
343 
344 static const struct attribute_group *xe_sriov_vf_attr_groups[] = {
345 	&profile_vf_attr_group,
346 	&control_vf_attr_group,
347 	NULL
348 };
349 
350 /* no user serviceable parts below */
351 
352 static void action_put_kobject(void *arg)
353 {
354 	struct kobject *kobj = arg;
355 
356 	kobject_put(kobj);
357 }
358 
359 static struct kobject *create_xe_sriov_kobj(struct xe_device *xe, unsigned int vfid,
360 					    const struct kobj_type *ktype)
361 {
362 	struct xe_sriov_kobj *vkobj;
363 	int err;
364 
365 	xe_sriov_pf_assert_vfid(xe, vfid);
366 
367 	vkobj = kzalloc_obj(*vkobj);
368 	if (!vkobj)
369 		return ERR_PTR(-ENOMEM);
370 
371 	vkobj->xe = xe;
372 	vkobj->vfid = vfid;
373 	kobject_init(&vkobj->base, ktype);
374 
375 	err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, &vkobj->base);
376 	if (err)
377 		return ERR_PTR(err);
378 
379 	return &vkobj->base;
380 }
381 
382 static void release_xe_sriov_kobj(struct kobject *kobj)
383 {
384 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
385 
386 	kfree(vkobj);
387 }
388 
389 static ssize_t xe_sriov_dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
390 {
391 	struct xe_sriov_dev_attr *vattr  = to_xe_sriov_dev_attr(attr);
392 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
393 	struct xe_device *xe = vkobj->xe;
394 
395 	if (!vattr->show)
396 		return -EPERM;
397 
398 	return vattr->show(xe, buf);
399 }
400 
401 static ssize_t xe_sriov_dev_attr_store(struct kobject *kobj, struct attribute *attr,
402 				       const char *buf, size_t count)
403 {
404 	struct xe_sriov_dev_attr *vattr = to_xe_sriov_dev_attr(attr);
405 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
406 	struct xe_device *xe = vkobj->xe;
407 
408 	if (!vattr->store)
409 		return -EPERM;
410 
411 	guard(xe_pm_runtime)(xe);
412 	return xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, buf, count);
413 }
414 
415 static ssize_t xe_sriov_vf_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
416 {
417 	struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr);
418 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
419 	struct xe_device *xe = vkobj->xe;
420 	unsigned int vfid = vkobj->vfid;
421 
422 	xe_sriov_pf_assert_vfid(xe, vfid);
423 
424 	if (!vattr->show)
425 		return -EPERM;
426 
427 	return vattr->show(xe, vfid, buf);
428 }
429 
430 static ssize_t xe_sriov_vf_attr_store(struct kobject *kobj, struct attribute *attr,
431 				      const char *buf, size_t count)
432 {
433 	struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr);
434 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
435 	struct xe_device *xe = vkobj->xe;
436 	unsigned int vfid = vkobj->vfid;
437 
438 	xe_sriov_pf_assert_vfid(xe, vfid);
439 
440 	if (!vattr->store)
441 		return -EPERM;
442 
443 	guard(xe_pm_runtime)(xe);
444 	return xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, vfid, buf, count);
445 }
446 
447 static const struct sysfs_ops xe_sriov_dev_sysfs_ops = {
448 	.show = xe_sriov_dev_attr_show,
449 	.store = xe_sriov_dev_attr_store,
450 };
451 
452 static const struct sysfs_ops xe_sriov_vf_sysfs_ops = {
453 	.show = xe_sriov_vf_attr_show,
454 	.store = xe_sriov_vf_attr_store,
455 };
456 
457 static const struct kobj_type xe_sriov_dev_ktype = {
458 	.release = release_xe_sriov_kobj,
459 	.sysfs_ops = &xe_sriov_dev_sysfs_ops,
460 	.default_groups = xe_sriov_dev_attr_groups,
461 };
462 
463 static const struct kobj_type xe_sriov_vf_ktype = {
464 	.release = release_xe_sriov_kobj,
465 	.sysfs_ops = &xe_sriov_vf_sysfs_ops,
466 	.default_groups = xe_sriov_vf_attr_groups,
467 };
468 
469 static int pf_sysfs_error(struct xe_device *xe, int err, const char *what)
470 {
471 	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG))
472 		xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err));
473 	return err;
474 }
475 
476 static void pf_sysfs_note(struct xe_device *xe, int err, const char *what)
477 {
478 	xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err));
479 }
480 
481 static int pf_setup_root(struct xe_device *xe)
482 {
483 	struct kobject *parent = &xe->drm.dev->kobj;
484 	struct kobject *root;
485 	int err;
486 
487 	root = create_xe_sriov_kobj(xe, PFID, &xe_sriov_dev_ktype);
488 	if (IS_ERR(root))
489 		return pf_sysfs_error(xe, PTR_ERR(root), "root obj");
490 
491 	err = kobject_add(root, parent, "sriov_admin");
492 	if (err)
493 		return pf_sysfs_error(xe, err, "root init");
494 
495 	xe_assert(xe, IS_SRIOV_PF(xe));
496 	xe_assert(xe, !xe->sriov.pf.sysfs.root);
497 	xe->sriov.pf.sysfs.root = root;
498 	return 0;
499 }
500 
501 static int pf_setup_tree(struct xe_device *xe)
502 {
503 	unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe);
504 	struct kobject *root, *kobj;
505 	unsigned int n;
506 	int err;
507 
508 	xe_assert(xe, IS_SRIOV_PF(xe));
509 	root = xe->sriov.pf.sysfs.root;
510 
511 	for (n = 0; n <= totalvfs; n++) {
512 		kobj = create_xe_sriov_kobj(xe, VFID(n), &xe_sriov_vf_ktype);
513 		if (IS_ERR(kobj))
514 			return pf_sysfs_error(xe, PTR_ERR(kobj), "tree obj");
515 
516 		if (n)
517 			err = kobject_add(kobj, root, "vf%u", n);
518 		else
519 			err = kobject_add(kobj, root, "pf");
520 		if (err)
521 			return pf_sysfs_error(xe, err, "tree init");
522 
523 		xe_assert(xe, !xe->sriov.pf.vfs[n].kobj);
524 		xe->sriov.pf.vfs[n].kobj = kobj;
525 	}
526 
527 	return 0;
528 }
529 
530 static void action_rm_device_link(void *arg)
531 {
532 	struct kobject *kobj = arg;
533 
534 	sysfs_remove_link(kobj, "device");
535 }
536 
537 static int pf_link_pf_device(struct xe_device *xe)
538 {
539 	struct kobject *kobj = xe->sriov.pf.vfs[PFID].kobj;
540 	int err;
541 
542 	err = sysfs_create_link(kobj, &xe->drm.dev->kobj, "device");
543 	if (err)
544 		return pf_sysfs_error(xe, err, "PF device link");
545 
546 	err = devm_add_action_or_reset(xe->drm.dev, action_rm_device_link, kobj);
547 	if (err)
548 		return pf_sysfs_error(xe, err, "PF unlink action");
549 
550 	return 0;
551 }
552 
553 /**
554  * xe_sriov_pf_sysfs_init() - Setup PF's SR-IOV sysfs tree.
555  * @xe: the PF &xe_device to setup sysfs
556  *
557  * This function will create additional nodes that will represent PF and VFs
558  * devices, each populated with SR-IOV Xe specific attributes.
559  *
560  * Return: 0 on success or a negative error code on failure.
561  */
562 int xe_sriov_pf_sysfs_init(struct xe_device *xe)
563 {
564 	int err;
565 
566 	err = pf_setup_root(xe);
567 	if (err)
568 		return err;
569 
570 	err = pf_setup_tree(xe);
571 	if (err)
572 		return err;
573 
574 	err = pf_link_pf_device(xe);
575 	if (err)
576 		return err;
577 
578 	return 0;
579 }
580 
581 /**
582  * xe_sriov_pf_sysfs_link_vfs() - Add VF's links in SR-IOV sysfs tree.
583  * @xe: the &xe_device where to update sysfs
584  * @num_vfs: number of enabled VFs to link
585  *
586  * This function is specific for the PF driver.
587  *
588  * This function will add symbolic links between VFs represented in the SR-IOV
589  * sysfs tree maintained by the PF and enabled VF PCI devices.
590  *
591  * The @xe_sriov_pf_sysfs_unlink_vfs() shall be used to remove those links.
592  */
593 void xe_sriov_pf_sysfs_link_vfs(struct xe_device *xe, unsigned int num_vfs)
594 {
595 	unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe);
596 	struct pci_dev *pf_pdev = to_pci_dev(xe->drm.dev);
597 	struct pci_dev *vf_pdev = NULL;
598 	unsigned int n;
599 	int err;
600 
601 	xe_assert(xe, IS_SRIOV_PF(xe));
602 	xe_assert(xe, num_vfs <= totalvfs);
603 
604 	for (n = 1; n <= num_vfs; n++) {
605 		vf_pdev = xe_pci_sriov_get_vf_pdev(pf_pdev, VFID(n));
606 		if (!vf_pdev)
607 			return pf_sysfs_note(xe, -ENOENT, "VF link");
608 
609 		err = sysfs_create_link(xe->sriov.pf.vfs[VFID(n)].kobj,
610 					&vf_pdev->dev.kobj, "device");
611 
612 		/* must balance xe_pci_sriov_get_vf_pdev() */
613 		pci_dev_put(vf_pdev);
614 
615 		if (err)
616 			return pf_sysfs_note(xe, err, "VF link");
617 	}
618 }
619 
620 /**
621  * xe_sriov_pf_sysfs_unlink_vfs() - Remove VF's links from SR-IOV sysfs tree.
622  * @xe: the &xe_device where to update sysfs
623  * @num_vfs: number of VFs to unlink
624  *
625  * This function shall be called only on the PF.
626  * This function will remove "device" links added by @xe_sriov_sysfs_link_vfs().
627  */
628 void xe_sriov_pf_sysfs_unlink_vfs(struct xe_device *xe, unsigned int num_vfs)
629 {
630 	unsigned int n;
631 
632 	xe_assert(xe, IS_SRIOV_PF(xe));
633 	xe_assert(xe, num_vfs <= xe_sriov_pf_get_totalvfs(xe));
634 
635 	for (n = 1; n <= num_vfs; n++)
636 		sysfs_remove_link(xe->sriov.pf.vfs[VFID(n)].kobj, "device");
637 }
638