drm/i915: Wait upon userptr get-user-pages within execbuffer
authorChris Wilson <chris@chris-wilson.co.uk>
Fri, 16 Jun 2017 14:05:22 +0000 (15:05 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Fri, 16 Jun 2017 15:54:05 +0000 (16:54 +0100)
This simply hides the EAGAIN caused by userptr when userspace causes
resource contention. However, it is quite beneficial with highly
contended userptr users as we avoid repeating the setup costs and
kernel-user context switches.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: MichaƂ Winiarski <michal.winiarski@intel.com>
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_userptr.c

index a534412a5551d467043480d7a28332dfe8d69a09..e33a2ed9244c8c36a93208c699b74f2a6f03076d 100644 (file)
@@ -579,6 +579,7 @@ static void i915_gem_fini(struct drm_i915_private *dev_priv)
        intel_uc_fini_hw(dev_priv);
        i915_gem_cleanup_engines(dev_priv);
        i915_gem_context_fini(dev_priv);
+       i915_gem_cleanup_userptr(dev_priv);
        mutex_unlock(&dev_priv->drm.struct_mutex);
 
        i915_gem_drain_freed_objects(dev_priv);
index 7e182dd7e356295135dde41f08c9d462d61f0347..e750be52b04bb0925f6994efb83eef57a841ae8b 100644 (file)
@@ -1453,6 +1453,13 @@ struct i915_gem_mm {
        /** LRU list of objects with fence regs on them. */
        struct list_head fence_list;
 
+       /**
+        * Workqueue to fault in userptr pages, flushed by the execbuf
+        * when required but otherwise left to userspace to try again
+        * on EAGAIN.
+        */
+       struct workqueue_struct *userptr_wq;
+
        u64 unordered_timeline;
 
        /* the indicator for dispatch video commands on two BSD rings */
@@ -3228,7 +3235,8 @@ int i915_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 int i915_gem_get_tiling_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
-void i915_gem_init_userptr(struct drm_i915_private *dev_priv);
+int i915_gem_init_userptr(struct drm_i915_private *dev_priv);
+void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv);
 int i915_gem_userptr_ioctl(struct drm_device *dev, void *data,
                           struct drm_file *file);
 int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
index fcdc452f28bb6cb81e0eab7c1db3cc2551c85a9b..96b344901a7b2d37cbd040804a6594ba04064106 100644 (file)
@@ -4804,7 +4804,9 @@ int i915_gem_init(struct drm_i915_private *dev_priv)
         */
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
-       i915_gem_init_userptr(dev_priv);
+       ret = i915_gem_init_userptr(dev_priv);
+       if (ret)
+               goto out_unlock;
 
        ret = i915_gem_init_ggtt(dev_priv);
        if (ret)
index 3eaf07dfbe629fe42aa3b3ddc93706e269c8a00f..f4b02ef3987fee722032e7f7b397326d8e06510c 100644 (file)
@@ -1499,6 +1499,9 @@ repeat:
                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);
index 05c36f6635503c20d41cc7236009f07e21d556d8..ccd09e8419f5ffb74bda3222725057dc68fcf529 100644 (file)
@@ -378,7 +378,7 @@ __i915_mm_struct_free(struct kref *kref)
        mutex_unlock(&mm->i915->mm_lock);
 
        INIT_WORK(&mm->work, __i915_mm_struct_free__worker);
-       schedule_work(&mm->work);
+       queue_work(mm->i915->mm.userptr_wq, &mm->work);
 }
 
 static void
@@ -598,7 +598,7 @@ __i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj)
        get_task_struct(work->task);
 
        INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker);
-       schedule_work(&work->work);
+       queue_work(to_i915(obj->base.dev)->mm.userptr_wq, &work->work);
 
        return ERR_PTR(-EAGAIN);
 }
@@ -830,8 +830,20 @@ i915_gem_userptr_ioctl(struct drm_device *dev, void *data, struct drm_file *file
        return 0;
 }
 
-void i915_gem_init_userptr(struct drm_i915_private *dev_priv)
+int i915_gem_init_userptr(struct drm_i915_private *dev_priv)
 {
        mutex_init(&dev_priv->mm_lock);
        hash_init(dev_priv->mm_structs);
+
+       dev_priv->mm.userptr_wq =
+               alloc_workqueue("i915-userptr-acquire", WQ_HIGHPRI, 0);
+       if (!dev_priv->mm.userptr_wq)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv)
+{
+       destroy_workqueue(dev_priv->mm.userptr_wq);
 }