[Intel-gfx] [PATCH 1/4] drm/i915: introduce query info uAPI

Lionel Landwerlin lionel.g.landwerlin at intel.com
Wed Nov 8 16:22:35 UTC 2017


From: Tvrtko Ursulin <tvrtko.ursulin at 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 at intel.com>
Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin at intel.com>
Cc: Ben Widawsky <ben at bwidawsk.net>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Daniel Vetter <daniel.vetter at intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: Jon Bloomfield <jon.bloomfield at intel.com>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin at intel.com>
Cc: Oscar Mateo <oscar.mateo at intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong at 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

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
-- 
2.15.0



More information about the Intel-gfx mailing list