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/
└── engines
    ├── bcs
    │   └── 0
    │       ├── capabilities
    │       ├── class
    │       ├── id
    │       └── instance
    ├── rcs
    │   └── 0
    │       ├── capabilities
    │       ├── class
    │       ├── id
    │       └── instance
    ├── vcs
    │   ├── 0
    │   │   ├── capabilities
    │   │   │   └── hevc
    │   │   ├── class
    │   │   ├── id
    │   │   └── instance
    │   └── 1
    │       ├── capabilities
    │       ├── class
    │       ├── id
    │       └── instance
    └── vecs
        └── 0
            ├── capabilities
            ├── class
            ├── id
            └── instance

Instance is the instance number of the engine for a particular class :
$ cat 
/sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/bcs/0/instance
0

Id is a global id used from submitting commands from userspace through execbuf :
$ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/bcs/0/id
3

Class maps to enum drm_i915_gem_engine_class in i915_drm.h :
$ cat /sys/devices/pci0000\:00/0000\:00\:02.0/drm/card0/gt/engines/bcs/0/class
1

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)

v3: Move engines to drm/card/gt/engines/ (Tvrtko)
    Add instance attribute to engines (Tvrtko)

v4: Fix dev_priv->gt_topology.engines_classes_kobj size (Lionel)

Signed-off-by: Lionel Landwerlin <lionel.g.landwer...@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         |   6 ++
 drivers/gpu/drm/i915/i915_sysfs.c       | 178 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_engine_cs.c  |  12 +++
 drivers/gpu/drm/i915/intel_ringbuffer.h |   4 +
 4 files changed, 200 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0a8e8a3772e5..893ecb0d4639 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2731,6 +2731,12 @@ struct drm_i915_private {
                } oa;
        } perf;
 
+       struct {
+               struct kobject gt_kobj;
+               struct kobject engines_kobj;
+               struct kobject engines_classes_kobjs[MAX_ENGINE_CLASS + 1];
+       } 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_sysfs.c 
b/drivers/gpu/drm/i915/i915_sysfs.c
index c74a20b80182..d8ec8ec51cca 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -570,6 +570,178 @@ static void i915_setup_error_capture(struct device *kdev) 
{}
 static void i915_teardown_error_capture(struct device *kdev) {}
 #endif
 
+static struct attribute engine_class_attr = {
+       .name = "class",
+       .mode = 0444,
+};
+
+static struct attribute engine_id_attr = {
+       .name = "id",
+       .mode = 0444,
+};
+
+static struct attribute engine_instance_attr = {
+       .name = "instance",
+       .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_class_attr)
+               return sprintf(buf, "%hhu\n", engine->uabi_class);
+       if (attr == &engine_id_attr)
+               return sprintf(buf, "%hhu\n", engine->uabi_id);
+       if (attr == &engine_instance_attr)
+               return sprintf(buf, "%hhu\n", engine->instance);
+       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;
+       struct kobject *engines_kobj = &dev_priv->gt_topology.engines_kobj;
+       bool registred[MAX_ENGINE_CLASS + 1] = { false, };
+       int ret;
+
+       ret = kobject_init_and_add(engines_kobj, gt_kobj->ktype, gt_kobj,
+                                  "engines");
+       if (ret)
+               return ret;
+
+       for_each_engine(engine_for_class, dev_priv, id_for_class) {
+               struct kobject *engine_class_kobj =
+                       
&dev_priv->gt_topology.engines_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,
+                                          engines_kobj->ktype,
+                                          engines_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_class_attr);
+                       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_instance_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_class_attr);
+               sysfs_remove_file(&engine->instance_kobj, &engine_id_attr);
+               sysfs_remove_file(&engine->instance_kobj, 
&engine_instance_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.gt_kobj,
+                                  kdev->kobj.ktype,
+                                  &kdev->kobj,
+                                  "gt");
+       if (ret)
+               return ret;
+
+       return i915_setup_engines_sysfs(dev_priv, 
&dev_priv->gt_topology.gt_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.gt_kobj);
+       kobject_del(&dev_priv->gt_topology.gt_kobj);
+}
+
 void i915_setup_sysfs(struct drm_i915_private *dev_priv)
 {
        struct device *kdev = dev_priv->drm.primary->kdev;
@@ -616,6 +788,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);
 }
 
@@ -625,6 +801,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 86d4c85c8725..7bda1c283f2c 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -131,6 +131,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 9c4434438965..dc4eeb897407 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -282,6 +282,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;
@@ -995,6 +998,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.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to