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