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