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