[Intel-gfx] [PATCH 3/4] drm/i915: expose engine availability through sysfs

Tvrtko Ursulin tvrtko.ursulin at linux.intel.com
Mon Nov 20 16:03:00 UTC 2017


On 20/11/2017 12:23, Lionel Landwerlin wrote:
> 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

One more thing - I would need engine->instance here as well.

Regards,

Tvrtko

> ├── 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 at intel.com>
> ---
>   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 78c49db4280a..db550322207c 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 96c80fa0fcac..17aecd4fc6aa 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);
>   
> 


More information about the Intel-gfx mailing list