[PATCH 21/21] drm/i915: Use reservation_object to coordinate userptr get_pages()

Chris Wilson chris at chris-wilson.co.uk
Fri May 31 22:09:28 UTC 2019


Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 .../gpu/drm/i915/gem/i915_gem_execbuffer.c    |   3 -
 drivers/gpu/drm/i915/gem/i915_gem_userptr.c   | 104 +++++++++++++++---
 2 files changed, 91 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
index db34593aaefc..c7eec146d5be 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
@@ -1781,9 +1781,6 @@ static noinline int eb_relocate_slow(struct i915_execbuffer *eb)
 		goto out;
 	}
 
-	/* A frequent cause for EAGAIN are currently unavailable client pages */
-	flush_workqueue(eb->i915->mm.userptr_wq);
-
 	err = i915_mutex_lock_interruptible(dev);
 	if (err) {
 		mutex_lock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
index cfa990edb351..6fee84628086 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_userptr.c
@@ -18,6 +18,8 @@
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+static DEFINE_SPINLOCK(fence_lock);
+
 struct i915_mm_struct {
 	struct mm_struct *mm;
 	struct drm_i915_private *i915;
@@ -420,11 +422,39 @@ i915_gem_userptr_release__mm_struct(struct drm_i915_gem_object *obj)
 }
 
 struct get_pages_work {
+	struct dma_fence dma; /* Must be first for dma_fence_free() */
+	struct i915_sw_fence wait;
 	struct work_struct work;
 	struct drm_i915_gem_object *obj;
 	struct task_struct *task;
 };
 
+static const char *get_pages_work_driver_name(struct dma_fence *fence)
+{
+	return DRIVER_NAME;
+}
+
+static const char *get_pages_work_timeline_name(struct dma_fence *fence)
+{
+	return "allocation";
+}
+
+static void get_pages_work_release(struct dma_fence *fence)
+{
+	struct get_pages_work *w = container_of(fence, typeof(*w), dma);
+
+	i915_sw_fence_fini(&w->wait);
+
+	BUILD_BUG_ON(offsetof(typeof(*w), dma));
+	dma_fence_free(&w->dma);
+}
+
+static const struct dma_fence_ops get_pages_work_ops = {
+	.get_driver_name = get_pages_work_driver_name,
+	.get_timeline_name = get_pages_work_timeline_name,
+	.release = get_pages_work_release,
+};
+
 static struct sg_table *
 __i915_gem_userptr_alloc_pages(struct drm_i915_gem_object *obj,
 			       struct page **pvec, int num_pages)
@@ -477,11 +507,17 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
 	struct page **pvec;
 	int pinned, ret;
 
-	ret = -ENOMEM;
-	pinned = 0;
+	if (!work->dma.error) {
+		pvec = kvmalloc_array(npages, sizeof(struct page *),
+				      GFP_KERNEL);
+		ret = -ENOMEM;
+	} else {
+		pvec = NULL;
+		ret = work->dma.error;
+	}
 
-	pvec = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
-	if (pvec != NULL) {
+	pinned = 0;
+	if (pvec) {
 		struct mm_struct *mm = obj->userptr.mm->mm;
 		unsigned int flags = 0;
 
@@ -532,15 +568,40 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
 
 	i915_gem_object_put(obj);
 	put_task_struct(work->task);
-	kfree(work);
+
+	dma_fence_signal(&work->dma);
+	dma_fence_put(&work->dma);
+}
+
+static int __i915_sw_fence_call
+get_pages_work_notify(struct i915_sw_fence *fence,
+		      enum i915_sw_fence_notify state)
+{
+	struct get_pages_work *w = container_of(fence, typeof(*w), wait);
+
+	switch (state) {
+	case FENCE_COMPLETE:
+		if (fence->error)
+			dma_fence_set_error(&w->dma, fence->error);
+		queue_work(to_i915(w->obj->base.dev)->mm.userptr_wq, &w->work);
+		break;
+
+	case FENCE_FREE:
+		dma_fence_put(&w->dma);
+		break;
+	}
+
+	return NOTIFY_DONE;
 }
 
 static struct sg_table *
 __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj)
 {
 	struct get_pages_work *work;
+	int err;
 
-	/* Spawn a worker so that we can acquire the
+	/*
+	 * Spawn a worker so that we can acquire the
 	 * user pages without holding our mutex. Access
 	 * to the user pages requires mmap_sem, and we have
 	 * a strict lock ordering of mmap_sem, struct_mutex -
@@ -565,15 +626,36 @@ __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj)
 
 	obj->userptr.work = &work->work;
 
+	dma_fence_init(&work->dma,
+		       &get_pages_work_ops,
+		       &fence_lock,
+		       to_i915(obj->base.dev)->mm.unordered_timeline,
+		       0);
+	i915_sw_fence_init(&work->wait, get_pages_work_notify);
+
 	work->obj = i915_gem_object_get(obj);
 
 	work->task = current;
 	get_task_struct(work->task);
 
 	INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker);
-	queue_work(to_i915(obj->base.dev)->mm.userptr_wq, &work->work);
 
-	return ERR_PTR(-EAGAIN);
+	i915_gem_object_lock(obj);
+	GEM_BUG_ON(!reservation_object_test_signaled_rcu(obj->resv, true));
+	err = i915_sw_fence_await_reservation(&work->wait,
+					      obj->resv, NULL,
+					      true, I915_FENCE_TIMEOUT,
+					      I915_FENCE_GFP);
+	if (err == 0)
+		reservation_object_add_excl_fence(obj->resv, &work->dma);
+	else
+		dma_fence_set_error(&work->dma, err);
+	i915_gem_object_unlock(obj);
+
+	dma_fence_get(&work->dma);
+	i915_sw_fence_commit(&work->wait);
+
+	return ERR_PTR(err);
 }
 
 static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
@@ -582,7 +664,6 @@ static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
 	struct mm_struct *mm = obj->userptr.mm->mm;
 	struct page **pvec;
 	struct sg_table *pages;
-	bool active;
 	int pinned;
 
 	/* If userspace should engineer that these pages are replaced in
@@ -625,18 +706,15 @@ static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj)
 						       pvec);
 	}
 
-	active = false;
 	if (pinned < 0) {
 		pages = ERR_PTR(pinned);
 		pinned = 0;
 	} else if (pinned < num_pages) {
 		pages = __i915_gem_userptr_get_pages_schedule(obj);
-		active = pages == ERR_PTR(-EAGAIN);
 	} else {
 		pages = __i915_gem_userptr_alloc_pages(obj, pvec, num_pages);
-		active = !IS_ERR(pages);
 	}
-	if (active)
+	if (!IS_ERR(pages))
 		__i915_gem_userptr_set_active(obj, true);
 
 	if (IS_ERR(pages))
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list