[PATCH 117/118] drm/i915/userptr: Add a flag to populate the userptr on creation

Chris Wilson chris at chris-wilson.co.uk
Tue Sep 11 19:50:17 UTC 2018


Acquiring the backing struct pages for the userptr range is not free;
the first client for userptr would insist on frequently creating userptr
objects ahead of time and not use them. For that first client, deferring
the cost of populating the userptr (calling get_user_pages()) to the
actual execbuf was a substantial improvement. However, not all clients
are the same, and most would like to validate that the userptr is valid
and backed by struct pages upon creation, so offer a
I915_USERPTR_POPULATE flag to do just that.

Note that big difference between I915_USERPTR_POPULATE and the deferred
scheme is that POPULATE is guaranteed to be synchronous, the result is
known before the ioctl returns (and the handle exposed). However, due to
system memory pressure, the object may be paged out before use,
requiring them to be paged back in on execbuf (as may always happen).

Testcase: igt/gem_userptr_blits/populate
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Cc: MichaƂ Winiarski <michal.winiarski at intel.com>
Cc: Jason Ekstrand <jason at jlekstrand.net>
---
 drivers/gpu/drm/i915/i915_gem_userptr.c | 57 ++++++++++++++++++++++++-
 include/uapi/drm/i915_drm.h             |  1 +
 2 files changed, 57 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index aaa081092930..001a6cbb5535 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -786,6 +786,58 @@ static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = {
 	.release = i915_gem_userptr_release,
 };
 
+static int populate(struct drm_i915_gem_object *obj)
+{
+	const unsigned long num_pages = obj->base.size >> PAGE_SHIFT;
+	const unsigned long addr = obj->userptr.ptr;
+	struct page **pvec;
+	unsigned int flags;
+	int pinned = 0;
+	int ret;
+
+	pvec = kvmalloc_array(num_pages, sizeof(struct page *),
+			      GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
+	if (!pvec)
+		return -ENOMEM;
+
+	down_read(&current->mm->mmap_sem);
+	ret = __i915_gem_userptr_set_active(obj, true);
+	if (ret)
+		goto out;
+
+	flags = 0;
+	if (!i915_gem_object_is_readonly(obj))
+		flags |= FOLL_WRITE;
+
+	do {
+		ret = get_user_pages(addr + pinned * PAGE_SIZE,
+				     num_pages - pinned,
+				     flags,
+				     pvec + pinned, NULL);
+		if (ret < 0)
+			goto err;
+
+		pinned += ret;
+	} while (pinned < num_pages);
+
+	mutex_lock(&obj->mm.lock);
+	ret = __i915_gem_userptr_alloc_pages(obj, pvec, num_pages);
+	mutex_unlock(&obj->mm.lock);
+	if (ret)
+		goto err;
+
+	pinned = 0;
+out:
+	up_read(&current->mm->mmap_sem);
+	release_pages(pvec, pinned);
+	kvfree(pvec);
+	return ret;
+
+err:
+	__i915_gem_userptr_set_active(obj, false);
+	goto out;
+}
+
 /*
  * Creates a new mm object that wraps some normal memory from the process
  * context - user memory.
@@ -841,6 +893,7 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
 
 	if (args->flags & ~(I915_USERPTR_READ_ONLY |
 			    I915_USERPTR_PROBE |
+			    I915_USERPTR_POPULATE |
 			    I915_USERPTR_UNSYNCHRONIZED))
 		return -EINVAL;
 
@@ -866,7 +919,7 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
 			return -ENODEV;
 	}
 
-	if (args->flags & I915_USERPTR_PROBE) {
+	if (args->flags & (I915_USERPTR_PROBE | I915_USERPTR_POPULATE)) {
 		/*
 		 * Check that the range pointed to represents real struct
 		 * pages and not iomappings (at *this* moment in time!)
@@ -899,6 +952,8 @@ i915_gem_userptr_ioctl(struct drm_device *dev,
 	ret = i915_gem_userptr_init__mm_struct(obj);
 	if (ret == 0)
 		ret = i915_gem_userptr_init__mmu_notifier(obj, args->flags);
+	if (ret == 0 && args->flags & I915_USERPTR_POPULATE)
+		ret = populate(obj);
 	if (ret == 0)
 		ret = drm_gem_handle_create(file, &obj->base, &handle);
 
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index 6378d89ba587..d31d9ec0e271 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -1504,6 +1504,7 @@ struct drm_i915_gem_userptr {
 	__u32 flags;
 #define I915_USERPTR_READ_ONLY		0x1
 #define I915_USERPTR_PROBE		0x2
+#define I915_USERPTR_POPULATE		0x4
 #define I915_USERPTR_UNSYNCHRONIZED	0x80000000
 	/**
 	 * Returned handle for the object.
-- 
2.19.0



More information about the Intel-gfx-trybot mailing list