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