diff mbox

[1/4] drm/i915: introduce query info uAPI

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

Commit Message

Lionel Landwerlin Nov. 8, 2017, 4:22 p.m. UTC
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Query info uAPI allows userspace to probe for a number of properties
of the GPU. This partially removes the need for userspace to maintain
the internal PCI id based database (as well as code duplication across
userspace components).

This first version enables engine configuration and features to be
queried.

Probing is done via the new DRM_IOCTL_I915_QUERY_INFO ioctl which
takes a query ID as well as query arguments.

Currently only general engine configuration and HEVC feature of the
VCS engine can be probed but the uAPI is designed to be generic and
extensible.

Code is based almost exactly on the earlier proposal on the topic by
Jon Bloomfield. Engine class and instance refactoring made recently by
Daniele Ceraolo Spurio enabled this to be implemented in an elegant
fashion.

To probe configuration userspace sets the engine class it wants to
query (struct drm_i915_gem_engine_info) and provides an array of
drm_i915_engine_info structs which will be filled in by the driver.
Userspace also has to tell i915 how many elements are in the array,
and the driver will report back the total number of engine instances
in any case.

Pseudo-code example of userspace using the uAPI:

  struct drm_i915_query_info info = {};
  struct drm_i915_engine_info *engines;
  int i, ret;

  info.version = 1;
  info.query = I915_QUERY_INFO_ENGINE;
  info.query_params[0] = I915_ENGINE_CLASS_VIDEO;
  info.info_ptr_len = 0;
  ret = ioctl(..., &info);
  assert(ret == 0);

  engines = malloc(info.info_ptr_len);
  info.info_ptr = to_user_pointer(engines);
  ret = ioctl(..., &info);
  assert(ret == 0);

  for (i = 0; i < info.info_ptr / sizeof(*engines); i++)
      printf("VCS%u: flags=%x\n",
             engines[i].instance,
             engines[i].info);

First time with info.info_ptr_len set to zero, so the kernel reports
back the size of the data to be written into info.info_ptr. Then a
second time with the info.info_ptr_len field set to the correct
length.

v2:
 * Add a version field and consolidate to one engine count.
   (Chris Wilson)
 * Rename uAPI flags for VCS engines to DRM_I915_ENGINE_CLASS_VIDEO.
   (Gong Zhipeng)

v3:
 * Drop the DRM_ prefix from uAPI enums. (Chris Wilson)
 * Only reserve 8-bits for the engine info for time being.

v4:
 * Made user_class_map static.

v5:
 * Example usage added to commit msg. (Chris Wilson)
 * Report engine count in case of version mismatch. (Chris Wilson)

v6:
 * Return API to query_info to make it more generic (Lionel)
 * Add query ID & query params (Lionel)

Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Cc: Ben Widawsky <ben@bwidawsk.net>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Jon Bloomfield <jon.bloomfield@intel.com>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: Oscar Mateo <oscar.mateo@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
---
 drivers/gpu/drm/i915/Makefile           |   1 +
 drivers/gpu/drm/i915/i915_drv.c         |   1 +
 drivers/gpu/drm/i915/i915_drv.h         |   3 +
 drivers/gpu/drm/i915/intel_engine_cs.c  |   1 +
 drivers/gpu/drm/i915/intel_query_info.c | 118 ++++++++++++++++++++++++++++++++
 include/uapi/drm/i915_drm.h             |  64 +++++++++++++++++
 6 files changed, 188 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/intel_query_info.c

Comments

Joonas Lahtinen Nov. 9, 2017, 3:57 p.m. UTC | #1
On Wed, 2017-11-08 at 16:22 +0000, Lionel Landwerlin wrote:
> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> 
> Query info uAPI allows userspace to probe for a number of properties
> of the GPU. This partially removes the need for userspace to maintain
> the internal PCI id based database (as well as code duplication across
> userspace components).
> 
> This first version enables engine configuration and features to be
> queried.
> 
> Probing is done via the new DRM_IOCTL_I915_QUERY_INFO ioctl which
> takes a query ID as well as query arguments.
> 
> Currently only general engine configuration and HEVC feature of the
> VCS engine can be probed but the uAPI is designed to be generic and
> extensible.
> 
> Code is based almost exactly on the earlier proposal on the topic by
> Jon Bloomfield. Engine class and instance refactoring made recently by
> Daniele Ceraolo Spurio enabled this to be implemented in an elegant
> fashion.
> 
> To probe configuration userspace sets the engine class it wants to
> query (struct drm_i915_gem_engine_info) and provides an array of
> drm_i915_engine_info structs which will be filled in by the driver.
> Userspace also has to tell i915 how many elements are in the array,
> and the driver will report back the total number of engine instances
> in any case.
> 
> Pseudo-code example of userspace using the uAPI:
> 
>   struct drm_i915_query_info info = {};
>   struct drm_i915_engine_info *engines;
>   int i, ret;
> 
>   info.version = 1;
>   info.query = I915_QUERY_INFO_ENGINE;
>   info.query_params[0] = I915_ENGINE_CLASS_VIDEO;
>   info.info_ptr_len = 0;
>   ret = ioctl(..., &info);
>   assert(ret == 0);
> 
>   engines = malloc(info.info_ptr_len);
>   info.info_ptr = to_user_pointer(engines);
>   ret = ioctl(..., &info);
>   assert(ret == 0);
> 
>   for (i = 0; i < info.info_ptr / sizeof(*engines); i++)
>       printf("VCS%u: flags=%x\n",
>              engines[i].instance,
>              engines[i].info);
> 
> First time with info.info_ptr_len set to zero, so the kernel reports
> back the size of the data to be written into info.info_ptr. Then a
> second time with the info.info_ptr_len field set to the correct
> length.
> 
> v2:
>  * Add a version field and consolidate to one engine count.
>    (Chris Wilson)
>  * Rename uAPI flags for VCS engines to DRM_I915_ENGINE_CLASS_VIDEO.
>    (Gong Zhipeng)
> 
> v3:
>  * Drop the DRM_ prefix from uAPI enums. (Chris Wilson)
>  * Only reserve 8-bits for the engine info for time being.
> 
> v4:
>  * Made user_class_map static.
> 
> v5:
>  * Example usage added to commit msg. (Chris Wilson)
>  * Report engine count in case of version mismatch. (Chris Wilson)
> 
> v6:
>  * Return API to query_info to make it more generic (Lionel)
>  * Add query ID & query params (Lionel)
> 
> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
> Cc: Ben Widawsky <ben@bwidawsk.net>
> Cc: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Daniel Vetter <daniel.vetter@intel.com>
> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
> Cc: Jon Bloomfield <jon.bloomfield@intel.com>
> Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
> Cc: Oscar Mateo <oscar.mateo@intel.com>
> Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>

<SNIP>

> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -2776,6 +2776,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
>  	DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW),
>  	DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
>  	DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
> +	DRM_IOCTL_DEF_DRV(I915_QUERY_INFO, i915_query_info_ioctl, DRM_RENDER_ALLOW),

I'm not a fan. This is bit much to the direction of I915_META_IOCTL.

So can we keep this as engine info query without versioning, and if you
need to query something else, lets have another ioctl for that.

(I heard a rumour of this being about RCS topology, which could be in
the engine info.).

Regards, Joonas
Lionel Landwerlin Nov. 9, 2017, 4:15 p.m. UTC | #2
On 09/11/17 15:57, Joonas Lahtinen wrote:
> On Wed, 2017-11-08 at 16:22 +0000, Lionel Landwerlin wrote:
>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>
>> Query info uAPI allows userspace to probe for a number of properties
>> of the GPU. This partially removes the need for userspace to maintain
>> the internal PCI id based database (as well as code duplication across
>> userspace components).
>>
>> This first version enables engine configuration and features to be
>> queried.
>>
>> Probing is done via the new DRM_IOCTL_I915_QUERY_INFO ioctl which
>> takes a query ID as well as query arguments.
>>
>> Currently only general engine configuration and HEVC feature of the
>> VCS engine can be probed but the uAPI is designed to be generic and
>> extensible.
>>
>> Code is based almost exactly on the earlier proposal on the topic by
>> Jon Bloomfield. Engine class and instance refactoring made recently by
>> Daniele Ceraolo Spurio enabled this to be implemented in an elegant
>> fashion.
>>
>> To probe configuration userspace sets the engine class it wants to
>> query (struct drm_i915_gem_engine_info) and provides an array of
>> drm_i915_engine_info structs which will be filled in by the driver.
>> Userspace also has to tell i915 how many elements are in the array,
>> and the driver will report back the total number of engine instances
>> in any case.
>>
>> Pseudo-code example of userspace using the uAPI:
>>
>>    struct drm_i915_query_info info = {};
>>    struct drm_i915_engine_info *engines;
>>    int i, ret;
>>
>>    info.version = 1;
>>    info.query = I915_QUERY_INFO_ENGINE;
>>    info.query_params[0] = I915_ENGINE_CLASS_VIDEO;
>>    info.info_ptr_len = 0;
>>    ret = ioctl(..., &info);
>>    assert(ret == 0);
>>
>>    engines = malloc(info.info_ptr_len);
>>    info.info_ptr = to_user_pointer(engines);
>>    ret = ioctl(..., &info);
>>    assert(ret == 0);
>>
>>    for (i = 0; i < info.info_ptr / sizeof(*engines); i++)
>>        printf("VCS%u: flags=%x\n",
>>               engines[i].instance,
>>               engines[i].info);
>>
>> First time with info.info_ptr_len set to zero, so the kernel reports
>> back the size of the data to be written into info.info_ptr. Then a
>> second time with the info.info_ptr_len field set to the correct
>> length.
>>
>> v2:
>>   * Add a version field and consolidate to one engine count.
>>     (Chris Wilson)
>>   * Rename uAPI flags for VCS engines to DRM_I915_ENGINE_CLASS_VIDEO.
>>     (Gong Zhipeng)
>>
>> v3:
>>   * Drop the DRM_ prefix from uAPI enums. (Chris Wilson)
>>   * Only reserve 8-bits for the engine info for time being.
>>
>> v4:
>>   * Made user_class_map static.
>>
>> v5:
>>   * Example usage added to commit msg. (Chris Wilson)
>>   * Report engine count in case of version mismatch. (Chris Wilson)
>>
>> v6:
>>   * Return API to query_info to make it more generic (Lionel)
>>   * Add query ID & query params (Lionel)
>>
>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
>> Cc: Ben Widawsky <ben@bwidawsk.net>
>> Cc: Chris Wilson <chris@chris-wilson.co.uk>
>> Cc: Daniel Vetter <daniel.vetter@intel.com>
>> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
>> Cc: Jon Bloomfield <jon.bloomfield@intel.com>
>> Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
>> Cc: Oscar Mateo <oscar.mateo@intel.com>
>> Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
> <SNIP>
>
>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>> @@ -2776,6 +2776,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
>>   	DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW),
>>   	DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
>>   	DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
>> +	DRM_IOCTL_DEF_DRV(I915_QUERY_INFO, i915_query_info_ioctl, DRM_RENDER_ALLOW),
> I'm not a fan. This is bit much to the direction of I915_META_IOCTL.

So you would prefer a different ioctl for every bit of information we 
would want to query from the kernel?

>
> So can we keep this as engine info query without versioning, and if you
> need to query something else, lets have another ioctl for that.
>
> (I heard a rumour of this being about RCS topology, which could be in
> the engine info.).

I'm not sure to understand what you mean by "in the engine info". Would 
you mind to give an example?

>
> Regards, Joonas
Tvrtko Ursulin Nov. 9, 2017, 5:10 p.m. UTC | #3
On 09/11/2017 16:15, Lionel Landwerlin wrote:
> On 09/11/17 15:57, Joonas Lahtinen wrote:
>> On Wed, 2017-11-08 at 16:22 +0000, Lionel Landwerlin wrote:
>>> From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>>
>>> Query info uAPI allows userspace to probe for a number of properties
>>> of the GPU. This partially removes the need for userspace to maintain
>>> the internal PCI id based database (as well as code duplication across
>>> userspace components).
>>>
>>> This first version enables engine configuration and features to be
>>> queried.
>>>
>>> Probing is done via the new DRM_IOCTL_I915_QUERY_INFO ioctl which
>>> takes a query ID as well as query arguments.
>>>
>>> Currently only general engine configuration and HEVC feature of the
>>> VCS engine can be probed but the uAPI is designed to be generic and
>>> extensible.
>>>
>>> Code is based almost exactly on the earlier proposal on the topic by
>>> Jon Bloomfield. Engine class and instance refactoring made recently by
>>> Daniele Ceraolo Spurio enabled this to be implemented in an elegant
>>> fashion.
>>>
>>> To probe configuration userspace sets the engine class it wants to
>>> query (struct drm_i915_gem_engine_info) and provides an array of
>>> drm_i915_engine_info structs which will be filled in by the driver.
>>> Userspace also has to tell i915 how many elements are in the array,
>>> and the driver will report back the total number of engine instances
>>> in any case.
>>>
>>> Pseudo-code example of userspace using the uAPI:
>>>
>>>    struct drm_i915_query_info info = {};
>>>    struct drm_i915_engine_info *engines;
>>>    int i, ret;
>>>
>>>    info.version = 1;
>>>    info.query = I915_QUERY_INFO_ENGINE;
>>>    info.query_params[0] = I915_ENGINE_CLASS_VIDEO;
>>>    info.info_ptr_len = 0;
>>>    ret = ioctl(..., &info);
>>>    assert(ret == 0);
>>>
>>>    engines = malloc(info.info_ptr_len);
>>>    info.info_ptr = to_user_pointer(engines);
>>>    ret = ioctl(..., &info);
>>>    assert(ret == 0);
>>>
>>>    for (i = 0; i < info.info_ptr / sizeof(*engines); i++)
>>>        printf("VCS%u: flags=%x\n",
>>>               engines[i].instance,
>>>               engines[i].info);
>>>
>>> First time with info.info_ptr_len set to zero, so the kernel reports
>>> back the size of the data to be written into info.info_ptr. Then a
>>> second time with the info.info_ptr_len field set to the correct
>>> length.
>>>
>>> v2:
>>>   * Add a version field and consolidate to one engine count.
>>>     (Chris Wilson)
>>>   * Rename uAPI flags for VCS engines to DRM_I915_ENGINE_CLASS_VIDEO.
>>>     (Gong Zhipeng)
>>>
>>> v3:
>>>   * Drop the DRM_ prefix from uAPI enums. (Chris Wilson)
>>>   * Only reserve 8-bits for the engine info for time being.
>>>
>>> v4:
>>>   * Made user_class_map static.
>>>
>>> v5:
>>>   * Example usage added to commit msg. (Chris Wilson)
>>>   * Report engine count in case of version mismatch. (Chris Wilson)
>>>
>>> v6:
>>>   * Return API to query_info to make it more generic (Lionel)
>>>   * Add query ID & query params (Lionel)
>>>
>>> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
>>> Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
>>> Cc: Ben Widawsky <ben@bwidawsk.net>
>>> Cc: Chris Wilson <chris@chris-wilson.co.uk>
>>> Cc: Daniel Vetter <daniel.vetter@intel.com>
>>> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
>>> Cc: Jon Bloomfield <jon.bloomfield@intel.com>
>>> Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
>>> Cc: Oscar Mateo <oscar.mateo@intel.com>
>>> Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
>> <SNIP>
>>
>>> +++ b/drivers/gpu/drm/i915/i915_drv.c
>>> @@ -2776,6 +2776,7 @@ static const struct drm_ioctl_desc 
>>> i915_ioctls[] = {
>>>       DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, 
>>> DRM_RENDER_ALLOW),
>>>       DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, 
>>> i915_perf_add_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
>>>       DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, 
>>> i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
>>> +    DRM_IOCTL_DEF_DRV(I915_QUERY_INFO, i915_query_info_ioctl, 
>>> DRM_RENDER_ALLOW),
>> I'm not a fan. This is bit much to the direction of I915_META_IOCTL.
> 
> So you would prefer a different ioctl for every bit of information we 
> would want to query from the kernel?
> 
>>
>> So can we keep this as engine info query without versioning, and if you
>> need to query something else, lets have another ioctl for that.
>>
>> (I heard a rumour of this being about RCS topology, which could be in
>> the engine info.).
> 
> I'm not sure to understand what you mean by "in the engine info". Would 
> you mind to give an example?

We chatted about this internally a bit and no one seems to like a 
multiplexer within a multiplexer approach.

So one option is a completely separate ioctl, but before that the 
question is if everything you need to export is called RCS topology, so 
logically belongs to the render engine, could it be exported under the 
engine info name after all?

Like maybe adding drm_i915_rcs_engine_info, containing all the extra 
fields you need on top of the existing info, to be returned when the 
render class is queried.

One problem I spotted is that your new data is only valid on gen8+. So 
that would mean having a flag saying what data is valid.

Regards,

Tvrtko
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 177404462386..18d087f3e501 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -75,6 +75,7 @@  i915-y += i915_cmd_parser.o \
 	  intel_hangcheck.o \
 	  intel_lrc.o \
 	  intel_mocs.o \
+	  intel_query_info.o \
 	  intel_ringbuffer.o \
 	  intel_uncore.o
 
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index e7e9e061073b..d1843a18ea2a 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -2776,6 +2776,7 @@  static const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_PERF_OPEN, i915_perf_open_ioctl, DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_PERF_ADD_CONFIG, i915_perf_add_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_PERF_REMOVE_CONFIG, i915_perf_remove_config_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+	DRM_IOCTL_DEF_DRV(I915_QUERY_INFO, i915_query_info_ioctl, DRM_RENDER_ALLOW),
 };
 
 static struct drm_driver driver = {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 5e6938d0a903..a4978bd6a436 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3858,6 +3858,9 @@  void i915_oa_init_reg_state(struct intel_engine_cs *engine,
 			    struct i915_gem_context *ctx,
 			    uint32_t *reg_state);
 
+int i915_query_info_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *file);
+
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct i915_address_space *vm,
 					  u64 min_size, u64 alignment,
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index 6997306be0d2..ddfe9b722d92 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -28,6 +28,7 @@ 
 #include "i915_vgpu.h"
 #include "intel_ringbuffer.h"
 #include "intel_lrc.h"
+#include <uapi/drm/i915_drm.h>
 
 /* Haswell does have the CXT_SIZE register however it does not appear to be
  * valid. Now, docs explain in dwords what is in the context object. The full
diff --git a/drivers/gpu/drm/i915/intel_query_info.c b/drivers/gpu/drm/i915/intel_query_info.c
new file mode 100644
index 000000000000..21434c393582
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_query_info.c
@@ -0,0 +1,118 @@ 
+/*
+ * Copyright © 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "i915_drv.h"
+#include <uapi/drm/i915_drm.h>
+
+static u8 user_class_map[I915_ENGINE_CLASS_MAX] = {
+	[I915_ENGINE_CLASS_OTHER] = OTHER_CLASS,
+	[I915_ENGINE_CLASS_RENDER] = RENDER_CLASS,
+	[I915_ENGINE_CLASS_COPY] = COPY_ENGINE_CLASS,
+	[I915_ENGINE_CLASS_VIDEO] = VIDEO_DECODE_CLASS,
+	[I915_ENGINE_CLASS_VIDEO_ENHANCE] = VIDEO_ENHANCEMENT_CLASS,
+};
+
+static int query_info_engine(struct drm_i915_private *dev_priv,
+			     struct drm_i915_query_info *args)
+{
+	struct drm_i915_engine_info __user *user_info =
+		u64_to_user_ptr(args->info_ptr);
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+	u8 num_engines, class;
+	u32 info_size;
+
+	switch (args->query_params[0]) {
+	case I915_ENGINE_CLASS_OTHER:
+	case I915_ENGINE_CLASS_RENDER:
+	case I915_ENGINE_CLASS_COPY:
+	case I915_ENGINE_CLASS_VIDEO:
+	case I915_ENGINE_CLASS_VIDEO_ENHANCE:
+		class = user_class_map[args->query_params[0]];
+		break;
+	case I915_ENGINE_CLASS_MAX:
+	default:
+		return -EINVAL;
+	};
+
+	num_engines = 0;
+	for_each_engine(engine, dev_priv, id) {
+		if (class != engine->class)
+			continue;
+
+		num_engines++;
+	}
+
+	info_size = sizeof(struct drm_i915_engine_info) * num_engines;
+	if (args->info_ptr_len == 0) {
+		args->info_ptr_len = info_size;
+		return 0;
+	}
+
+	if (args->info_ptr_len < info_size)
+		return -EINVAL;
+
+	for_each_engine(engine, dev_priv, id) {
+		struct drm_i915_engine_info info;
+		int ret;
+
+		if (class != engine->class)
+			continue;
+
+		memset(&info, 0, sizeof(info));
+		info.instance = engine->instance;
+		if (INTEL_GEN(dev_priv) >= 8 && id == VCS)
+			info.info = I915_VCS_HAS_HEVC;
+
+		ret = copy_to_user(user_info++, &info, sizeof(info));
+		if (ret)
+			return -EFAULT;
+	}
+
+	return 0;
+}
+
+
+int i915_query_info_ioctl(struct drm_device *dev, void *data,
+			  struct drm_file *file)
+{
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct drm_i915_query_info *args = data;
+
+	/* Currently supported version of this API. */
+	if (args->version == 0) {
+		args->version = 1;
+		return 0;
+	}
+
+	if (args->version != 1)
+		return -EINVAL;
+
+	switch (args->query) {
+	case I915_QUERY_INFO_ENGINE:
+		return query_info_engine(dev_priv, args);
+	default:
+		return -EINVAL;
+	}
+}
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index ac3c6503ca27..c6026616300e 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -262,6 +262,7 @@  typedef struct _drm_i915_sarea {
 #define DRM_I915_PERF_OPEN		0x36
 #define DRM_I915_PERF_ADD_CONFIG	0x37
 #define DRM_I915_PERF_REMOVE_CONFIG	0x38
+#define DRM_I915_QUERY_INFO		0x39
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -319,6 +320,7 @@  typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_PERF_OPEN	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_OPEN, struct drm_i915_perf_open_param)
 #define DRM_IOCTL_I915_PERF_ADD_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_ADD_CONFIG, struct drm_i915_perf_oa_config)
 #define DRM_IOCTL_I915_PERF_REMOVE_CONFIG	DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
+#define DRM_IOCTL_I915_QUERY_INFO	DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY_INFO, struct drm_i915_query_info)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -1536,6 +1538,68 @@  struct drm_i915_perf_oa_config {
 	__u64 flex_regs_ptr;
 };
 
+
+/* Query engines information.
+ *
+ * drm_i915_query_info.query_params[0] should be set to one of the
+ * I915_ENGINE_CLASS_* enum.
+ *
+ * drm_i915_engine_info.info_ptr will be written to with an array of
+ * drm_i915_engine_info.
+ */
+#define I915_QUERY_INFO_ENGINE		0 /* version 1 */
+
+enum drm_i915_engine_class {
+	I915_ENGINE_CLASS_OTHER = 0,
+	I915_ENGINE_CLASS_RENDER = 1,
+	I915_ENGINE_CLASS_COPY = 2,
+	I915_ENGINE_CLASS_VIDEO = 3,
+	I915_ENGINE_CLASS_VIDEO_ENHANCE = 4,
+	I915_ENGINE_CLASS_MAX /* non-ABI */
+};
+
+struct drm_i915_engine_info {
+	/** Engine instance number. */
+	__u8 instance;
+
+	/** Engine specific info. */
+#define I915_VCS_HAS_HEVC	BIT(0)
+	__u8 info;
+
+	__u8 rsvd2[6];
+};
+
+
+struct drm_i915_query_info {
+	/* in/out: Protocol version requested/supported. When set to 0, the
+	 * kernel set this field to the current supported version. EINVAL will
+	 * be return if version is greater than what the kernel supports.
+	 */
+	__u32 version;
+
+	/* in: Query to perform on the engine (use one of
+	 * I915_QUERY_INFO_* define).
+	 */
+	__u32 query;
+
+	/** in: Parameters associated with the query (refer to each
+	 * I915_QUERY_INFO_* define)
+	 */
+	__u32 query_params[3];
+
+	/* in/out: Size of the data to be copied into info_ptr. When set to 0,
+	 * the kernel set this field to the size to be copied into info_ptr.
+	 * Call this one more time with the correct value set to make the
+	 * kernel copy the data into info_ptr.
+	 */
+	__u32 info_ptr_len;
+
+	/** in/out: Pointer to the data filled for the query (pointer set by
+	 * the caller, data written by the callee).
+	 */
+	__u64 info_ptr;
+};
+
 #if defined(__cplusplus)
 }
 #endif