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
