drm/i915: Add ww locking to vm_fault_gtt
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Wed, 19 Aug 2020 14:09:02 +0000 (16:09 +0200)
committerJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Mon, 7 Sep 2020 11:32:16 +0000 (14:32 +0300)
We want to start requiring the reservation_lock instead of obj->mm.lock
for pinning objects, take the ww lock inside vm_fault_gtt as a first step
towards the legacy lock removal.

Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Thomas Hellström <thomas.hellstrom@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200819140904.1708856-23-maarten.lankhorst@linux.intel.com
Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
drivers/gpu/drm/i915/gem/i915_gem_mman.c

index b233685..548ed9f 100644 (file)
@@ -283,37 +283,46 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
        struct intel_runtime_pm *rpm = &i915->runtime_pm;
        struct i915_ggtt *ggtt = &i915->ggtt;
        bool write = area->vm_flags & VM_WRITE;
+       struct i915_gem_ww_ctx ww;
        intel_wakeref_t wakeref;
        struct i915_vma *vma;
        pgoff_t page_offset;
        int srcu;
        int ret;
 
-       /* Sanity check that we allow writing into this object */
-       if (i915_gem_object_is_readonly(obj) && write)
-               return VM_FAULT_SIGBUS;
-
        /* We don't use vmf->pgoff since that has the fake offset */
        page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT;
 
        trace_i915_gem_object_fault(obj, page_offset, true, write);
 
-       ret = i915_gem_object_pin_pages(obj);
+       wakeref = intel_runtime_pm_get(rpm);
+
+       i915_gem_ww_ctx_init(&ww, true);
+retry:
+       ret = i915_gem_object_lock(obj, &ww);
        if (ret)
-               goto err;
+               goto err_rpm;
 
-       wakeref = intel_runtime_pm_get(rpm);
+       /* Sanity check that we allow writing into this object */
+       if (i915_gem_object_is_readonly(obj) && write) {
+               ret = -EFAULT;
+               goto err_rpm;
+       }
 
-       ret = intel_gt_reset_trylock(ggtt->vm.gt, &srcu);
+       ret = i915_gem_object_pin_pages(obj);
        if (ret)
                goto err_rpm;
 
+       ret = intel_gt_reset_trylock(ggtt->vm.gt, &srcu);
+       if (ret)
+               goto err_pages;
+
        /* Now pin it into the GTT as needed */
-       vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0,
-                                      PIN_MAPPABLE |
-                                      PIN_NONBLOCK /* NOWARN */ |
-                                      PIN_NOEVICT);
-       if (IS_ERR(vma)) {
+       vma = i915_gem_object_ggtt_pin_ww(obj, &ww, NULL, 0, 0,
+                                         PIN_MAPPABLE |
+                                         PIN_NONBLOCK /* NOWARN */ |
+                                         PIN_NOEVICT);
+       if (IS_ERR(vma) && vma != ERR_PTR(-EDEADLK)) {
                /* Use a partial view if it is bigger than available space */
                struct i915_ggtt_view view =
                        compute_partial_view(obj, page_offset, MIN_CHUNK_PAGES);
@@ -328,11 +337,11 @@ static vm_fault_t vm_fault_gtt(struct vm_fault *vmf)
                 * all hope that the hardware is able to track future writes.
                 */
 
-               vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags);
-               if (IS_ERR(vma)) {
+               vma = i915_gem_object_ggtt_pin_ww(obj, &ww, &view, 0, 0, flags);
+               if (IS_ERR(vma) && vma != ERR_PTR(-EDEADLK)) {
                        flags = PIN_MAPPABLE;
                        view.type = I915_GGTT_VIEW_PARTIAL;
-                       vma = i915_gem_object_ggtt_pin(obj, &view, 0, 0, flags);
+                       vma = i915_gem_object_ggtt_pin_ww(obj, &ww, &view, 0, 0, flags);
                }
 
                /* The entire mappable GGTT is pinned? Unexpected! */
@@ -389,10 +398,16 @@ err_unpin:
        __i915_vma_unpin(vma);
 err_reset:
        intel_gt_reset_unlock(ggtt->vm.gt, srcu);
+err_pages:
+       i915_gem_object_unpin_pages(obj);
 err_rpm:
+       if (ret == -EDEADLK) {
+               ret = i915_gem_ww_ctx_backoff(&ww);
+               if (!ret)
+                       goto retry;
+       }
+       i915_gem_ww_ctx_fini(&ww);
        intel_runtime_pm_put(rpm, wakeref);
-       i915_gem_object_unpin_pages(obj);
-err:
        return i915_error_to_vmf_fault(ret);
 }