xref: /linux/drivers/gpu/drm/xe/xe_hw_engine_class_sysfs.c (revision d7b4e3287ca3a7baf66efd9158498e551a9550da)
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
14 static 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  */
28 bool xe_hw_engine_timeout_in_range(u64 timeout, u64 min, u64 max)
29 {
30 	return timeout >= min && timeout <= max;
31 }
32 
33 static void kobj_xe_hw_engine_release(struct kobject *kobj)
34 {
35 	kfree(kobj);
36 }
37 
38 static const struct kobj_type kobj_xe_hw_engine_type = {
39 	.release = kobj_xe_hw_engine_release,
40 	.sysfs_ops = &kobj_sysfs_ops
41 };
42 
43 static 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 
68 static 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 
76 static struct kobj_attribute job_timeout_max_attr =
77 __ATTR(job_timeout_max, 0644, job_timeout_max_show, job_timeout_max_store);
78 
79 static 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 
104 static 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 
112 static struct kobj_attribute job_timeout_min_attr =
113 __ATTR(job_timeout_min, 0644, job_timeout_min_show, job_timeout_min_store);
114 
115 static 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 
137 static 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 
145 static struct kobj_attribute job_timeout_attr =
146 __ATTR(job_timeout_ms, 0644, job_timeout_show, job_timeout_store);
147 
148 static 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 
156 static struct kobj_attribute job_timeout_def =
157 __ATTR(job_timeout_ms, 0444, job_timeout_default, NULL);
158 
159 static 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 
167 static struct kobj_attribute job_timeout_min_def =
168 __ATTR(job_timeout_min, 0444, job_timeout_min_default, NULL);
169 
170 static 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 
178 static struct kobj_attribute job_timeout_max_def =
179 __ATTR(job_timeout_max, 0444, job_timeout_max_default, NULL);
180 
181 static 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 
203 static 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 
228 static 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 
237 static struct kobj_attribute timeslice_duration_max_attr =
238 	__ATTR(timeslice_duration_max, 0644, timeslice_duration_max_show,
239 	       timeslice_duration_max_store);
240 
241 static 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 
266 static 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 
275 static struct kobj_attribute timeslice_duration_min_attr =
276 	__ATTR(timeslice_duration_min, 0644, timeslice_duration_min_show,
277 	       timeslice_duration_min_store);
278 
279 static 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 
287 static struct kobj_attribute timeslice_duration_attr =
288 	__ATTR(timeslice_duration_us, 0644, timeslice_duration_show,
289 	       timeslice_duration_store);
290 
291 static 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 
299 static struct kobj_attribute timeslice_duration_def =
300 __ATTR(timeslice_duration_us, 0444, timeslice_default, NULL);
301 
302 static 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 
310 static struct kobj_attribute timeslice_duration_min_def =
311 __ATTR(timeslice_duration_min, 0444, timeslice_min_default, NULL);
312 
313 static 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 
321 static struct kobj_attribute timeslice_duration_max_def =
322 __ATTR(timeslice_duration_max, 0444, timeslice_max_default, NULL);
323 
324 static 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 
346 static 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 
354 static struct kobj_attribute preempt_timeout_attr =
355 __ATTR(preempt_timeout_us, 0644, preempt_timeout_show, preempt_timeout_store);
356 
357 static 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 
366 static struct kobj_attribute preempt_timeout_def =
367 __ATTR(preempt_timeout_us, 0444, preempt_timeout_default, NULL);
368 
369 static 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 
378 static struct kobj_attribute preempt_timeout_min_def =
379 __ATTR(preempt_timeout_min, 0444, preempt_timeout_min_default, NULL);
380 
381 static 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 
390 static struct kobj_attribute preempt_timeout_max_def =
391 __ATTR(preempt_timeout_max, 0444, preempt_timeout_max_default, NULL);
392 
393 static 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 
418 static 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 
426 static struct kobj_attribute preempt_timeout_max_attr =
427 	__ATTR(preempt_timeout_max, 0644, preempt_timeout_max_show,
428 	       preempt_timeout_max_store);
429 
430 static 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 
455 static 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 
463 static struct kobj_attribute preempt_timeout_min_attr =
464 	__ATTR(preempt_timeout_min, 0644, preempt_timeout_min_show,
465 	       preempt_timeout_min_store);
466 
467 static const struct attribute *defaults[] = {
468 	&job_timeout_def.attr,
469 	&job_timeout_min_def.attr,
470 	&job_timeout_max_def.attr,
471 	&timeslice_duration_def.attr,
472 	&timeslice_duration_min_def.attr,
473 	&timeslice_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 
480 static const struct attribute *files[] = {
481 	&job_timeout_attr.attr,
482 	&job_timeout_min_attr.attr,
483 	&job_timeout_max_attr.attr,
484 	&timeslice_duration_attr.attr,
485 	&timeslice_duration_min_attr.attr,
486 	&timeslice_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 
493 static 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 *
502 kobj_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 
526 static 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 
534 static 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;
560 err_object:
561 	kobject_put(kobj);
562 	return err;
563 }
564 
565 static void xe_hw_engine_sysfs_kobj_release(struct kobject *kobj)
566 {
567 	kfree(kobj);
568 }
569 
570 static 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 
575 static 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  */
591 int 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;
672 err_object:
673 	kobject_put(kobj);
674 	return err;
675 }
676