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