FILE
xe_sriov_pf_sysfs.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/xe/xe_sriov_pf_sysfs.c
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 22static 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 68struct 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 75struct 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) \ 83struct 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) \ 87struct 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) \ 91struct xe_sriov_dev_attr xe_sriov_dev_attr_##NAME = \ 92 __ATTR(NAME, 0200, NULL, xe_sriov_dev_attr_##NAME##_store) 93 94struct 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) \ 102struct 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) \ 106struct 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) \ 110struct 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 \ 117static 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 \ 131static XE_SRIOV_DEV_ATTR_WO(NAME) 132 133DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(exec_quantum_ms, eq, u32); 134DEFINE_SIMPLE_BULK_PROVISIONING_SRIOV_DEV_ATTR_WO(preempt_timeout_us, pt, u32); 135 136static 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 142static 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 148static 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 154static 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 160static 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 178static XE_SRIOV_DEV_ATTR_WO(sched_priority); 179 180static 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 187static const struct attribute_group bulk_profile_dev_attr_group = { 188 .name = ".bulk_profile", 189 .attrs = bulk_profile_dev_attrs, 190}; 191 192static 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) \ 200static 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 \ 213static 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 \ 227static XE_SRIOV_VF_ATTR(NAME) 228 229DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(exec_quantum_ms, eq, u32, "%u\n"); 230DEFINE_SIMPLE_PROVISIONING_SRIOV_VF_ATTR(preempt_timeout_us, pt, u32, "%u\n"); 231 232static 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 250static 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 271static XE_SRIOV_VF_ATTR(sched_priority); 272 273static 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 280static 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 292static 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 \ 300static 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 \ 319static XE_SRIOV_VF_ATTR_WO(NAME) 320 321DEFINE_SIMPLE_CONTROL_SRIOV_VF_ATTR(stop); 322 323static struct attribute *control_vf_attrs[] = { 324 &xe_sriov_vf_attr_stop.attr, 325 NULL 326}; 327 328static 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 339static const struct attribute_group control_vf_attr_group = { 340 .attrs = control_vf_attrs, 341 .is_visible = control_vf_attr_is_visible, 342}; 343 344static 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 352static void action_put_kobject(void *arg) 353{ 354 struct kobject *kobj = arg; 355 356 kobject_put(kobj); 357} 358 359static 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(sizeof(*vkobj), GFP_KERNEL); 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 382static 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 389static 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 401static 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 ssize_t ret; 408 409 if (!vattr->store) 410 return -EPERM; 411 412 xe_pm_runtime_get(xe); 413 ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, buf, count); 414 xe_pm_runtime_put(xe); 415 416 return ret; 417} 418 419static ssize_t xe_sriov_vf_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) 420{ 421 struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr); 422 struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 423 struct xe_device *xe = vkobj->xe; 424 unsigned int vfid = vkobj->vfid; 425 426 xe_sriov_pf_assert_vfid(xe, vfid); 427 428 if (!vattr->show) 429 return -EPERM; 430 431 return vattr->show(xe, vfid, buf); 432} 433 434static ssize_t xe_sriov_vf_attr_store(struct kobject *kobj, struct attribute *attr, 435 const char *buf, size_t count) 436{ 437 struct xe_sriov_vf_attr *vattr = to_xe_sriov_vf_attr(attr); 438 struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); 439 struct xe_device *xe = vkobj->xe; 440 unsigned int vfid = vkobj->vfid; 441 ssize_t ret; 442 443 xe_sriov_pf_assert_vfid(xe, vfid); 444 445 if (!vattr->store) 446 return -EPERM; 447 448 xe_pm_runtime_get(xe); 449 ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, vfid, buf, count); 450 xe_pm_runtime_get(xe); 451 452 return ret; 453} 454 455static const struct sysfs_ops xe_sriov_dev_sysfs_ops = { 456 .show = xe_sriov_dev_attr_show, 457 .store = xe_sriov_dev_attr_store, 458}; 459 460static const struct sysfs_ops xe_sriov_vf_sysfs_ops = { 461 .show = xe_sriov_vf_attr_show, 462 .store = xe_sriov_vf_attr_store, 463}; 464 465static const struct kobj_type xe_sriov_dev_ktype = { 466 .release = release_xe_sriov_kobj, 467 .sysfs_ops = &xe_sriov_dev_sysfs_ops, 468 .default_groups = xe_sriov_dev_attr_groups, 469}; 470 471static const struct kobj_type xe_sriov_vf_ktype = { 472 .release = release_xe_sriov_kobj, 473 .sysfs_ops = &xe_sriov_vf_sysfs_ops, 474 .default_groups = xe_sriov_vf_attr_groups, 475}; 476 477static int pf_sysfs_error(struct xe_device *xe, int err, const char *what) 478{ 479 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) 480 xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err)); 481 return err; 482} 483 484static void pf_sysfs_note(struct xe_device *xe, int err, const char *what) 485{ 486 xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err)); 487} 488 489static int pf_setup_root(struct xe_device *xe) 490{ 491 struct kobject *parent = &xe->drm.dev->kobj; 492 struct kobject *root; 493 int err; 494 495 root = create_xe_sriov_kobj(xe, PFID, &xe_sriov_dev_ktype); 496 if (IS_ERR(root)) 497 return pf_sysfs_error(xe, PTR_ERR(root), "root obj"); 498 499 err = kobject_add(root, parent, "sriov_admin"); 500 if (err) 501 return pf_sysfs_error(xe, err, "root init"); 502 503 xe_assert(xe, IS_SRIOV_PF(xe)); 504 xe_assert(xe, !xe->sriov.pf.sysfs.root); 505 xe->sriov.pf.sysfs.root = root; 506 return 0; 507} 508 509static int pf_setup_tree(struct xe_device *xe) 510{ 511 unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe); 512 struct kobject *root, *kobj; 513 unsigned int n; 514 int err; 515 516 xe_assert(xe, IS_SRIOV_PF(xe)); 517 root = xe->sriov.pf.sysfs.root; 518 519 for (n = 0; n <= totalvfs; n++) { 520 kobj = create_xe_sriov_kobj(xe, VFID(n), &xe_sriov_vf_ktype); 521 if (IS_ERR(kobj)) 522 return pf_sysfs_error(xe, PTR_ERR(kobj), "tree obj"); 523 524 if (n) 525 err = kobject_add(kobj, root, "vf%u", n); 526 else 527 err = kobject_add(kobj, root, "pf"); 528 if (err) 529 return pf_sysfs_error(xe, err, "tree init"); 530 531 xe_assert(xe, !xe->sriov.pf.vfs[n].kobj); 532 xe->sriov.pf.vfs[n].kobj = kobj; 533 } 534 535 return 0; 536} 537 538static void action_rm_device_link(void *arg) 539{ 540 struct kobject *kobj = arg; 541 542 sysfs_remove_link(kobj, "device"); 543} 544 545static int pf_link_pf_device(struct xe_device *xe) 546{ 547 struct kobject *kobj = xe->sriov.pf.vfs[PFID].kobj; 548 int err; 549 550 err = sysfs_create_link(kobj, &xe->drm.dev->kobj, "device"); 551 if (err) 552 return pf_sysfs_error(xe, err, "PF device link"); 553 554 err = devm_add_action_or_reset(xe->drm.dev, action_rm_device_link, kobj); 555 if (err) 556 return pf_sysfs_error(xe, err, "PF unlink action"); 557 558 return 0; 559} 560 561/** 562 * xe_sriov_pf_sysfs_init() - Setup PF's SR-IOV sysfs tree. 563 * @xe: the PF &xe_device to setup sysfs 564 * 565 * This function will create additional nodes that will represent PF and VFs 566 * devices, each populated with SR-IOV Xe specific attributes. 567 * 568 * Return: 0 on success or a negative error code on failure. 569 */ 570int xe_sriov_pf_sysfs_init(struct xe_device *xe) 571{ 572 int err; 573 574 err = pf_setup_root(xe); 575 if (err) 576 return err; 577 578 err = pf_setup_tree(xe); 579 if (err) 580 return err; 581 582 err = pf_link_pf_device(xe); 583 if (err) 584 return err; 585 586 return 0; 587} 588 589/** 590 * xe_sriov_pf_sysfs_link_vfs() - Add VF's links in SR-IOV sysfs tree. 591 * @xe: the &xe_device where to update sysfs 592 * @num_vfs: number of enabled VFs to link 593 * 594 * This function is specific for the PF driver. 595 * 596 * This function will add symbolic links between VFs represented in the SR-IOV 597 * sysfs tree maintained by the PF and enabled VF PCI devices. 598 * 599 * The @xe_sriov_pf_sysfs_unlink_vfs() shall be used to remove those links. 600 */ 601void xe_sriov_pf_sysfs_link_vfs(struct xe_device *xe, unsigned int num_vfs) 602{ 603 unsigned int totalvfs = xe_sriov_pf_get_totalvfs(xe); 604 struct pci_dev *pf_pdev = to_pci_dev(xe->drm.dev); 605 struct pci_dev *vf_pdev = NULL; 606 unsigned int n; 607 int err; 608 609 xe_assert(xe, IS_SRIOV_PF(xe)); 610 xe_assert(xe, num_vfs <= totalvfs); 611 612 for (n = 1; n <= num_vfs; n++) { 613 vf_pdev = xe_pci_sriov_get_vf_pdev(pf_pdev, VFID(n)); 614 if (!vf_pdev) 615 return pf_sysfs_note(xe, -ENOENT, "VF link"); 616 617 err = sysfs_create_link(xe->sriov.pf.vfs[VFID(n)].kobj, 618 &vf_pdev->dev.kobj, "device"); 619 620 /* must balance xe_pci_sriov_get_vf_pdev() */ 621 pci_dev_put(vf_pdev); 622 623 if (err) 624 return pf_sysfs_note(xe, err, "VF link"); 625 } 626} 627 628/** 629 * xe_sriov_pf_sysfs_unlink_vfs() - Remove VF's links from SR-IOV sysfs tree. 630 * @xe: the &xe_device where to update sysfs 631 * @num_vfs: number of VFs to unlink 632 * 633 * This function shall be called only on the PF. 634 * This function will remove "device" links added by @xe_sriov_sysfs_link_vfs(). 635 */ 636void xe_sriov_pf_sysfs_unlink_vfs(struct xe_device *xe, unsigned int num_vfs) 637{ 638 unsigned int n; 639 640 xe_assert(xe, IS_SRIOV_PF(xe)); 641 xe_assert(xe, num_vfs <= xe_sriov_pf_get_totalvfs(xe)); 642 643 for (n = 1; n <= num_vfs; n++) 644 sysfs_remove_link(xe->sriov.pf.vfs[VFID(n)].kobj, "device"); 645}
~/
Read-only file preview.