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 © 2023 Intel Corporation
4 */
5
6#include <drm/drm_managed.h>
7#include <linux/kobject.h>
8#include <linux/sysfs.h>
9
10#include "xe_device.h"
11#include "xe_gt.h"
12#include "xe_hw_engine_class_sysfs.h"
13#include "xe_pm.h"
14
15#define MAX_ENGINE_CLASS_NAME_LEN 16
16static int xe_add_hw_engine_class_defaults(struct xe_device *xe,
17 struct kobject *parent);
18
19/**
20 * xe_hw_engine_timeout_in_range - Helper to check if timeout is in range
21 * @timeout: timeout to validate
22 * @min: min value of valid range
23 * @max: max value of valid range
24 *
25 * This helper helps to validate if timeout is in min-max range of HW engine
26 * scheduler.
27 *
28 * Returns: Returns false value for failure and true for success.
29 */
30bool xe_hw_engine_timeout_in_range(u64 timeout, u64 min, u64 max)
31{
32 return timeout >= min && timeout <= max;
33}
34
35static void xe_hw_engine_sysfs_kobj_release(struct kobject *kobj)
36{
37 kfree(kobj);
38}
39
40static ssize_t xe_hw_engine_class_sysfs_attr_show(struct kobject *kobj,
41 struct attribute *attr,
42 char *buf)
43{
44 struct xe_device *xe = kobj_to_xe(kobj);
45 struct kobj_attribute *kattr;
46 ssize_t ret = -EIO;
47
48 kattr = container_of(attr, struct kobj_attribute, attr);
49 if (kattr->show) {
50 xe_pm_runtime_get(xe);
51 ret = kattr->show(kobj, kattr, buf);
52 xe_pm_runtime_put(xe);
53 }
54
55 return ret;
56}
57
58static ssize_t xe_hw_engine_class_sysfs_attr_store(struct kobject *kobj,
59 struct attribute *attr,
60 const char *buf,
61 size_t count)
62{
63 struct xe_device *xe = kobj_to_xe(kobj);
64 struct kobj_attribute *kattr;
65 ssize_t ret = -EIO;
66
67 kattr = container_of(attr, struct kobj_attribute, attr);
68 if (kattr->store) {
69 xe_pm_runtime_get(xe);
70 ret = kattr->store(kobj, kattr, buf, count);
71 xe_pm_runtime_put(xe);
72 }
73
74 return ret;
75}
76
77static const struct sysfs_ops xe_hw_engine_class_sysfs_ops = {
78 .show = xe_hw_engine_class_sysfs_attr_show,
79 .store = xe_hw_engine_class_sysfs_attr_store,
80};
81
82static const struct kobj_type kobj_xe_hw_engine_type = {
83 .release = xe_hw_engine_sysfs_kobj_release,
84 .sysfs_ops = &xe_hw_engine_class_sysfs_ops,
85};
86
87static const struct kobj_type kobj_xe_hw_engine_type_def = {
88 .release = xe_hw_engine_sysfs_kobj_release,
89 .sysfs_ops = &kobj_sysfs_ops,
90};
91
92static ssize_t job_timeout_max_store(struct kobject *kobj,
93 struct kobj_attribute *attr,
94 const char *buf, size_t count)
95{
96 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
97 u32 timeout;
98 int err;
99
100 err = kstrtou32(buf, 0, &timeout);
101 if (err)
102 return err;
103
104 if (timeout < eclass->sched_props.job_timeout_min)
105 return -EINVAL;
106
107 if (!xe_hw_engine_timeout_in_range(timeout,
108 XE_HW_ENGINE_JOB_TIMEOUT_MIN,
109 XE_HW_ENGINE_JOB_TIMEOUT_MAX))
110 return -EINVAL;
111
112 WRITE_ONCE(eclass->sched_props.job_timeout_max, timeout);
113
114 return count;
115}
116
117static ssize_t job_timeout_max_show(struct kobject *kobj,
118 struct kobj_attribute *attr, char *buf)
119{
120 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
121
122 return sysfs_emit(buf, "%u\n", eclass->sched_props.job_timeout_max);
123}
124
125static const struct kobj_attribute job_timeout_max_attr =
126__ATTR(job_timeout_max, 0644, job_timeout_max_show, job_timeout_max_store);
127
128static ssize_t job_timeout_min_store(struct kobject *kobj,
129 struct kobj_attribute *attr,
130 const char *buf, size_t count)
131{
132 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
133 u32 timeout;
134 int err;
135
136 err = kstrtou32(buf, 0, &timeout);
137 if (err)
138 return err;
139
140 if (timeout > eclass->sched_props.job_timeout_max)
141 return -EINVAL;
142
143 if (!xe_hw_engine_timeout_in_range(timeout,
144 XE_HW_ENGINE_JOB_TIMEOUT_MIN,
145 XE_HW_ENGINE_JOB_TIMEOUT_MAX))
146 return -EINVAL;
147
148 WRITE_ONCE(eclass->sched_props.job_timeout_min, timeout);
149
150 return count;
151}
152
153static ssize_t job_timeout_min_show(struct kobject *kobj,
154 struct kobj_attribute *attr, char *buf)
155{
156 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
157
158 return sysfs_emit(buf, "%u\n", eclass->sched_props.job_timeout_min);
159}
160
161static const struct kobj_attribute job_timeout_min_attr =
162__ATTR(job_timeout_min, 0644, job_timeout_min_show, job_timeout_min_store);
163
164static ssize_t job_timeout_store(struct kobject *kobj,
165 struct kobj_attribute *attr,
166 const char *buf, size_t count)
167{
168 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
169 u32 min = eclass->sched_props.job_timeout_min;
170 u32 max = eclass->sched_props.job_timeout_max;
171 u32 timeout;
172 int err;
173
174 err = kstrtou32(buf, 0, &timeout);
175 if (err)
176 return err;
177
178 if (!xe_hw_engine_timeout_in_range(timeout, min, max))
179 return -EINVAL;
180
181 WRITE_ONCE(eclass->sched_props.job_timeout_ms, timeout);
182
183 return count;
184}
185
186static ssize_t job_timeout_show(struct kobject *kobj,
187 struct kobj_attribute *attr, char *buf)
188{
189 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
190
191 return sysfs_emit(buf, "%u\n", eclass->sched_props.job_timeout_ms);
192}
193
194static const struct kobj_attribute job_timeout_attr =
195__ATTR(job_timeout_ms, 0644, job_timeout_show, job_timeout_store);
196
197static ssize_t job_timeout_default(struct kobject *kobj,
198 struct kobj_attribute *attr, char *buf)
199{
200 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
201
202 return sysfs_emit(buf, "%u\n", eclass->defaults.job_timeout_ms);
203}
204
205static const struct kobj_attribute job_timeout_def =
206__ATTR(job_timeout_ms, 0444, job_timeout_default, NULL);
207
208static ssize_t job_timeout_min_default(struct kobject *kobj,
209 struct kobj_attribute *attr, char *buf)
210{
211 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
212
213 return sysfs_emit(buf, "%u\n", eclass->defaults.job_timeout_min);
214}
215
216static const struct kobj_attribute job_timeout_min_def =
217__ATTR(job_timeout_min, 0444, job_timeout_min_default, NULL);
218
219static ssize_t job_timeout_max_default(struct kobject *kobj,
220 struct kobj_attribute *attr, char *buf)
221{
222 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
223
224 return sysfs_emit(buf, "%u\n", eclass->defaults.job_timeout_max);
225}
226
227static const struct kobj_attribute job_timeout_max_def =
228__ATTR(job_timeout_max, 0444, job_timeout_max_default, NULL);
229
230static ssize_t timeslice_duration_store(struct kobject *kobj,
231 struct kobj_attribute *attr,
232 const char *buf, size_t count)
233{
234 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
235 u32 min = eclass->sched_props.timeslice_min;
236 u32 max = eclass->sched_props.timeslice_max;
237 u32 duration;
238 int err;
239
240 err = kstrtou32(buf, 0, &duration);
241 if (err)
242 return err;
243
244 if (!xe_hw_engine_timeout_in_range(duration, min, max))
245 return -EINVAL;
246
247 WRITE_ONCE(eclass->sched_props.timeslice_us, duration);
248
249 return count;
250}
251
252static ssize_t timeslice_duration_max_store(struct kobject *kobj,
253 struct kobj_attribute *attr,
254 const char *buf, size_t count)
255{
256 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
257 u32 duration;
258 int err;
259
260 err = kstrtou32(buf, 0, &duration);
261 if (err)
262 return err;
263
264 if (duration < eclass->sched_props.timeslice_min)
265 return -EINVAL;
266
267 if (!xe_hw_engine_timeout_in_range(duration,
268 XE_HW_ENGINE_TIMESLICE_MIN,
269 XE_HW_ENGINE_TIMESLICE_MAX))
270 return -EINVAL;
271
272 WRITE_ONCE(eclass->sched_props.timeslice_max, duration);
273
274 return count;
275}
276
277static ssize_t timeslice_duration_max_show(struct kobject *kobj,
278 struct kobj_attribute *attr,
279 char *buf)
280{
281 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
282
283 return sysfs_emit(buf, "%u\n", eclass->sched_props.timeslice_max);
284}
285
286static const struct kobj_attribute timeslice_duration_max_attr =
287 __ATTR(timeslice_duration_max, 0644, timeslice_duration_max_show,
288 timeslice_duration_max_store);
289
290static ssize_t timeslice_duration_min_store(struct kobject *kobj,
291 struct kobj_attribute *attr,
292 const char *buf, size_t count)
293{
294 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
295 u32 duration;
296 int err;
297
298 err = kstrtou32(buf, 0, &duration);
299 if (err)
300 return err;
301
302 if (duration > eclass->sched_props.timeslice_max)
303 return -EINVAL;
304
305 if (!xe_hw_engine_timeout_in_range(duration,
306 XE_HW_ENGINE_TIMESLICE_MIN,
307 XE_HW_ENGINE_TIMESLICE_MAX))
308 return -EINVAL;
309
310 WRITE_ONCE(eclass->sched_props.timeslice_min, duration);
311
312 return count;
313}
314
315static ssize_t timeslice_duration_min_show(struct kobject *kobj,
316 struct kobj_attribute *attr,
317 char *buf)
318{
319 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
320
321 return sysfs_emit(buf, "%u\n", eclass->sched_props.timeslice_min);
322}
323
324static const struct kobj_attribute timeslice_duration_min_attr =
325 __ATTR(timeslice_duration_min, 0644, timeslice_duration_min_show,
326 timeslice_duration_min_store);
327
328static ssize_t timeslice_duration_show(struct kobject *kobj,
329 struct kobj_attribute *attr, char *buf)
330{
331 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
332
333 return sysfs_emit(buf, "%u\n", eclass->sched_props.timeslice_us);
334}
335
336static const struct kobj_attribute timeslice_duration_attr =
337 __ATTR(timeslice_duration_us, 0644, timeslice_duration_show,
338 timeslice_duration_store);
339
340static ssize_t timeslice_default(struct kobject *kobj,
341 struct kobj_attribute *attr, char *buf)
342{
343 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
344
345 return sysfs_emit(buf, "%u\n", eclass->defaults.timeslice_us);
346}
347
348static const struct kobj_attribute timeslice_duration_def =
349__ATTR(timeslice_duration_us, 0444, timeslice_default, NULL);
350
351static ssize_t timeslice_min_default(struct kobject *kobj,
352 struct kobj_attribute *attr, char *buf)
353{
354 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
355
356 return sysfs_emit(buf, "%u\n", eclass->defaults.timeslice_min);
357}
358
359static const struct kobj_attribute timeslice_duration_min_def =
360__ATTR(timeslice_duration_min, 0444, timeslice_min_default, NULL);
361
362static ssize_t timeslice_max_default(struct kobject *kobj,
363 struct kobj_attribute *attr, char *buf)
364{
365 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
366
367 return sysfs_emit(buf, "%u\n", eclass->defaults.timeslice_max);
368}
369
370static const struct kobj_attribute timeslice_duration_max_def =
371__ATTR(timeslice_duration_max, 0444, timeslice_max_default, NULL);
372
373static ssize_t preempt_timeout_store(struct kobject *kobj,
374 struct kobj_attribute *attr,
375 const char *buf, size_t count)
376{
377 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
378 u32 min = eclass->sched_props.preempt_timeout_min;
379 u32 max = eclass->sched_props.preempt_timeout_max;
380 u32 timeout;
381 int err;
382
383 err = kstrtou32(buf, 0, &timeout);
384 if (err)
385 return err;
386
387 if (!xe_hw_engine_timeout_in_range(timeout, min, max))
388 return -EINVAL;
389
390 WRITE_ONCE(eclass->sched_props.preempt_timeout_us, timeout);
391
392 return count;
393}
394
395static ssize_t preempt_timeout_show(struct kobject *kobj,
396 struct kobj_attribute *attr, char *buf)
397{
398 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
399
400 return sysfs_emit(buf, "%u\n", eclass->sched_props.preempt_timeout_us);
401}
402
403static const struct kobj_attribute preempt_timeout_attr =
404__ATTR(preempt_timeout_us, 0644, preempt_timeout_show, preempt_timeout_store);
405
406static ssize_t preempt_timeout_default(struct kobject *kobj,
407 struct kobj_attribute *attr,
408 char *buf)
409{
410 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
411
412 return sysfs_emit(buf, "%u\n", eclass->defaults.preempt_timeout_us);
413}
414
415static const struct kobj_attribute preempt_timeout_def =
416__ATTR(preempt_timeout_us, 0444, preempt_timeout_default, NULL);
417
418static ssize_t preempt_timeout_min_default(struct kobject *kobj,
419 struct kobj_attribute *attr,
420 char *buf)
421{
422 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
423
424 return sysfs_emit(buf, "%u\n", eclass->defaults.preempt_timeout_min);
425}
426
427static const struct kobj_attribute preempt_timeout_min_def =
428__ATTR(preempt_timeout_min, 0444, preempt_timeout_min_default, NULL);
429
430static ssize_t preempt_timeout_max_default(struct kobject *kobj,
431 struct kobj_attribute *attr,
432 char *buf)
433{
434 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj->parent);
435
436 return sysfs_emit(buf, "%u\n", eclass->defaults.preempt_timeout_max);
437}
438
439static const struct kobj_attribute preempt_timeout_max_def =
440__ATTR(preempt_timeout_max, 0444, preempt_timeout_max_default, NULL);
441
442static ssize_t preempt_timeout_max_store(struct kobject *kobj,
443 struct kobj_attribute *attr,
444 const char *buf, size_t count)
445{
446 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
447 u32 timeout;
448 int err;
449
450 err = kstrtou32(buf, 0, &timeout);
451 if (err)
452 return err;
453
454 if (timeout < eclass->sched_props.preempt_timeout_min)
455 return -EINVAL;
456
457 if (!xe_hw_engine_timeout_in_range(timeout,
458 XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN,
459 XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX))
460 return -EINVAL;
461
462 WRITE_ONCE(eclass->sched_props.preempt_timeout_max, timeout);
463
464 return count;
465}
466
467static ssize_t preempt_timeout_max_show(struct kobject *kobj,
468 struct kobj_attribute *attr, char *buf)
469{
470 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
471
472 return sysfs_emit(buf, "%u\n", eclass->sched_props.preempt_timeout_max);
473}
474
475static const struct kobj_attribute preempt_timeout_max_attr =
476 __ATTR(preempt_timeout_max, 0644, preempt_timeout_max_show,
477 preempt_timeout_max_store);
478
479static ssize_t preempt_timeout_min_store(struct kobject *kobj,
480 struct kobj_attribute *attr,
481 const char *buf, size_t count)
482{
483 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
484 u32 timeout;
485 int err;
486
487 err = kstrtou32(buf, 0, &timeout);
488 if (err)
489 return err;
490
491 if (timeout > eclass->sched_props.preempt_timeout_max)
492 return -EINVAL;
493
494 if (!xe_hw_engine_timeout_in_range(timeout,
495 XE_HW_ENGINE_PREEMPT_TIMEOUT_MIN,
496 XE_HW_ENGINE_PREEMPT_TIMEOUT_MAX))
497 return -EINVAL;
498
499 WRITE_ONCE(eclass->sched_props.preempt_timeout_min, timeout);
500
501 return count;
502}
503
504static ssize_t preempt_timeout_min_show(struct kobject *kobj,
505 struct kobj_attribute *attr, char *buf)
506{
507 struct xe_hw_engine_class_intf *eclass = kobj_to_eclass(kobj);
508
509 return sysfs_emit(buf, "%u\n", eclass->sched_props.preempt_timeout_min);
510}
511
512static const struct kobj_attribute preempt_timeout_min_attr =
513 __ATTR(preempt_timeout_min, 0644, preempt_timeout_min_show,
514 preempt_timeout_min_store);
515
516static const struct attribute *defaults[] = {
517 &job_timeout_def.attr,
518 &job_timeout_min_def.attr,
519 &job_timeout_max_def.attr,
520 ×lice_duration_def.attr,
521 ×lice_duration_min_def.attr,
522 ×lice_duration_max_def.attr,
523 &preempt_timeout_def.attr,
524 &preempt_timeout_min_def.attr,
525 &preempt_timeout_max_def.attr,
526 NULL
527};
528
529static const struct attribute * const files[] = {
530 &job_timeout_attr.attr,
531 &job_timeout_min_attr.attr,
532 &job_timeout_max_attr.attr,
533 ×lice_duration_attr.attr,
534 ×lice_duration_min_attr.attr,
535 ×lice_duration_max_attr.attr,
536 &preempt_timeout_attr.attr,
537 &preempt_timeout_min_attr.attr,
538 &preempt_timeout_max_attr.attr,
539 NULL
540};
541
542static void kobj_xe_hw_engine_class_fini(void *arg)
543{
544 struct kobject *kobj = arg;
545
546 sysfs_remove_files(kobj, files);
547 kobject_put(kobj);
548}
549
550static struct kobj_eclass *
551kobj_xe_hw_engine_class(struct xe_device *xe, struct kobject *parent, const char *name)
552{
553 struct kobj_eclass *keclass;
554 int err = 0;
555
556 keclass = kzalloc(sizeof(*keclass), GFP_KERNEL);
557 if (!keclass)
558 return NULL;
559
560 kobject_init(&keclass->base, &kobj_xe_hw_engine_type);
561 if (kobject_add(&keclass->base, parent, "%s", name)) {
562 kobject_put(&keclass->base);
563 return NULL;
564 }
565 keclass->xe = xe;
566
567 err = devm_add_action_or_reset(xe->drm.dev, kobj_xe_hw_engine_class_fini,
568 &keclass->base);
569 if (err)
570 return NULL;
571
572 return keclass;
573}
574
575static void hw_engine_class_defaults_fini(void *arg)
576{
577 struct kobject *kobj = arg;
578
579 sysfs_remove_files(kobj, defaults);
580 kobject_put(kobj);
581}
582
583static int xe_add_hw_engine_class_defaults(struct xe_device *xe,
584 struct kobject *parent)
585{
586 struct kobject *kobj;
587 int err = 0;
588
589 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
590 if (!kobj)
591 return -ENOMEM;
592
593 kobject_init(kobj, &kobj_xe_hw_engine_type_def);
594 err = kobject_add(kobj, parent, "%s", ".defaults");
595 if (err)
596 goto err_object;
597
598 err = sysfs_create_files(kobj, defaults);
599 if (err)
600 goto err_object;
601
602 return devm_add_action_or_reset(xe->drm.dev, hw_engine_class_defaults_fini, kobj);
603
604err_object:
605 kobject_put(kobj);
606 return err;
607}
608ALLOW_ERROR_INJECTION(xe_add_hw_engine_class_defaults, ERRNO); /* See xe_pci_probe() */
609
610
611static void hw_engine_class_sysfs_fini(void *arg)
612{
613 struct kobject *kobj = arg;
614
615 kobject_put(kobj);
616}
617
618/**
619 * xe_hw_engine_class_sysfs_init - Init HW engine classes on GT.
620 * @gt: Xe GT.
621 *
622 * This routine creates sysfs for HW engine classes and adds methods
623 * to get/set different scheduling properties for HW engines class.
624 *
625 * Returns: Returns error value for failure and 0 for success.
626 */
627int xe_hw_engine_class_sysfs_init(struct xe_gt *gt)
628{
629 struct xe_device *xe = gt_to_xe(gt);
630 struct xe_hw_engine *hwe;
631 enum xe_hw_engine_id id;
632 struct kobject *kobj;
633 u16 class_mask = 0;
634 int err = 0;
635
636 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
637 if (!kobj)
638 return -ENOMEM;
639
640 kobject_init(kobj, &kobj_xe_hw_engine_type);
641
642 err = kobject_add(kobj, gt->sysfs, "engines");
643 if (err)
644 goto err_object;
645
646 for_each_hw_engine(hwe, gt, id) {
647 const char *name;
648 struct kobj_eclass *keclass;
649
650 if (hwe->class == XE_ENGINE_CLASS_OTHER ||
651 hwe->class == XE_ENGINE_CLASS_MAX)
652 continue;
653
654 if ((class_mask >> hwe->class) & 1)
655 continue;
656
657 class_mask |= 1 << hwe->class;
658 name = xe_hw_engine_class_to_str(hwe->class);
659 if (!name) {
660 err = -EINVAL;
661 goto err_object;
662 }
663
664 keclass = kobj_xe_hw_engine_class(xe, kobj, name);
665 if (!keclass) {
666 err = -EINVAL;
667 goto err_object;
668 }
669
670 keclass->eclass = hwe->eclass;
671 err = xe_add_hw_engine_class_defaults(xe, &keclass->base);
672 if (err)
673 goto err_object;
674
675 err = sysfs_create_files(&keclass->base, files);
676 if (err)
677 goto err_object;
678 }
679
680 return devm_add_action_or_reset(xe->drm.dev, hw_engine_class_sysfs_fini, kobj);
681
682err_object:
683 kobject_put(kobj);
684 return err;
685}