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 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 kobj_xe_hw_engine_release(struct kobject *kobj) 36 { 37 kfree(kobj); 38 } 39 40 static const struct kobj_type kobj_xe_hw_engine_type = { 41 .release = kobj_xe_hw_engine_release, 42 .sysfs_ops = &kobj_sysfs_ops 43 }; 44 45 static 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 70 static 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 78 static const struct kobj_attribute job_timeout_max_attr = 79 __ATTR(job_timeout_max, 0644, job_timeout_max_show, job_timeout_max_store); 80 81 static 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 106 static 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 114 static const struct kobj_attribute job_timeout_min_attr = 115 __ATTR(job_timeout_min, 0644, job_timeout_min_show, job_timeout_min_store); 116 117 static 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 139 static 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 147 static const struct kobj_attribute job_timeout_attr = 148 __ATTR(job_timeout_ms, 0644, job_timeout_show, job_timeout_store); 149 150 static 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 158 static const struct kobj_attribute job_timeout_def = 159 __ATTR(job_timeout_ms, 0444, job_timeout_default, NULL); 160 161 static 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 169 static const struct kobj_attribute job_timeout_min_def = 170 __ATTR(job_timeout_min, 0444, job_timeout_min_default, NULL); 171 172 static 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 180 static const struct kobj_attribute job_timeout_max_def = 181 __ATTR(job_timeout_max, 0444, job_timeout_max_default, NULL); 182 183 static 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 205 static 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 230 static 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 239 static const struct kobj_attribute timeslice_duration_max_attr = 240 __ATTR(timeslice_duration_max, 0644, timeslice_duration_max_show, 241 timeslice_duration_max_store); 242 243 static 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 268 static 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 277 static const struct kobj_attribute timeslice_duration_min_attr = 278 __ATTR(timeslice_duration_min, 0644, timeslice_duration_min_show, 279 timeslice_duration_min_store); 280 281 static 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 289 static const struct kobj_attribute timeslice_duration_attr = 290 __ATTR(timeslice_duration_us, 0644, timeslice_duration_show, 291 timeslice_duration_store); 292 293 static 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 301 static const struct kobj_attribute timeslice_duration_def = 302 __ATTR(timeslice_duration_us, 0444, timeslice_default, NULL); 303 304 static 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 312 static const struct kobj_attribute timeslice_duration_min_def = 313 __ATTR(timeslice_duration_min, 0444, timeslice_min_default, NULL); 314 315 static 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 323 static const struct kobj_attribute timeslice_duration_max_def = 324 __ATTR(timeslice_duration_max, 0444, timeslice_max_default, NULL); 325 326 static 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 348 static 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 356 static const struct kobj_attribute preempt_timeout_attr = 357 __ATTR(preempt_timeout_us, 0644, preempt_timeout_show, preempt_timeout_store); 358 359 static 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 368 static const struct kobj_attribute preempt_timeout_def = 369 __ATTR(preempt_timeout_us, 0444, preempt_timeout_default, NULL); 370 371 static 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 380 static const struct kobj_attribute preempt_timeout_min_def = 381 __ATTR(preempt_timeout_min, 0444, preempt_timeout_min_default, NULL); 382 383 static 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 392 static const struct kobj_attribute preempt_timeout_max_def = 393 __ATTR(preempt_timeout_max, 0444, preempt_timeout_max_default, NULL); 394 395 static 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 420 static 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 428 static const struct kobj_attribute preempt_timeout_max_attr = 429 __ATTR(preempt_timeout_max, 0644, preempt_timeout_max_show, 430 preempt_timeout_max_store); 431 432 static 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 457 static 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 465 static const struct kobj_attribute preempt_timeout_min_attr = 466 __ATTR(preempt_timeout_min, 0644, preempt_timeout_min_show, 467 preempt_timeout_min_store); 468 469 static const struct attribute *defaults[] = { 470 &job_timeout_def.attr, 471 &job_timeout_min_def.attr, 472 &job_timeout_max_def.attr, 473 ×lice_duration_def.attr, 474 ×lice_duration_min_def.attr, 475 ×lice_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 482 static const struct attribute * const files[] = { 483 &job_timeout_attr.attr, 484 &job_timeout_min_attr.attr, 485 &job_timeout_max_attr.attr, 486 ×lice_duration_attr.attr, 487 ×lice_duration_min_attr.attr, 488 ×lice_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 495 static void kobj_xe_hw_engine_class_fini(struct drm_device *drm, void *arg) 496 { 497 struct kobject *kobj = arg; 498 499 sysfs_remove_files(kobj, files); 500 kobject_put(kobj); 501 } 502 503 static struct kobj_eclass * 504 kobj_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 = drmm_add_action_or_reset(&xe->drm, kobj_xe_hw_engine_class_fini, 521 &keclass->base); 522 if (err) 523 return NULL; 524 525 return keclass; 526 } 527 528 static void hw_engine_class_defaults_fini(struct drm_device *drm, void *arg) 529 { 530 struct kobject *kobj = arg; 531 532 sysfs_remove_files(kobj, defaults); 533 kobject_put(kobj); 534 } 535 536 static 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 drmm_add_action_or_reset(&xe->drm, hw_engine_class_defaults_fini, kobj); 556 557 err_object: 558 kobject_put(kobj); 559 return err; 560 } 561 562 static void xe_hw_engine_sysfs_kobj_release(struct kobject *kobj) 563 { 564 kfree(kobj); 565 } 566 567 static 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 585 static 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 604 static 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 609 static 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 614 static void hw_engine_class_sysfs_fini(struct drm_device *drm, void *arg) 615 { 616 struct kobject *kobj = arg; 617 618 kobject_put(kobj); 619 } 620 621 static const char *xe_hw_engine_class_to_str(enum xe_engine_class class) 622 { 623 switch (class) { 624 case XE_ENGINE_CLASS_RENDER: 625 return "rcs"; 626 case XE_ENGINE_CLASS_VIDEO_DECODE: 627 return "vcs"; 628 case XE_ENGINE_CLASS_VIDEO_ENHANCE: 629 return "vecs"; 630 case XE_ENGINE_CLASS_COPY: 631 return "bcs"; 632 case XE_ENGINE_CLASS_COMPUTE: 633 return "ccs"; 634 default: 635 return NULL; 636 } 637 } 638 639 /** 640 * xe_hw_engine_class_sysfs_init - Init HW engine classes on GT. 641 * @gt: Xe GT. 642 * 643 * This routine creates sysfs for HW engine classes and adds methods 644 * to get/set different scheduling properties for HW engines class. 645 * 646 * Returns: Returns error value for failure and 0 for success. 647 */ 648 int xe_hw_engine_class_sysfs_init(struct xe_gt *gt) 649 { 650 struct xe_device *xe = gt_to_xe(gt); 651 struct xe_hw_engine *hwe; 652 enum xe_hw_engine_id id; 653 struct kobject *kobj; 654 u16 class_mask = 0; 655 int err = 0; 656 657 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); 658 if (!kobj) 659 return -ENOMEM; 660 661 kobject_init(kobj, &xe_hw_engine_sysfs_kobj_type); 662 663 err = kobject_add(kobj, gt->sysfs, "engines"); 664 if (err) 665 goto err_object; 666 667 for_each_hw_engine(hwe, gt, id) { 668 const char *name; 669 struct kobj_eclass *keclass; 670 671 if (hwe->class == XE_ENGINE_CLASS_OTHER || 672 hwe->class == XE_ENGINE_CLASS_MAX) 673 continue; 674 675 if ((class_mask >> hwe->class) & 1) 676 continue; 677 678 class_mask |= 1 << hwe->class; 679 name = xe_hw_engine_class_to_str(hwe->class); 680 if (!name) { 681 err = -EINVAL; 682 goto err_object; 683 } 684 685 keclass = kobj_xe_hw_engine_class(xe, kobj, name); 686 if (!keclass) { 687 err = -EINVAL; 688 goto err_object; 689 } 690 691 keclass->eclass = hwe->eclass; 692 err = xe_add_hw_engine_class_defaults(xe, &keclass->base); 693 if (err) 694 goto err_object; 695 696 err = sysfs_create_files(&keclass->base, files); 697 if (err) 698 goto err_object; 699 } 700 701 return drmm_add_action_or_reset(&xe->drm, hw_engine_class_sysfs_fini, kobj); 702 703 err_object: 704 kobject_put(kobj); 705 return err; 706 } 707