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