[PATCH v2 3/4] drm/i915: expose engine availability through sysfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This enables userspace to discover the engines available on the GPU.
Here is the layout on a Skylake GT4:

/sys/devices/pci0000:00/0000:00:02.0/drm/card0/gt
├── bcs
│   └── 0
│       ├── capabilities
│       ├── class
│       └── id
├── rcs
│   └── 0
│       ├── capabilities
│       ├── class
│       └── id
├── vcs
│   ├── 0
│   │   ├── capabilities
│   │   │   └── hevc
│   │   ├── class
│   │   └── id
│   └── 1
│       ├── capabilities
│       ├── class
│       └── id
└── vecs
    └── 0
        ├── capabilities
        ├── class
        └── id

Further capabilities can be added later as attributes of each engine.

v2: Add capabilities sub directory (Tvrtko)
    Move engines directory to drm/card/gt (Chris)

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@xxxxxxxxx>
---
 drivers/gpu/drm/i915/i915_drv.h         |   5 +
 drivers/gpu/drm/i915/i915_reg.h         |   1 +
 drivers/gpu/drm/i915/i915_sysfs.c       | 160 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_engine_cs.c  |  12 +++
 drivers/gpu/drm/i915/intel_ringbuffer.h |   4 +
 5 files changed, 182 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f8d239d8bfab..22ac96d2ef42 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2729,6 +2729,11 @@ struct drm_i915_private {
 		} oa;
 	} perf;
 
+	struct {
+		struct kobject kobj;
+		struct kobject classes_kobjs[MAX_ENGINE_CLASS];
+	} gt_topology;
+
 	/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
 	struct {
 		void (*resume)(struct drm_i915_private *);
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 107e2d7c9fba..5d1ef1314547 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -186,6 +186,7 @@ static inline bool i915_mmio_reg_valid(i915_reg_t reg)
 #define VIDEO_ENHANCEMENT_CLASS	2
 #define COPY_ENGINE_CLASS	3
 #define OTHER_CLASS		4
+#define MAX_ENGINE_CLASS	5
 
 /* PCI config space */
 
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 791759f632e1..fd04d0b93eaf 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -559,6 +559,160 @@ static void i915_setup_error_capture(struct device *kdev) {}
 static void i915_teardown_error_capture(struct device *kdev) {}
 #endif
 
+static struct attribute engine_id_attr = {
+	.name = "id",
+	.mode = 0444,
+};
+
+static struct attribute engine_class_attr = {
+	.name = "class",
+	.mode = 0444,
+};
+
+static ssize_t
+show_engine_attr(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct intel_engine_cs *engine =
+		container_of(kobj, struct intel_engine_cs, instance_kobj);
+
+	if (attr == &engine_id_attr)
+		return sprintf(buf, "%hhu\n", engine->uabi_id);
+	if (attr == &engine_class_attr)
+		return sprintf(buf, "%hhu\n", engine->uabi_class);
+	return sprintf(buf, "\n");
+}
+
+static const struct sysfs_ops engine_ops = {
+	.show = show_engine_attr,
+};
+
+static struct kobj_type engine_type = {
+	.sysfs_ops = &engine_ops,
+};
+
+static struct attribute engine_capability_hevc_attr = {
+	.name = "hevc",
+	.mode = 0444,
+};
+
+static ssize_t
+show_engine_capabilities_attr(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct intel_engine_cs *engine =
+		container_of(kobj, struct intel_engine_cs, capabilities_kobj);
+
+	if (attr == &engine_capability_hevc_attr)
+		return sprintf(buf, "%i\n", INTEL_GEN(engine->i915) >= 8);
+	return sprintf(buf, "\n");
+}
+
+static const struct sysfs_ops engine_capabilities_ops = {
+	.show = show_engine_capabilities_attr,
+};
+
+static struct kobj_type engine_capabilities_type = {
+	.sysfs_ops = &engine_capabilities_ops,
+};
+
+static int i915_setup_engines_sysfs(struct drm_i915_private *dev_priv,
+				    struct kobject *gt_kobj)
+{
+	struct intel_engine_cs *engine_for_class, *engine;
+	enum intel_engine_id id_for_class, id;
+	bool registred[MAX_ENGINE_CLASS] = { false, };
+	int ret;
+
+	for_each_engine(engine_for_class, dev_priv, id_for_class) {
+		struct kobject *engine_class_kobj =
+			&dev_priv->gt_topology.classes_kobjs[engine_for_class->class];
+
+		if (registred[engine_for_class->class])
+			continue;
+
+		registred[engine_for_class->class] = true;
+
+		ret = kobject_init_and_add(engine_class_kobj,
+					   gt_kobj->ktype,
+					   gt_kobj,
+					   intel_engine_get_class_name(engine_for_class));
+		if (ret)
+			return ret;
+
+		for_each_engine(engine, dev_priv, id) {
+			if (engine->class != engine_for_class->class)
+				continue;
+
+			ret = kobject_init_and_add(&engine->instance_kobj,
+						   &engine_type,
+						   engine_class_kobj,
+						   "%d", engine->instance);
+			if (ret)
+				return ret;
+
+			ret = sysfs_create_file(&engine->instance_kobj,
+						&engine_id_attr);
+			if (ret)
+				return ret;
+			ret = sysfs_create_file(&engine->instance_kobj,
+						&engine_class_attr);
+			if (ret)
+				return ret;
+
+			ret = kobject_init_and_add(&engine->capabilities_kobj,
+						   &engine_capabilities_type,
+						   &engine->instance_kobj,
+						   "capabilities");
+			if (ret)
+				return ret;
+
+			if (engine->id == VCS) {
+				ret = sysfs_create_file(&engine->capabilities_kobj,
+							&engine_capability_hevc_attr);
+				if (ret)
+					return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void i915_teardown_engines_sysfs(struct drm_i915_private *dev_priv)
+{
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+
+	for_each_engine(engine, dev_priv, id) {
+		sysfs_remove_file(&engine->instance_kobj, &engine_id_attr);
+		sysfs_remove_file(&engine->instance_kobj, &engine_class_attr);
+		sysfs_remove_file(&engine->capabilities_kobj,
+				  &engine_capability_hevc_attr);
+	}
+}
+
+static int i915_setup_gt_sysfs(struct drm_i915_private *dev_priv,
+			       struct device *kdev)
+{
+	int ret;
+
+	ret = kobject_init_and_add(&dev_priv->gt_topology.kobj,
+				   kdev->kobj.ktype,
+				   &kdev->kobj,
+				   "gt");
+	if (ret)
+		return ret;
+
+	return i915_setup_engines_sysfs(dev_priv, &dev_priv->gt_topology.kobj);
+}
+
+static void i915_teardown_gt_sysfs(struct drm_i915_private *dev_priv)
+{
+	i915_teardown_engines_sysfs(dev_priv);
+
+	kobject_get(&dev_priv->gt_topology.kobj);
+	kobject_del(&dev_priv->gt_topology.kobj);
+}
+
 void i915_setup_sysfs(struct drm_i915_private *dev_priv)
 {
 	struct device *kdev = dev_priv->drm.primary->kdev;
@@ -605,6 +759,10 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv)
 	if (ret)
 		DRM_ERROR("RPS sysfs setup failed\n");
 
+	ret = i915_setup_gt_sysfs(dev_priv, kdev);
+	if (ret)
+		DRM_ERROR("GT sysfs setup failed\n");
+
 	i915_setup_error_capture(kdev);
 }
 
@@ -614,6 +772,8 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
 
 	i915_teardown_error_capture(kdev);
 
+	i915_teardown_gt_sysfs(dev_priv);
+
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 		sysfs_remove_files(&kdev->kobj, vlv_attrs);
 	else
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index 9897c7f78c51..9d82dfbb45db 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -133,6 +133,18 @@ static const struct engine_info intel_engines[] = {
 	},
 };
 
+/**
+ * intel_engine_get_class_name() - return the name of the class for an engine
+ * @engine: engine
+ *
+ * Return: a string naming the class of the engine
+ */
+const char *
+intel_engine_get_class_name(struct intel_engine_cs *engine)
+{
+	return intel_engine_classes[engine->class].name;
+}
+
 /**
  * ___intel_engine_context_size() - return the size of the context for an engine
  * @dev_priv: i915 device private
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 5f96533e5341..eca6c87a1e06 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -290,6 +290,9 @@ struct intel_engine_cs {
 	struct drm_i915_private *i915;
 	char name[INTEL_ENGINE_CS_MAX_NAME];
 
+	struct kobject instance_kobj;
+	struct kobject capabilities_kobj;
+
 	enum intel_engine_id id;
 	unsigned int hw_id;
 	unsigned int guc_id;
@@ -924,6 +927,7 @@ gen8_emit_ggtt_write(u32 *cs, u32 value, u32 gtt_offset)
 	return cs;
 }
 
+const char *intel_engine_get_class_name(struct intel_engine_cs *engine);
 bool intel_engine_is_idle(struct intel_engine_cs *engine);
 bool intel_engines_are_idle(struct drm_i915_private *dev_priv);
 
-- 
2.15.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux