[RFC PATCH 35/42] drm/i915: Introduce GEM_OBJECT_SETPARAM with I915_PARAM_MEMORY_REGION

Matthew Auld
2019-02-14T14:58:27Z

From: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>

This call will specify which memory region an object should be placed.

Note that changing the object's backing storage should be immediately
done after an object is created or if it's not yet in use, otherwise
this will fail on a busy object.

Signed-off-by: Abdiel Janulgue <abdiel.janulgue@linux.intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
---
drivers/gpu/drm/i915/i915_drv.c | 1 +
drivers/gpu/drm/i915/i915_drv.h | 2 +
drivers/gpu/drm/i915/i915_gem.c | 111 ++++++++++++++++++++++++++++++++
include/uapi/drm/i915_drm.h | 24 +++++++
4 files changed, 138 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 90ce9973ce46..08a4286b70c6 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -3016,6 +3016,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = {
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, i915_query_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_OBJECT_SETPARAM, i915_gem_object_setparam_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 f0e8567f18f5..8185ea126752 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2762,6 +2762,8 @@ ibx_disable_display_interrupt(struct drm_i915_private *dev_priv, u32 bits)
/* i915_gem.c */
int i915_gem_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+int i915_gem_object_setparam_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
int i915_gem_pread_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index a9e119d8d1f1..387eae998fbf 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2257,6 +2257,117 @@ int i915_gem_mmap(struct file *filp, struct vm_area_struct *vma)
return ret;
}

+static enum intel_region_id
+__region_id(u32 region)
+{
+ enum intel_region_id id;
+
+ for (id = 0; id < ARRAY_SIZE(intel_region_map); ++id) {
+ if (intel_region_map[id] == region)
+ return id;
+ }
+
+ return INTEL_MEMORY_UKNOWN;
+}
+
+static int i915_gem_object_region_select(struct drm_i915_private *dev_priv,
+ struct drm_i915_gem_object_param *args,
+ struct drm_file *file,
+ struct drm_i915_gem_object *obj)
+{
+ struct i915_gem_context *ctx = 0;
+ intel_wakeref_t wakeref;
+ u32 __user *uregions = u64_to_user_ptr(args->data);
+ int i, ret;
+
+ ctx = i915_gem_context_lookup(file->driver_priv,
+ DEFAULT_CONTEXT_HANDLE);
+ if (!ctx)
+ return -ENOENT;
+
+ mutex_lock(&dev_priv->drm.struct_mutex);
+ ret = i915_gem_object_prepare_move(obj);
+ if (ret) {
+ DRM_ERROR("Cannot set memory region, object in use\n");
+ goto err;
+ }
+
+ if (args->size > ARRAY_SIZE(intel_region_map))
+ return -EINVAL;
+
+ for (i = 0; i < args->size; i++) {
+ u32 region;
+ enum intel_region_id id;
+
+ ret = get_user(region, uregions);
+ if (ret)
+ goto err;
+
+ id = __region_id(region);
+ if (id == INTEL_MEMORY_UKNOWN) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = i915_gem_object_migrate(ctx, obj, id);
+ if (!ret) {
+ if (MEMORY_TYPE_FROM_REGION(region) ==
+ INTEL_LMEM) {
+ /*
+ * TODO: this should be part of get_pages(),
+ * when async get_pages arrives
+ */
+ with_intel_runtime_pm(dev_priv, wakeref)
+ ret = i915_gem_object_clear_blt(ctx, obj);
+
+ if (ret) {
+ __i915_gem_object_release_unless_active(obj);
+ DRM_ERROR("Failed clearing the object\n");
+ goto err;
+ }
+ }
+ break;
+ }
+ ++uregions;
+ }
+err:
+ mutex_unlock(&dev_priv->drm.struct_mutex);
+ i915_gem_context_put(ctx);
+ return ret;
+}
+
+int i915_gem_object_setparam_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+
+ struct drm_i915_gem_object_param *args = data;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct drm_i915_gem_object *obj;
+ int ret;
+
+ obj = i915_gem_object_lookup(file, args->handle);
+ if (!obj)
+ return -ENOENT;
+
+ switch (args->param) {
+ case I915_PARAM_MEMORY_REGION:
+ ret = i915_gem_object_region_select(dev_priv, args, file, obj);
+ if (ret) {
+ DRM_ERROR("Cannot set memory region, migration failed\n");
+ goto err;
+ }
+
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+err:
+ i915_gem_object_put(obj);
+ return ret;
+}
+
/* Immediately discard the backing storage */
static void
i915_gem_object_truncate(struct drm_i915_gem_object *obj)
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 5a102a5cb415..4f789d43d10b 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -320,6 +320,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_PERF_REMOVE_CONFIG 0x38
#define DRM_I915_QUERY 0x39
#define DRM_I915_GEM_MMAP_OFFSET DRM_I915_GEM_MMAP_GTT
+#define DRM_I915_GEM_OBJECT_SETPARAM 0x3c

#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)
@@ -379,6 +380,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_PERF_REMOVE_CONFIG DRM_IOW(DRM_COMMAND_BASE + DRM_I915_PERF_REMOVE_CONFIG, __u64)
#define DRM_IOCTL_I915_QUERY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_QUERY, struct drm_i915_query)
#define DRM_IOCTL_I915_GEM_MMAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MMAP_OFFSET, struct drm_i915_gem_mmap_offset)
+#define DRM_IOCTL_I915_GEM_OBJECT_SETPARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_OBJECT_SETPARAM, struct drm_i915_gem_object_param)

/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -664,6 +666,28 @@ struct drm_i915_gem_create {
__u32 pad;
};

+struct drm_i915_gem_object_param {
+ /** Handle for the object */
+ __u32 handle;
+
+ /** Set the memory region for the object listed in preference order
+ * as an array of region ids within data. To force an object
+ * to a particular memory region, set the region as the sole entry.
+ *
+ * Valid region ids are derived from the id field of
+ * struct drm_i915_memory_region_info.
+ * See struct drm_i915_query_memory_region_info.
+ */
+#define I915_PARAM_MEMORY_REGION 0x1
+ __u32 param;
+
+ __u32 size;
+ /* Unused at the moment */
+ __u32 flags;
+
+ __u64 data;
+};
+
struct drm_i915_gem_pread {
/** Handle for the object being read. */
__u32 handle;
--
2.20.1