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