diff mbox

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

Message ID 20171116160004.22720-5-lionel.g.landwerlin@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Lionel Landwerlin Nov. 16, 2017, 4 p.m. UTC
This enables userspace to discover the engines available on the GPU.
Here is the layout :

/sys/devices/pci0000:00/0000:00:02.0/drm/card0/engines
├── bcs0
│   ├── class
│   └── instance
├── rcs0
│   ├── class
│   └── instance
├── vcs0
│   ├── class
│   ├── hevc
│   └── instance
├── vcs1
│   ├── class
│   └── instance
└── vecs0
    ├── class
    └── instance

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

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h         |  1 +
 drivers/gpu/drm/i915/i915_sysfs.c       | 92 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |  2 +
 3 files changed, 95 insertions(+)

Comments

Tvrtko Ursulin Nov. 17, 2017, 9:51 a.m. UTC | #1
On 16/11/2017 16:00, Lionel Landwerlin wrote:
> This enables userspace to discover the engines available on the GPU.
> Here is the layout :
> 
> /sys/devices/pci0000:00/0000:00:02.0/drm/card0/engines
> ├── bcs0
> │   ├── class
> │   └── instance
> ├── rcs0
> │   ├── class
> │   └── instance
> ├── vcs0
> │   ├── class
> │   ├── hevc

For engine capabilities I was considering two alternatives since I think 
both would be better than stuffing individual files on the same level as 
class and instance.

Option 1:

$ cat vcs0/capabilities
hevc

Essentially a list of tokens similar to the cpu info string in 
/proc/cpuinfo.

Option 2, more subdirectories:

$ ls -1 vcs0/capabilities
hevc

Option 2 might be easier for userspace to parse? But more annoying to 
implement in i915 I think. So not sure.

Otherwise I am quite happy with the sysfs approach. Can't think of any 
real downsides at the moment.

Regards,

Tvrtko

> │   └── instance
> ├── vcs1
> │   ├── class
> │   └── instance
> └── vecs0
>      ├── class
>      └── instance
> 
> Further capabilities can be added later as attributes of each engine.
> 
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h         |  1 +
>   drivers/gpu/drm/i915/i915_sysfs.c       | 92 +++++++++++++++++++++++++++++++++
>   drivers/gpu/drm/i915/intel_ringbuffer.h |  2 +
>   3 files changed, 95 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 44b807421af8..c4f6e8ecf212 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2749,6 +2749,7 @@ struct drm_i915_private {
>   
>   	struct {
>   		struct intel_topology_kobject kobj;
> +		struct kobject engines_kobj;
>   
>   		struct sysfs_slice {
>   			struct intel_slice_kobject kobj;
> diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
> index 1d835f164d80..992aeaa91565 100644
> --- a/drivers/gpu/drm/i915/i915_sysfs.c
> +++ b/drivers/gpu/drm/i915/i915_sysfs.c
> @@ -712,6 +712,92 @@ static void i915_teardown_topology_sysfs(struct drm_i915_private *dev_priv)
>   	kobject_del(&topology_kobj->kobj);
>   }
>   
> +static struct attribute engine_instance_attr = {
> +	.name = "instance",
> +	.mode = 0444,
> +};
> +
> +static struct attribute engine_class_attr = {
> +	.name = "class",
> +	.mode = 0444,
> +};
> +
> +static struct attribute engine_hevc_attr = {
> +	.name = "hevc",
> +	.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, kobj);
> +
> +	if (attr == &engine_instance_attr)
> +		return sprintf(buf, "%hhu\n", engine->uabi_id);
> +	if (attr == &engine_class_attr)
> +		return sprintf(buf, "%hhu\n", engine->uabi_class);
> +	if (attr == &engine_hevc_attr)
> +		return sprintf(buf, "%i\n", INTEL_GEN(engine->i915) >= 8);
> +	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 int i915_setup_engines_sysfs(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_engine_cs *engine;
> +	enum intel_engine_id id;
> +
> +	kobject_init_and_add(&dev_priv->topology.engines_kobj,
> +			     dev_priv->drm.primary->kdev->kobj.ktype,
> +			     &dev_priv->drm.primary->kdev->kobj,
> +			     "engines");
> +
> +	for_each_engine(engine, dev_priv, id) {
> +		int ret;
> +
> +		kobject_init_and_add(&engine->kobj, &engine_type,
> +				     &dev_priv->topology.engines_kobj,
> +				     engine->name);
> +
> +		ret = sysfs_create_file(&engine->kobj, &engine_instance_attr);
> +		if (ret)
> +			return ret;
> +		ret = sysfs_create_file(&engine->kobj, &engine_class_attr);
> +		if (ret)
> +			return ret;
> +		if (engine->id == VCS) {
> +			ret = sysfs_create_file(&engine->kobj, &engine_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->kobj, &engine_instance_attr);
> +		sysfs_remove_file(&engine->kobj, &engine_class_attr);
> +		sysfs_remove_file(&engine->kobj, &engine_hevc_attr);
> +	}
> +
> +	kobject_get(&dev_priv->topology.engines_kobj);
> +	kobject_del(&dev_priv->topology.engines_kobj);
> +}
> +
>   void i915_setup_sysfs(struct drm_i915_private *dev_priv)
>   {
>   	struct device *kdev = dev_priv->drm.primary->kdev;
> @@ -762,6 +848,10 @@ void i915_setup_sysfs(struct drm_i915_private *dev_priv)
>   	if (ret)
>   		DRM_ERROR("Topology sysfs setup failed\n");
>   
> +	ret = i915_setup_engines_sysfs(dev_priv);
> +	if (ret)
> +		DRM_ERROR("Engines sysfs setup failed\n");
> +
>   	i915_setup_error_capture(kdev);
>   }
>   
> @@ -771,6 +861,8 @@ void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
>   
>   	i915_teardown_error_capture(kdev);
>   
> +	i915_teardown_engines_sysfs(dev_priv);
> +
>   	i915_teardown_topology_sysfs(dev_priv);
>   
>   	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index 5f96533e5341..0243a9e620da 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -290,6 +290,8 @@ struct intel_engine_cs {
>   	struct drm_i915_private *i915;
>   	char name[INTEL_ENGINE_CS_MAX_NAME];
>   
> +	struct kobject kobj;
> +
>   	enum intel_engine_id id;
>   	unsigned int hw_id;
>   	unsigned int guc_id;
>
Lionel Landwerlin Nov. 17, 2017, 10:48 a.m. UTC | #2
On 17/11/17 09:51, Tvrtko Ursulin wrote:
>
> On 16/11/2017 16:00, Lionel Landwerlin wrote:
>> This enables userspace to discover the engines available on the GPU.
>> Here is the layout :
>>
>> /sys/devices/pci0000:00/0000:00:02.0/drm/card0/engines
>> ├── bcs0
>> │   ├── class
>> │   └── instance
>> ├── rcs0
>> │   ├── class
>> │   └── instance
>> ├── vcs0
>> │   ├── class
>> │   ├── hevc
>
> For engine capabilities I was considering two alternatives since I 
> think both would be better than stuffing individual files on the same 
> level as class and instance.
>
> Option 1:
>
> $ cat vcs0/capabilities
> hevc
>
> Essentially a list of tokens similar to the cpu info string in 
> /proc/cpuinfo.
>
> Option 2, more subdirectories:
>
> $ ls -1 vcs0/capabilities
> hevc
>
> Option 2 might be easier for userspace to parse? But more annoying to 
> implement in i915 I think. So not sure.
>
> Otherwise I am quite happy with the sysfs approach. Can't think of any 
> real downsides at the moment.
>
> Regards,
>
> Tvrtko

Now that I'm familiar with kobject/sysfs, option 1 or 2 is about the 
same amount of work.
Just let me know what you prefer.

I would also take suggestions about the layout, is card0/engines the 
right places?
Should I rename card0/topology to card0/eu_topology?
You could argue that both engines & eus are part of the topology of the 
GPU...

>
>> │   └── instance
>> ├── vcs1
>> │   ├── class
>> │   └── instance
>> └── vecs0
>>      ├── class
>>      └── instance
>>
>> Further capabilities can be added later as attributes of each engine.
>>
>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
>> ---
>>   drivers/gpu/drm/i915/i915_drv.h         |  1 +
>>   drivers/gpu/drm/i915/i915_sysfs.c       | 92 
>> +++++++++++++++++++++++++++++++++
>>   drivers/gpu/drm/i915/intel_ringbuffer.h |  2 +
>>   3 files changed, 95 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/i915/i915_drv.h 
>> b/drivers/gpu/drm/i915/i915_drv.h
>> index 44b807421af8..c4f6e8ecf212 100644
>> --- a/drivers/gpu/drm/i915/i915_drv.h
>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>> @@ -2749,6 +2749,7 @@ struct drm_i915_private {
>>         struct {
>>           struct intel_topology_kobject kobj;
>> +        struct kobject engines_kobj;
>>             struct sysfs_slice {
>>               struct intel_slice_kobject kobj;
>> diff --git a/drivers/gpu/drm/i915/i915_sysfs.c 
>> b/drivers/gpu/drm/i915/i915_sysfs.c
>> index 1d835f164d80..992aeaa91565 100644
>> --- a/drivers/gpu/drm/i915/i915_sysfs.c
>> +++ b/drivers/gpu/drm/i915/i915_sysfs.c
>> @@ -712,6 +712,92 @@ static void i915_teardown_topology_sysfs(struct 
>> drm_i915_private *dev_priv)
>>       kobject_del(&topology_kobj->kobj);
>>   }
>>   +static struct attribute engine_instance_attr = {
>> +    .name = "instance",
>> +    .mode = 0444,
>> +};
>> +
>> +static struct attribute engine_class_attr = {
>> +    .name = "class",
>> +    .mode = 0444,
>> +};
>> +
>> +static struct attribute engine_hevc_attr = {
>> +    .name = "hevc",
>> +    .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, kobj);
>> +
>> +    if (attr == &engine_instance_attr)
>> +        return sprintf(buf, "%hhu\n", engine->uabi_id);
>> +    if (attr == &engine_class_attr)
>> +        return sprintf(buf, "%hhu\n", engine->uabi_class);
>> +    if (attr == &engine_hevc_attr)
>> +        return sprintf(buf, "%i\n", INTEL_GEN(engine->i915) >= 8);
>> +    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 int i915_setup_engines_sysfs(struct drm_i915_private *dev_priv)
>> +{
>> +    struct intel_engine_cs *engine;
>> +    enum intel_engine_id id;
>> +
>> + kobject_init_and_add(&dev_priv->topology.engines_kobj,
>> + dev_priv->drm.primary->kdev->kobj.ktype,
>> + &dev_priv->drm.primary->kdev->kobj,
>> +                 "engines");
>> +
>> +    for_each_engine(engine, dev_priv, id) {
>> +        int ret;
>> +
>> +        kobject_init_and_add(&engine->kobj, &engine_type,
>> +                     &dev_priv->topology.engines_kobj,
>> +                     engine->name);
>> +
>> +        ret = sysfs_create_file(&engine->kobj, &engine_instance_attr);
>> +        if (ret)
>> +            return ret;
>> +        ret = sysfs_create_file(&engine->kobj, &engine_class_attr);
>> +        if (ret)
>> +            return ret;
>> +        if (engine->id == VCS) {
>> +            ret = sysfs_create_file(&engine->kobj, &engine_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->kobj, &engine_instance_attr);
>> +        sysfs_remove_file(&engine->kobj, &engine_class_attr);
>> +        sysfs_remove_file(&engine->kobj, &engine_hevc_attr);
>> +    }
>> +
>> +    kobject_get(&dev_priv->topology.engines_kobj);
>> +    kobject_del(&dev_priv->topology.engines_kobj);
>> +}
>> +
>>   void i915_setup_sysfs(struct drm_i915_private *dev_priv)
>>   {
>>       struct device *kdev = dev_priv->drm.primary->kdev;
>> @@ -762,6 +848,10 @@ void i915_setup_sysfs(struct drm_i915_private 
>> *dev_priv)
>>       if (ret)
>>           DRM_ERROR("Topology sysfs setup failed\n");
>>   +    ret = i915_setup_engines_sysfs(dev_priv);
>> +    if (ret)
>> +        DRM_ERROR("Engines sysfs setup failed\n");
>> +
>>       i915_setup_error_capture(kdev);
>>   }
>>   @@ -771,6 +861,8 @@ void i915_teardown_sysfs(struct 
>> drm_i915_private *dev_priv)
>>         i915_teardown_error_capture(kdev);
>>   +    i915_teardown_engines_sysfs(dev_priv);
>> +
>>       i915_teardown_topology_sysfs(dev_priv);
>>         if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
>> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h 
>> b/drivers/gpu/drm/i915/intel_ringbuffer.h
>> index 5f96533e5341..0243a9e620da 100644
>> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
>> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
>> @@ -290,6 +290,8 @@ struct intel_engine_cs {
>>       struct drm_i915_private *i915;
>>       char name[INTEL_ENGINE_CS_MAX_NAME];
>>   +    struct kobject kobj;
>> +
>>       enum intel_engine_id id;
>>       unsigned int hw_id;
>>       unsigned int guc_id;
>>
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 44b807421af8..c4f6e8ecf212 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2749,6 +2749,7 @@  struct drm_i915_private {
 
 	struct {
 		struct intel_topology_kobject kobj;
+		struct kobject engines_kobj;
 
 		struct sysfs_slice {
 			struct intel_slice_kobject kobj;
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 1d835f164d80..992aeaa91565 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -712,6 +712,92 @@  static void i915_teardown_topology_sysfs(struct drm_i915_private *dev_priv)
 	kobject_del(&topology_kobj->kobj);
 }
 
+static struct attribute engine_instance_attr = {
+	.name = "instance",
+	.mode = 0444,
+};
+
+static struct attribute engine_class_attr = {
+	.name = "class",
+	.mode = 0444,
+};
+
+static struct attribute engine_hevc_attr = {
+	.name = "hevc",
+	.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, kobj);
+
+	if (attr == &engine_instance_attr)
+		return sprintf(buf, "%hhu\n", engine->uabi_id);
+	if (attr == &engine_class_attr)
+		return sprintf(buf, "%hhu\n", engine->uabi_class);
+	if (attr == &engine_hevc_attr)
+		return sprintf(buf, "%i\n", INTEL_GEN(engine->i915) >= 8);
+	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 int i915_setup_engines_sysfs(struct drm_i915_private *dev_priv)
+{
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+
+	kobject_init_and_add(&dev_priv->topology.engines_kobj,
+			     dev_priv->drm.primary->kdev->kobj.ktype,
+			     &dev_priv->drm.primary->kdev->kobj,
+			     "engines");
+
+	for_each_engine(engine, dev_priv, id) {
+		int ret;
+
+		kobject_init_and_add(&engine->kobj, &engine_type,
+				     &dev_priv->topology.engines_kobj,
+				     engine->name);
+
+		ret = sysfs_create_file(&engine->kobj, &engine_instance_attr);
+		if (ret)
+			return ret;
+		ret = sysfs_create_file(&engine->kobj, &engine_class_attr);
+		if (ret)
+			return ret;
+		if (engine->id == VCS) {
+			ret = sysfs_create_file(&engine->kobj, &engine_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->kobj, &engine_instance_attr);
+		sysfs_remove_file(&engine->kobj, &engine_class_attr);
+		sysfs_remove_file(&engine->kobj, &engine_hevc_attr);
+	}
+
+	kobject_get(&dev_priv->topology.engines_kobj);
+	kobject_del(&dev_priv->topology.engines_kobj);
+}
+
 void i915_setup_sysfs(struct drm_i915_private *dev_priv)
 {
 	struct device *kdev = dev_priv->drm.primary->kdev;
@@ -762,6 +848,10 @@  void i915_setup_sysfs(struct drm_i915_private *dev_priv)
 	if (ret)
 		DRM_ERROR("Topology sysfs setup failed\n");
 
+	ret = i915_setup_engines_sysfs(dev_priv);
+	if (ret)
+		DRM_ERROR("Engines sysfs setup failed\n");
+
 	i915_setup_error_capture(kdev);
 }
 
@@ -771,6 +861,8 @@  void i915_teardown_sysfs(struct drm_i915_private *dev_priv)
 
 	i915_teardown_error_capture(kdev);
 
+	i915_teardown_engines_sysfs(dev_priv);
+
 	i915_teardown_topology_sysfs(dev_priv);
 
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 5f96533e5341..0243a9e620da 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -290,6 +290,8 @@  struct intel_engine_cs {
 	struct drm_i915_private *i915;
 	char name[INTEL_ENGINE_CS_MAX_NAME];
 
+	struct kobject kobj;
+
 	enum intel_engine_id id;
 	unsigned int hw_id;
 	unsigned int guc_id;