Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 664 lines 18 kB view raw
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}