xref: /linux/drivers/gpu/drm/xe/xe_sriov_pf_sysfs.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
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 struct kobject *create_xe_sriov_kobj(struct xe_device *xe, unsigned int vfid)
353 {
354 	struct xe_sriov_kobj *vkobj;
355 
356 	xe_sriov_pf_assert_vfid(xe, vfid);
357 
358 	vkobj = kzalloc(sizeof(*vkobj), GFP_KERNEL);
359 	if (!vkobj)
360 		return NULL;
361 
362 	vkobj->xe = xe;
363 	vkobj->vfid = vfid;
364 	return &vkobj->base;
365 }
366 
367 static void release_xe_sriov_kobj(struct kobject *kobj)
368 {
369 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
370 
371 	kfree(vkobj);
372 }
373 
374 static ssize_t xe_sriov_dev_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
375 {
376 	struct xe_sriov_dev_attr *vattr  = to_xe_sriov_dev_attr(attr);
377 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
378 	struct xe_device *xe = vkobj->xe;
379 
380 	if (!vattr->show)
381 		return -EPERM;
382 
383 	return vattr->show(xe, buf);
384 }
385 
386 static ssize_t xe_sriov_dev_attr_store(struct kobject *kobj, struct attribute *attr,
387 				       const char *buf, size_t count)
388 {
389 	struct xe_sriov_dev_attr *vattr = to_xe_sriov_dev_attr(attr);
390 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
391 	struct xe_device *xe = vkobj->xe;
392 	ssize_t ret;
393 
394 	if (!vattr->store)
395 		return -EPERM;
396 
397 	xe_pm_runtime_get(xe);
398 	ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, buf, count);
399 	xe_pm_runtime_put(xe);
400 
401 	return ret;
402 }
403 
404 static ssize_t xe_sriov_vf_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
405 {
406 	struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr);
407 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
408 	struct xe_device *xe = vkobj->xe;
409 	unsigned int vfid = vkobj->vfid;
410 
411 	xe_sriov_pf_assert_vfid(xe, vfid);
412 
413 	if (!vattr->show)
414 		return -EPERM;
415 
416 	return vattr->show(xe, vfid, buf);
417 }
418 
419 static ssize_t xe_sriov_vf_attr_store(struct kobject *kobj, struct attribute *attr,
420 				      const char *buf, size_t count)
421 {
422 	struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr);
423 	struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj);
424 	struct xe_device *xe = vkobj->xe;
425 	unsigned int vfid = vkobj->vfid;
426 	ssize_t ret;
427 
428 	xe_sriov_pf_assert_vfid(xe, vfid);
429 
430 	if (!vattr->store)
431 		return -EPERM;
432 
433 	xe_pm_runtime_get(xe);
434 	ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, vfid, buf, count);
435 	xe_pm_runtime_get(xe);
436 
437 	return ret;
438 }
439 
440 static const struct sysfs_ops xe_sriov_dev_sysfs_ops = {
441 	.show = xe_sriov_dev_attr_show,
442 	.store = xe_sriov_dev_attr_store,
443 };
444 
445 static const struct sysfs_ops xe_sriov_vf_sysfs_ops = {
446 	.show = xe_sriov_vf_attr_show,
447 	.store = xe_sriov_vf_attr_store,
448 };
449 
450 static const struct kobj_type xe_sriov_dev_ktype = {
451 	.release = release_xe_sriov_kobj,
452 	.sysfs_ops = &xe_sriov_dev_sysfs_ops,
453 	.default_groups = xe_sriov_dev_attr_groups,
454 };
455 
456 static const struct kobj_type xe_sriov_vf_ktype = {
457 	.release = release_xe_sriov_kobj,
458 	.sysfs_ops = &xe_sriov_vf_sysfs_ops,
459 	.default_groups = xe_sriov_vf_attr_groups,
460 };
461 
462 static int pf_sysfs_error(struct xe_device *xe, int err, const char *what)
463 {
464 	if (IS_ENABLED(CONFIG_DRM_XE_DEBUG))
465 		xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err));
466 	return err;
467 }
468 
469 static void pf_sysfs_note(struct xe_device *xe, int err, const char *what)
470 {
471 	xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err));
472 }
473 
474 static void action_put_kobject(void *arg)
475 {
476 	struct kobject *kobj = arg;
477 
478 	kobject_put(kobj);
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);
488 	if (!root)
489 		return pf_sysfs_error(xe, -ENOMEM, "root obj");
490 
491 	err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, root);
492 	if (err)
493 		return pf_sysfs_error(xe, err, "root action");
494 
495 	err = kobject_init_and_add(root, &xe_sriov_dev_ktype, parent, "sriov_admin");
496 	if (err)
497 		return pf_sysfs_error(xe, err, "root init");
498 
499 	xe_assert(xe, IS_SRIOV_PF(xe));
500 	xe_assert(xe, !xe->sriov.pf.sysfs.root);
501 	xe->sriov.pf.sysfs.root = root;
502 	return 0;
503 }
504 
505 static int pf_setup_tree(struct xe_device *xe)
506 {
507 	unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe);
508 	struct kobject *root, *kobj;
509 	unsigned int n;
510 	int err;
511 
512 	xe_assert(xe, IS_SRIOV_PF(xe));
513 	root = xe->sriov.pf.sysfs.root;
514 
515 	for (n = 0; n <= totalvfs; n++) {
516 		kobj = create_xe_sriov_kobj(xe, VFID(n));
517 		if (!kobj)
518 			return pf_sysfs_error(xe, -ENOMEM, "tree obj");
519 
520 		err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, root);
521 		if (err)
522 			return pf_sysfs_error(xe, err, "tree action");
523 
524 		if (n)
525 			err = kobject_init_and_add(kobj, &xe_sriov_vf_ktype,
526 						   root, "vf%u", n);
527 		else
528 			err = kobject_init_and_add(kobj, &xe_sriov_vf_ktype,
529 						   root, "pf");
530 		if (err)
531 			return pf_sysfs_error(xe, err, "tree init");
532 
533 		xe_assert(xe, !xe->sriov.pf.vfs[n].kobj);
534 		xe->sriov.pf.vfs[n].kobj = kobj;
535 	}
536 
537 	return 0;
538 }
539 
540 static void action_rm_device_link(void *arg)
541 {
542 	struct kobject *kobj = arg;
543 
544 	sysfs_remove_link(kobj, "device");
545 }
546 
547 static int pf_link_pf_device(struct xe_device *xe)
548 {
549 	struct kobject *kobj = xe->sriov.pf.vfs[PFID].kobj;
550 	int err;
551 
552 	err = sysfs_create_link(kobj, &xe->drm.dev->kobj, "device");
553 	if (err)
554 		return pf_sysfs_error(xe, err, "PF device link");
555 
556 	err = devm_add_action_or_reset(xe->drm.dev, action_rm_device_link, kobj);
557 	if (err)
558 		return pf_sysfs_error(xe, err, "PF unlink action");
559 
560 	return 0;
561 }
562 
563 /**
564  * xe_sriov_pf_sysfs_init() - Setup PF's SR-IOV sysfs tree.
565  * @xe: the PF &xe_device to setup sysfs
566  *
567  * This function will create additional nodes that will represent PF and VFs
568  * devices, each populated with SR-IOV Xe specific attributes.
569  *
570  * Return: 0 on success or a negative error code on failure.
571  */
572 int xe_sriov_pf_sysfs_init(struct xe_device *xe)
573 {
574 	int err;
575 
576 	err = pf_setup_root(xe);
577 	if (err)
578 		return err;
579 
580 	err = pf_setup_tree(xe);
581 	if (err)
582 		return err;
583 
584 	err = pf_link_pf_device(xe);
585 	if (err)
586 		return err;
587 
588 	return 0;
589 }
590 
591 /**
592  * xe_sriov_pf_sysfs_link_vfs() - Add VF's links in SR-IOV sysfs tree.
593  * @xe: the &xe_device where to update sysfs
594  * @num_vfs: number of enabled VFs to link
595  *
596  * This function is specific for the PF driver.
597  *
598  * This function will add symbolic links between VFs represented in the SR-IOV
599  * sysfs tree maintained by the PF and enabled VF PCI devices.
600  *
601  * The @xe_sriov_pf_sysfs_unlink_vfs() shall be used to remove those links.
602  */
603 void xe_sriov_pf_sysfs_link_vfs(struct xe_device *xe, unsigned int num_vfs)
604 {
605 	unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe);
606 	struct pci_dev *pf_pdev = to_pci_dev(xe->drm.dev);
607 	struct pci_dev *vf_pdev = NULL;
608 	unsigned int n;
609 	int err;
610 
611 	xe_assert(xe, IS_SRIOV_PF(xe));
612 	xe_assert(xe, num_vfs <= totalvfs);
613 
614 	for (n = 1; n <= num_vfs; n++) {
615 		vf_pdev = xe_pci_sriov_get_vf_pdev(pf_pdev, VFID(n));
616 		if (!vf_pdev)
617 			return pf_sysfs_note(xe, -ENOENT, "VF link");
618 
619 		err = sysfs_create_link(xe->sriov.pf.vfs[VFID(n)].kobj,
620 					&vf_pdev->dev.kobj, "device");
621 
622 		/* must balance xe_pci_sriov_get_vf_pdev() */
623 		pci_dev_put(vf_pdev);
624 
625 		if (err)
626 			return pf_sysfs_note(xe, err, "VF link");
627 	}
628 }
629 
630 /**
631  * xe_sriov_pf_sysfs_unlink_vfs() - Remove VF's links from SR-IOV sysfs tree.
632  * @xe: the &xe_device where to update sysfs
633  * @num_vfs: number of VFs to unlink
634  *
635  * This function shall be called only on the PF.
636  * This function will remove "device" links added by @xe_sriov_sysfs_link_vfs().
637  */
638 void xe_sriov_pf_sysfs_unlink_vfs(struct xe_device *xe, unsigned int num_vfs)
639 {
640 	unsigned int n;
641 
642 	xe_assert(xe, IS_SRIOV_PF(xe));
643 	xe_assert(xe, num_vfs <= xe_sriov_pf_get_totalvfs(xe));
644 
645 	for (n = 1; n <= num_vfs; n++)
646 		sysfs_remove_link(xe->sriov.pf.vfs[VFID(n)].kobj, "device");
647 }
648