Merge tag 's390-5.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / i915_vma.c
index 4ff3807..08699fa 100644 (file)
@@ -294,6 +294,7 @@ struct i915_vma_work {
        struct dma_fence_work base;
        struct i915_vma *vma;
        struct drm_i915_gem_object *pinned;
+       struct i915_sw_dma_fence_cb cb;
        enum i915_cache_level cache_level;
        unsigned int flags;
 };
@@ -339,6 +340,25 @@ struct i915_vma_work *i915_vma_work(void)
        return vw;
 }
 
+int i915_vma_wait_for_bind(struct i915_vma *vma)
+{
+       int err = 0;
+
+       if (rcu_access_pointer(vma->active.excl.fence)) {
+               struct dma_fence *fence;
+
+               rcu_read_lock();
+               fence = dma_fence_get_rcu_safe(&vma->active.excl.fence);
+               rcu_read_unlock();
+               if (fence) {
+                       err = dma_fence_wait(fence, MAX_SCHEDULE_TIMEOUT);
+                       dma_fence_put(fence);
+               }
+       }
+
+       return err;
+}
+
 /**
  * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space.
  * @vma: VMA to map
@@ -386,6 +406,8 @@ int i915_vma_bind(struct i915_vma *vma,
 
        trace_i915_vma_bind(vma, bind_flags);
        if (work && (bind_flags & ~vma_flags) & vma->vm->bind_async_flags) {
+               struct dma_fence *prev;
+
                work->vma = vma;
                work->cache_level = cache_level;
                work->flags = bind_flags | I915_VMA_ALLOC;
@@ -399,8 +421,14 @@ int i915_vma_bind(struct i915_vma *vma,
                 * part of the obj->resv->excl_fence as it only affects
                 * execution and not content or object's backing store lifetime.
                 */
-               GEM_BUG_ON(i915_active_has_exclusive(&vma->active));
-               i915_active_set_exclusive(&vma->active, &work->base.dma);
+               prev = i915_active_set_exclusive(&vma->active, &work->base.dma);
+               if (prev) {
+                       __i915_sw_fence_await_dma_fence(&work->base.chain,
+                                                       prev,
+                                                       &work->cb);
+                       dma_fence_put(prev);
+               }
+
                work->base.dma.error = 0; /* enable the queue_work() */
 
                if (vma->obj) {
@@ -408,7 +436,6 @@ int i915_vma_bind(struct i915_vma *vma,
                        work->pinned = vma->obj;
                }
        } else {
-               GEM_BUG_ON((bind_flags & ~vma_flags) & vma->vm->bind_async_flags);
                ret = vma->ops->bind_vma(vma, cache_level, bind_flags);
                if (ret)
                        return ret;
@@ -614,7 +641,6 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
        u64 start, end;
        int ret;
 
-       GEM_BUG_ON(i915_vma_is_closed(vma));
        GEM_BUG_ON(i915_vma_is_bound(vma, I915_VMA_GLOBAL_BIND | I915_VMA_LOCAL_BIND));
        GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
 
@@ -892,6 +918,11 @@ int i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
        if (err)
                goto err_fence;
 
+       if (unlikely(i915_vma_is_closed(vma))) {
+               err = -ENOENT;
+               goto err_unlock;
+       }
+
        bound = atomic_read(&vma->flags);
        if (unlikely(bound & I915_VMA_ERROR)) {
                err = -ENOMEM;
@@ -977,8 +1008,14 @@ int i915_ggtt_pin(struct i915_vma *vma, u32 align, unsigned int flags)
 
        do {
                err = i915_vma_pin(vma, 0, align, flags | PIN_GLOBAL);
-               if (err != -ENOSPC)
+               if (err != -ENOSPC) {
+                       if (!err) {
+                               err = i915_vma_wait_for_bind(vma);
+                               if (err)
+                                       i915_vma_unpin(vma);
+                       }
                        return err;
+               }
 
                /* Unlike i915_vma_pin, we don't take no for an answer! */
                flush_idle_contexts(vm->gt);
@@ -1060,6 +1097,7 @@ void i915_vma_release(struct kref *ref)
 void i915_vma_parked(struct intel_gt *gt)
 {
        struct i915_vma *vma, *next;
+       LIST_HEAD(closed);
 
        spin_lock_irq(&gt->closed_lock);
        list_for_each_entry_safe(vma, next, &gt->closed_vma, closed_link) {
@@ -1071,28 +1109,26 @@ void i915_vma_parked(struct intel_gt *gt)
                if (!kref_get_unless_zero(&obj->base.refcount))
                        continue;
 
-               if (i915_vm_tryopen(vm)) {
-                       list_del_init(&vma->closed_link);
-               } else {
+               if (!i915_vm_tryopen(vm)) {
                        i915_gem_object_put(obj);
-                       obj = NULL;
+                       continue;
                }
 
-               spin_unlock_irq(&gt->closed_lock);
+               list_move(&vma->closed_link, &closed);
+       }
+       spin_unlock_irq(&gt->closed_lock);
 
-               if (obj) {
-                       __i915_vma_put(vma);
-                       i915_gem_object_put(obj);
-               }
+       /* As the GT is held idle, no vma can be reopened as we destroy them */
+       list_for_each_entry_safe(vma, next, &closed, closed_link) {
+               struct drm_i915_gem_object *obj = vma->obj;
+               struct i915_address_space *vm = vma->vm;
 
-               i915_vm_close(vm);
+               INIT_LIST_HEAD(&vma->closed_link);
+               __i915_vma_put(vma);
 
-               /* Restart after dropping lock */
-               spin_lock_irq(&gt->closed_lock);
-               next = list_first_entry(&gt->closed_vma,
-                                       typeof(*next), closed_link);
+               i915_gem_object_put(obj);
+               i915_vm_close(vm);
        }
-       spin_unlock_irq(&gt->closed_lock);
 }
 
 static void __i915_vma_iounmap(struct i915_vma *vma)
@@ -1136,7 +1172,7 @@ int __i915_vma_move_to_active(struct i915_vma *vma, struct i915_request *rq)
        GEM_BUG_ON(!i915_vma_is_pinned(vma));
 
        /* Wait for the vma to be bound before we start! */
-       err = i915_request_await_active(rq, &vma->active);
+       err = i915_request_await_active(rq, &vma->active, 0);
        if (err)
                return err;
 
@@ -1228,9 +1264,15 @@ int __i915_vma_unbind(struct i915_vma *vma)
                 * before the unbind, other due to non-strict nature of those
                 * indirect writes they may end up referencing the GGTT PTE
                 * after the unbind.
+                *
+                * Note that we may be concurrently poking at the GGTT_WRITE
+                * bit from set-domain, as we mark all GGTT vma associated
+                * with an object. We know this is for another vma, as we
+                * are currently unbinding this one -- so if this vma will be
+                * reused, it will be refaulted and have its dirty bit set
+                * before the next write.
                 */
                i915_vma_flush_writes(vma);
-               GEM_BUG_ON(i915_vma_has_ggtt_write(vma));
 
                /* release the fence reg _after_ flushing */
                ret = i915_vma_revoke_fence(vma);
@@ -1250,7 +1292,8 @@ int __i915_vma_unbind(struct i915_vma *vma)
                trace_i915_vma_unbind(vma);
                vma->ops->unbind_vma(vma);
        }
-       atomic_and(~(I915_VMA_BIND_MASK | I915_VMA_ERROR), &vma->flags);
+       atomic_and(~(I915_VMA_BIND_MASK | I915_VMA_ERROR | I915_VMA_GGTT_WRITE),
+                  &vma->flags);
 
        i915_vma_detach(vma);
        vma_unbind_pages(vma);
@@ -1272,16 +1315,21 @@ int i915_vma_unbind(struct i915_vma *vma)
                /* XXX not always required: nop_clear_range */
                wakeref = intel_runtime_pm_get(&vm->i915->runtime_pm);
 
+       /* Optimistic wait before taking the mutex */
+       err = i915_vma_sync(vma);
+       if (err)
+               goto out_rpm;
+
        err = mutex_lock_interruptible(&vm->mutex);
        if (err)
-               return err;
+               goto out_rpm;
 
        err = __i915_vma_unbind(vma);
        mutex_unlock(&vm->mutex);
 
+out_rpm:
        if (wakeref)
                intel_runtime_pm_put(&vm->i915->runtime_pm, wakeref);
-
        return err;
 }