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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 const 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 ×lice_duration_def.attr, 472 ×lice_duration_min_def.attr, 473 ×lice_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 * const files[] = { 481 &job_timeout_attr.attr, 482 &job_timeout_min_attr.attr, 483 &job_timeout_max_attr.attr, 484 ×lice_duration_attr.attr, 485 ×lice_duration_min_attr.attr, 486 ×lice_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