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 91147a6b68b5f7a11bb14e09e428755e99f954ab..eabf85b9779f54b7358f5e989b2a82989444b151 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 5387aafd3424bc9b2309559379cedf39520d15b9..dedacafc9442fbdf36c6801067212fdd2d87d592 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 9cb5c3b307a6241f02c321c588f8eaba76c67c58..518cbaad9bea307630d86ca56ee8c6afff2c1e6d 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 b976c12817c59c6916aca9132f5e478bc9474b4b..080b90b63d16b6199e2b5e465fe888d8d2d9ef87 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;
 }