689 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2023 Intel Corporation4 */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 1616static 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 range21 * @timeout: timeout to validate22 * @min: min value of valid range23 * @max: max value of valid range24 *25 * This helper helps to validate if timeout is in min-max range of HW engine26 * scheduler.27 *28 * Returns: Returns false value for failure and true for success.29 */30bool xe_hw_engine_timeout_in_range(u64 timeout, u64 min, u64 max)31{32 return timeout >= min && timeout <= max;33}34 35static void kobj_xe_hw_engine_release(struct kobject *kobj)36{37 kfree(kobj);38}39 40static const struct kobj_type kobj_xe_hw_engine_type = {41 .release = kobj_xe_hw_engine_release,42 .sysfs_ops = &kobj_sysfs_ops43};44 45static 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 70static 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 78static const struct kobj_attribute job_timeout_max_attr =79__ATTR(job_timeout_max, 0644, job_timeout_max_show, job_timeout_max_store);80 81static 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 106static 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 114static const struct kobj_attribute job_timeout_min_attr =115__ATTR(job_timeout_min, 0644, job_timeout_min_show, job_timeout_min_store);116 117static 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 139static 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 147static const struct kobj_attribute job_timeout_attr =148__ATTR(job_timeout_ms, 0644, job_timeout_show, job_timeout_store);149 150static 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 158static const struct kobj_attribute job_timeout_def =159__ATTR(job_timeout_ms, 0444, job_timeout_default, NULL);160 161static 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 169static const struct kobj_attribute job_timeout_min_def =170__ATTR(job_timeout_min, 0444, job_timeout_min_default, NULL);171 172static 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 180static const struct kobj_attribute job_timeout_max_def =181__ATTR(job_timeout_max, 0444, job_timeout_max_default, NULL);182 183static 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 205static 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 230static 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 239static const struct kobj_attribute timeslice_duration_max_attr =240 __ATTR(timeslice_duration_max, 0644, timeslice_duration_max_show,241 timeslice_duration_max_store);242 243static 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 268static 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 277static const struct kobj_attribute timeslice_duration_min_attr =278 __ATTR(timeslice_duration_min, 0644, timeslice_duration_min_show,279 timeslice_duration_min_store);280 281static 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 289static const struct kobj_attribute timeslice_duration_attr =290 __ATTR(timeslice_duration_us, 0644, timeslice_duration_show,291 timeslice_duration_store);292 293static 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 301static const struct kobj_attribute timeslice_duration_def =302__ATTR(timeslice_duration_us, 0444, timeslice_default, NULL);303 304static 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 312static const struct kobj_attribute timeslice_duration_min_def =313__ATTR(timeslice_duration_min, 0444, timeslice_min_default, NULL);314 315static 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 323static const struct kobj_attribute timeslice_duration_max_def =324__ATTR(timeslice_duration_max, 0444, timeslice_max_default, NULL);325 326static 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 348static 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 356static const struct kobj_attribute preempt_timeout_attr =357__ATTR(preempt_timeout_us, 0644, preempt_timeout_show, preempt_timeout_store);358 359static 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 368static const struct kobj_attribute preempt_timeout_def =369__ATTR(preempt_timeout_us, 0444, preempt_timeout_default, NULL);370 371static 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 380static const struct kobj_attribute preempt_timeout_min_def =381__ATTR(preempt_timeout_min, 0444, preempt_timeout_min_default, NULL);382 383static 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 392static const struct kobj_attribute preempt_timeout_max_def =393__ATTR(preempt_timeout_max, 0444, preempt_timeout_max_default, NULL);394 395static 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 420static 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 428static const struct kobj_attribute preempt_timeout_max_attr =429 __ATTR(preempt_timeout_max, 0644, preempt_timeout_max_show,430 preempt_timeout_max_store);431 432static 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 457static 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 465static const struct kobj_attribute preempt_timeout_min_attr =466 __ATTR(preempt_timeout_min, 0644, preempt_timeout_min_show,467 preempt_timeout_min_store);468 469static 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 NULL480};481 482static 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 NULL493};494 495static void kobj_xe_hw_engine_class_fini(void *arg)496{497 struct kobject *kobj = arg;498 499 sysfs_remove_files(kobj, files);500 kobject_put(kobj);501}502 503static struct kobj_eclass *504kobj_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 = devm_add_action_or_reset(xe->drm.dev, kobj_xe_hw_engine_class_fini,521 &keclass->base);522 if (err)523 return NULL;524 525 return keclass;526}527 528static void hw_engine_class_defaults_fini(void *arg)529{530 struct kobject *kobj = arg;531 532 sysfs_remove_files(kobj, defaults);533 kobject_put(kobj);534}535 536static 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 devm_add_action_or_reset(xe->drm.dev, hw_engine_class_defaults_fini, kobj);556 557err_object:558 kobject_put(kobj);559 return err;560}561 562static void xe_hw_engine_sysfs_kobj_release(struct kobject *kobj)563{564 kfree(kobj);565}566 567static 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 585static 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 604static 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 609static 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 614static void hw_engine_class_sysfs_fini(void *arg)615{616 struct kobject *kobj = arg;617 618 kobject_put(kobj);619}620 621/**622 * xe_hw_engine_class_sysfs_init - Init HW engine classes on GT.623 * @gt: Xe GT.624 *625 * This routine creates sysfs for HW engine classes and adds methods626 * to get/set different scheduling properties for HW engines class.627 *628 * Returns: Returns error value for failure and 0 for success.629 */630int xe_hw_engine_class_sysfs_init(struct xe_gt *gt)631{632 struct xe_device *xe = gt_to_xe(gt);633 struct xe_hw_engine *hwe;634 enum xe_hw_engine_id id;635 struct kobject *kobj;636 u16 class_mask = 0;637 int err = 0;638 639 kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);640 if (!kobj)641 return -ENOMEM;642 643 kobject_init(kobj, &xe_hw_engine_sysfs_kobj_type);644 645 err = kobject_add(kobj, gt->sysfs, "engines");646 if (err)647 goto err_object;648 649 for_each_hw_engine(hwe, gt, id) {650 const char *name;651 struct kobj_eclass *keclass;652 653 if (hwe->class == XE_ENGINE_CLASS_OTHER ||654 hwe->class == XE_ENGINE_CLASS_MAX)655 continue;656 657 if ((class_mask >> hwe->class) & 1)658 continue;659 660 class_mask |= 1 << hwe->class;661 name = xe_hw_engine_class_to_str(hwe->class);662 if (!name) {663 err = -EINVAL;664 goto err_object;665 }666 667 keclass = kobj_xe_hw_engine_class(xe, kobj, name);668 if (!keclass) {669 err = -EINVAL;670 goto err_object;671 }672 673 keclass->eclass = hwe->eclass;674 err = xe_add_hw_engine_class_defaults(xe, &keclass->base);675 if (err)676 goto err_object;677 678 err = sysfs_create_files(&keclass->base, files);679 if (err)680 goto err_object;681 }682 683 return devm_add_action_or_reset(xe->drm.dev, hw_engine_class_sysfs_fini, kobj);684 685err_object:686 kobject_put(kobj);687 return err;688}689