14ec76dbeSChris Wilson // SPDX-License-Identifier: MIT 24ec76dbeSChris Wilson /* 34ec76dbeSChris Wilson * Copyright © 2019 Intel Corporation 44ec76dbeSChris Wilson */ 54ec76dbeSChris Wilson 64ec76dbeSChris Wilson #include <linux/kobject.h> 74ec76dbeSChris Wilson #include <linux/sysfs.h> 84ec76dbeSChris Wilson 94ec76dbeSChris Wilson #include "i915_drv.h" 104ec76dbeSChris Wilson #include "intel_engine.h" 114ec76dbeSChris Wilson #include "sysfs_engines.h" 124ec76dbeSChris Wilson 134ec76dbeSChris Wilson struct kobj_engine { 144ec76dbeSChris Wilson struct kobject base; 154ec76dbeSChris Wilson struct intel_engine_cs *engine; 164ec76dbeSChris Wilson }; 174ec76dbeSChris Wilson 184ec76dbeSChris Wilson static struct intel_engine_cs *kobj_to_engine(struct kobject *kobj) 194ec76dbeSChris Wilson { 204ec76dbeSChris Wilson return container_of(kobj, struct kobj_engine, base)->engine; 214ec76dbeSChris Wilson } 224ec76dbeSChris Wilson 234ec76dbeSChris Wilson static ssize_t 244ec76dbeSChris Wilson name_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 254ec76dbeSChris Wilson { 264ec76dbeSChris Wilson return sprintf(buf, "%s\n", kobj_to_engine(kobj)->name); 274ec76dbeSChris Wilson } 284ec76dbeSChris Wilson 294ec76dbeSChris Wilson static struct kobj_attribute name_attr = 304ec76dbeSChris Wilson __ATTR(name, 0444, name_show, NULL); 314ec76dbeSChris Wilson 324ec76dbeSChris Wilson static ssize_t 334ec76dbeSChris Wilson class_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 344ec76dbeSChris Wilson { 354ec76dbeSChris Wilson return sprintf(buf, "%d\n", kobj_to_engine(kobj)->uabi_class); 364ec76dbeSChris Wilson } 374ec76dbeSChris Wilson 384ec76dbeSChris Wilson static struct kobj_attribute class_attr = 394ec76dbeSChris Wilson __ATTR(class, 0444, class_show, NULL); 404ec76dbeSChris Wilson 414ec76dbeSChris Wilson static ssize_t 424ec76dbeSChris Wilson inst_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 434ec76dbeSChris Wilson { 444ec76dbeSChris Wilson return sprintf(buf, "%d\n", kobj_to_engine(kobj)->uabi_instance); 454ec76dbeSChris Wilson } 464ec76dbeSChris Wilson 474ec76dbeSChris Wilson static struct kobj_attribute inst_attr = 484ec76dbeSChris Wilson __ATTR(instance, 0444, inst_show, NULL); 494ec76dbeSChris Wilson 506e57cc39SChris Wilson static ssize_t 516e57cc39SChris Wilson mmio_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 526e57cc39SChris Wilson { 536e57cc39SChris Wilson return sprintf(buf, "0x%x\n", kobj_to_engine(kobj)->mmio_base); 546e57cc39SChris Wilson } 556e57cc39SChris Wilson 566e57cc39SChris Wilson static struct kobj_attribute mmio_attr = 576e57cc39SChris Wilson __ATTR(mmio_base, 0444, mmio_show, NULL); 586e57cc39SChris Wilson 594ec76dbeSChris Wilson static const char * const vcs_caps[] = { 604ec76dbeSChris Wilson [ilog2(I915_VIDEO_CLASS_CAPABILITY_HEVC)] = "hevc", 614ec76dbeSChris Wilson [ilog2(I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC)] = "sfc", 624ec76dbeSChris Wilson }; 634ec76dbeSChris Wilson 644ec76dbeSChris Wilson static const char * const vecs_caps[] = { 654ec76dbeSChris Wilson [ilog2(I915_VIDEO_AND_ENHANCE_CLASS_CAPABILITY_SFC)] = "sfc", 664ec76dbeSChris Wilson }; 674ec76dbeSChris Wilson 684ec76dbeSChris Wilson static ssize_t repr_trim(char *buf, ssize_t len) 694ec76dbeSChris Wilson { 704ec76dbeSChris Wilson /* Trim off the trailing space and replace with a newline */ 714ec76dbeSChris Wilson if (len > PAGE_SIZE) 724ec76dbeSChris Wilson len = PAGE_SIZE; 734ec76dbeSChris Wilson if (len > 0) 744ec76dbeSChris Wilson buf[len - 1] = '\n'; 754ec76dbeSChris Wilson 764ec76dbeSChris Wilson return len; 774ec76dbeSChris Wilson } 784ec76dbeSChris Wilson 794ec76dbeSChris Wilson static ssize_t 804ec76dbeSChris Wilson __caps_show(struct intel_engine_cs *engine, 814ec76dbeSChris Wilson u32 caps, char *buf, bool show_unknown) 824ec76dbeSChris Wilson { 834ec76dbeSChris Wilson const char * const *repr; 844ec76dbeSChris Wilson int count, n; 854ec76dbeSChris Wilson ssize_t len; 864ec76dbeSChris Wilson 874ec76dbeSChris Wilson BUILD_BUG_ON(!typecheck(typeof(caps), engine->uabi_capabilities)); 884ec76dbeSChris Wilson 894ec76dbeSChris Wilson switch (engine->class) { 904ec76dbeSChris Wilson case VIDEO_DECODE_CLASS: 914ec76dbeSChris Wilson repr = vcs_caps; 924ec76dbeSChris Wilson count = ARRAY_SIZE(vcs_caps); 934ec76dbeSChris Wilson break; 944ec76dbeSChris Wilson 954ec76dbeSChris Wilson case VIDEO_ENHANCEMENT_CLASS: 964ec76dbeSChris Wilson repr = vecs_caps; 974ec76dbeSChris Wilson count = ARRAY_SIZE(vecs_caps); 984ec76dbeSChris Wilson break; 994ec76dbeSChris Wilson 1004ec76dbeSChris Wilson default: 1014ec76dbeSChris Wilson repr = NULL; 1024ec76dbeSChris Wilson count = 0; 1034ec76dbeSChris Wilson break; 1044ec76dbeSChris Wilson } 1054ec76dbeSChris Wilson GEM_BUG_ON(count > BITS_PER_TYPE(typeof(caps))); 1064ec76dbeSChris Wilson 1074ec76dbeSChris Wilson len = 0; 1084ec76dbeSChris Wilson for_each_set_bit(n, 1094ec76dbeSChris Wilson (unsigned long *)&caps, 1104ec76dbeSChris Wilson show_unknown ? BITS_PER_TYPE(typeof(caps)) : count) { 1114ec76dbeSChris Wilson if (n >= count || !repr[n]) { 1124ec76dbeSChris Wilson if (GEM_WARN_ON(show_unknown)) 1134ec76dbeSChris Wilson len += snprintf(buf + len, PAGE_SIZE - len, 1144ec76dbeSChris Wilson "[%x] ", n); 1154ec76dbeSChris Wilson } else { 1164ec76dbeSChris Wilson len += snprintf(buf + len, PAGE_SIZE - len, 1174ec76dbeSChris Wilson "%s ", repr[n]); 1184ec76dbeSChris Wilson } 1194ec76dbeSChris Wilson if (GEM_WARN_ON(len >= PAGE_SIZE)) 1204ec76dbeSChris Wilson break; 1214ec76dbeSChris Wilson } 1224ec76dbeSChris Wilson return repr_trim(buf, len); 1234ec76dbeSChris Wilson } 1244ec76dbeSChris Wilson 1254ec76dbeSChris Wilson static ssize_t 1264ec76dbeSChris Wilson caps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 1274ec76dbeSChris Wilson { 1284ec76dbeSChris Wilson struct intel_engine_cs *engine = kobj_to_engine(kobj); 1294ec76dbeSChris Wilson 1304ec76dbeSChris Wilson return __caps_show(engine, engine->uabi_capabilities, buf, true); 1314ec76dbeSChris Wilson } 1324ec76dbeSChris Wilson 1334ec76dbeSChris Wilson static struct kobj_attribute caps_attr = 1344ec76dbeSChris Wilson __ATTR(capabilities, 0444, caps_show, NULL); 1354ec76dbeSChris Wilson 1364ec76dbeSChris Wilson static ssize_t 1374ec76dbeSChris Wilson all_caps_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) 1384ec76dbeSChris Wilson { 1394ec76dbeSChris Wilson return __caps_show(kobj_to_engine(kobj), -1, buf, false); 1404ec76dbeSChris Wilson } 1414ec76dbeSChris Wilson 1424ec76dbeSChris Wilson static struct kobj_attribute all_caps_attr = 1434ec76dbeSChris Wilson __ATTR(known_capabilities, 0444, all_caps_show, NULL); 1444ec76dbeSChris Wilson 1454ec76dbeSChris Wilson static void kobj_engine_release(struct kobject *kobj) 1464ec76dbeSChris Wilson { 1474ec76dbeSChris Wilson kfree(kobj); 1484ec76dbeSChris Wilson } 1494ec76dbeSChris Wilson 1504ec76dbeSChris Wilson static struct kobj_type kobj_engine_type = { 1514ec76dbeSChris Wilson .release = kobj_engine_release, 1524ec76dbeSChris Wilson .sysfs_ops = &kobj_sysfs_ops 1534ec76dbeSChris Wilson }; 1544ec76dbeSChris Wilson 1554ec76dbeSChris Wilson static struct kobject * 1564ec76dbeSChris Wilson kobj_engine(struct kobject *dir, struct intel_engine_cs *engine) 1574ec76dbeSChris Wilson { 1584ec76dbeSChris Wilson struct kobj_engine *ke; 1594ec76dbeSChris Wilson 1604ec76dbeSChris Wilson ke = kzalloc(sizeof(*ke), GFP_KERNEL); 1614ec76dbeSChris Wilson if (!ke) 1624ec76dbeSChris Wilson return NULL; 1634ec76dbeSChris Wilson 1644ec76dbeSChris Wilson kobject_init(&ke->base, &kobj_engine_type); 1654ec76dbeSChris Wilson ke->engine = engine; 1664ec76dbeSChris Wilson 1674ec76dbeSChris Wilson if (kobject_add(&ke->base, dir, "%s", engine->name)) { 1684ec76dbeSChris Wilson kobject_put(&ke->base); 1694ec76dbeSChris Wilson return NULL; 1704ec76dbeSChris Wilson } 1714ec76dbeSChris Wilson 1724ec76dbeSChris Wilson /* xfer ownership to sysfs tree */ 1734ec76dbeSChris Wilson return &ke->base; 1744ec76dbeSChris Wilson } 1754ec76dbeSChris Wilson 1764ec76dbeSChris Wilson void intel_engines_add_sysfs(struct drm_i915_private *i915) 1774ec76dbeSChris Wilson { 1784ec76dbeSChris Wilson static const struct attribute *files[] = { 1794ec76dbeSChris Wilson &name_attr.attr, 1804ec76dbeSChris Wilson &class_attr.attr, 1814ec76dbeSChris Wilson &inst_attr.attr, 1826e57cc39SChris Wilson &mmio_attr.attr, 1834ec76dbeSChris Wilson &caps_attr.attr, 1844ec76dbeSChris Wilson &all_caps_attr.attr, 1854ec76dbeSChris Wilson NULL 1864ec76dbeSChris Wilson }; 1874ec76dbeSChris Wilson 1884ec76dbeSChris Wilson struct device *kdev = i915->drm.primary->kdev; 1894ec76dbeSChris Wilson struct intel_engine_cs *engine; 1904ec76dbeSChris Wilson struct kobject *dir; 1914ec76dbeSChris Wilson 1924ec76dbeSChris Wilson dir = kobject_create_and_add("engine", &kdev->kobj); 1934ec76dbeSChris Wilson if (!dir) 1944ec76dbeSChris Wilson return; 1954ec76dbeSChris Wilson 1964ec76dbeSChris Wilson for_each_uabi_engine(engine, i915) { 1974ec76dbeSChris Wilson struct kobject *kobj; 1984ec76dbeSChris Wilson 1994ec76dbeSChris Wilson kobj = kobj_engine(dir, engine); 2004ec76dbeSChris Wilson if (!kobj) 2014ec76dbeSChris Wilson goto err_engine; 2024ec76dbeSChris Wilson 2034ec76dbeSChris Wilson if (sysfs_create_files(kobj, files)) 2044ec76dbeSChris Wilson goto err_object; 2054ec76dbeSChris Wilson 2064ec76dbeSChris Wilson if (0) { 2074ec76dbeSChris Wilson err_object: 2084ec76dbeSChris Wilson kobject_put(kobj); 2094ec76dbeSChris Wilson err_engine: 2104ec76dbeSChris Wilson dev_err(kdev, "Failed to add sysfs engine '%s'\n", 2114ec76dbeSChris Wilson engine->name); 2124ec76dbeSChris Wilson break; 2134ec76dbeSChris Wilson } 2144ec76dbeSChris Wilson } 2154ec76dbeSChris Wilson } 216