drm/i915: Propagate fence errors
authorChris Wilson <chris@chris-wilson.co.uk>
Sat, 17 Aug 2019 23:25:11 +0000 (00:25 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Sun, 18 Aug 2019 11:38:09 +0000 (12:38 +0100)
Errors spread like wildfire, and must eventually be returned to the
user. They need to be captured and passed along the flow of fences,
infecting each in turn with the existing error, until finally they fall
out of a user visible result.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190817232511.11391-1-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/i915_request.c
drivers/gpu/drm/i915/i915_sw_fence.c
drivers/gpu/drm/i915/i915_sw_fence.h
drivers/gpu/drm/i915/selftests/lib_sw_fence.c

index 91147a6..eabf85b 100644 (file)
@@ -496,6 +496,10 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state)
        switch (state) {
        case FENCE_COMPLETE:
                trace_i915_request_submit(request);
+
+               if (unlikely(fence->error))
+                       i915_request_skip(request, fence->error);
+
                /*
                 * We need to serialize use of the submit_request() callback
                 * with its hotplugging performed during an emergency
@@ -1048,6 +1052,9 @@ void i915_request_skip(struct i915_request *rq, int error)
        GEM_BUG_ON(!IS_ERR_VALUE((long)error));
        dma_fence_set_error(&rq->fence, error);
 
+       if (rq->infix == rq->postfix)
+               return;
+
        /*
         * As this request likely depends on state from the lost
         * context, clear out all the user operations leaving the
@@ -1059,6 +1066,7 @@ void i915_request_skip(struct i915_request *rq, int error)
                head = 0;
        }
        memset(vaddr + head, 0, rq->postfix - head);
+       rq->infix = rq->postfix;
 }
 
 static struct i915_request *
index 5387aaf..dedacaf 100644 (file)
@@ -157,8 +157,11 @@ static void __i915_sw_fence_wake_up_all(struct i915_sw_fence *fence,
                LIST_HEAD(extra);
 
                do {
-                       list_for_each_entry_safe(pos, next, &x->head, entry)
-                               pos->func(pos, TASK_NORMAL, 0, &extra);
+                       list_for_each_entry_safe(pos, next, &x->head, entry) {
+                               pos->func(pos,
+                                         TASK_NORMAL, fence->error,
+                                         &extra);
+                       }
 
                        if (list_empty(&extra))
                                break;
@@ -219,6 +222,8 @@ void __i915_sw_fence_init(struct i915_sw_fence *fence,
 
        __init_waitqueue_head(&fence->wait, name, key);
        atomic_set(&fence->pending, 1);
+       fence->error = 0;
+
        fence->flags = (unsigned long)fn;
 }
 
@@ -230,6 +235,8 @@ void i915_sw_fence_commit(struct i915_sw_fence *fence)
 
 static int i915_sw_fence_wake(wait_queue_entry_t *wq, unsigned mode, int flags, void *key)
 {
+       i915_sw_fence_set_error_once(wq->private, flags);
+
        list_del(&wq->entry);
        __i915_sw_fence_complete(wq->private, key);
 
@@ -302,8 +309,10 @@ static int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
        debug_fence_assert(fence);
        might_sleep_if(gfpflags_allow_blocking(gfp));
 
-       if (i915_sw_fence_done(signaler))
+       if (i915_sw_fence_done(signaler)) {
+               i915_sw_fence_set_error_once(fence, signaler->error);
                return 0;
+       }
 
        debug_fence_assert(signaler);
 
@@ -319,6 +328,7 @@ static int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
                                return -ENOMEM;
 
                        i915_sw_fence_wait(signaler);
+                       i915_sw_fence_set_error_once(fence, signaler->error);
                        return 0;
                }
 
@@ -337,7 +347,7 @@ static int __i915_sw_fence_await_sw_fence(struct i915_sw_fence *fence,
                __add_wait_queue_entry_tail(&signaler->wait, wq);
                pending = 1;
        } else {
-               i915_sw_fence_wake(wq, 0, 0, NULL);
+               i915_sw_fence_wake(wq, 0, signaler->error, NULL);
                pending = 0;
        }
        spin_unlock_irqrestore(&signaler->wait.lock, flags);
@@ -372,6 +382,7 @@ static void dma_i915_sw_fence_wake(struct dma_fence *dma,
 {
        struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
 
+       i915_sw_fence_set_error_once(cb->fence, dma->error);
        i915_sw_fence_complete(cb->fence);
        kfree(cb);
 }
@@ -391,6 +402,7 @@ static void timer_i915_sw_fence_wake(struct timer_list *t)
                  cb->dma->seqno,
                  i915_sw_fence_debug_hint(fence));
 
+       i915_sw_fence_set_error_once(fence, -ETIMEDOUT);
        i915_sw_fence_complete(fence);
 }
 
@@ -480,6 +492,7 @@ static void __dma_i915_sw_fence_wake(struct dma_fence *dma,
 {
        struct i915_sw_dma_fence_cb *cb = container_of(data, typeof(*cb), base);
 
+       i915_sw_fence_set_error_once(cb->fence, dma->error);
        i915_sw_fence_complete(cb->fence);
 }
 
@@ -501,7 +514,7 @@ int __i915_sw_fence_await_dma_fence(struct i915_sw_fence *fence,
        if (ret == 0) {
                ret = 1;
        } else {
-               i915_sw_fence_complete(fence);
+               __dma_i915_sw_fence_wake(dma, &cb->base);
                if (ret == -ENOENT) /* fence already signaled */
                        ret = 0;
        }
index 9cb5c3b..518cbaa 100644 (file)
@@ -22,6 +22,7 @@ struct i915_sw_fence {
        wait_queue_head_t wait;
        unsigned long flags;
        atomic_t pending;
+       int error;
 };
 
 #define I915_SW_FENCE_CHECKED_BIT      0 /* used internally for DAG checking */
@@ -106,4 +107,10 @@ static inline void i915_sw_fence_wait(struct i915_sw_fence *fence)
        wait_event(fence->wait, i915_sw_fence_done(fence));
 }
 
+static inline void
+i915_sw_fence_set_error_once(struct i915_sw_fence *fence, int error)
+{
+       cmpxchg(&fence->error, 0, error);
+}
+
 #endif /* _I915_SW_FENCE_H_ */
index b976c12..080b90b 100644 (file)
@@ -40,6 +40,7 @@ void __onstack_fence_init(struct i915_sw_fence *fence,
 
        __init_waitqueue_head(&fence->wait, name, key);
        atomic_set(&fence->pending, 1);
+       fence->error = 0;
        fence->flags = (unsigned long)nop_fence_notify;
 }