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 ×lice_duration_def.attr, 517 ×lice_duration_min_def.attr, 518 ×lice_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 ×lice_duration_attr.attr, 530 ×lice_duration_min_attr.attr, 531 ×lice_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