Linux Audio

Check our new training course

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	&timeslice_duration_def.attr,
474	&timeslice_duration_min_def.attr,
475	&timeslice_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	&timeslice_duration_attr.attr,
487	&timeslice_duration_min_attr.attr,
488	&timeslice_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}