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