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_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 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
367static 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
374static 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
386static 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
404static 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
419static 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
440static 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
445static 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
450static 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
456static 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
462static 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
469static 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
474static void action_put_kobject(void *arg)
475{
476 struct kobject *kobj = arg;
477
478 kobject_put(kobj);
479}
480
481static 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
505static 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
540static void action_rm_device_link(void *arg)
541{
542 struct kobject *kobj = arg;
543
544 sysfs_remove_link(kobj, "device");
545}
546
547static 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 */
572int 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 */
603void 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 */
638void 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}