Skip to content

Commit

Permalink
drm/i915: Propagate fence errors
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Chris Wilson committed Aug 18, 2019
1 parent a8dc0f6 commit ef46884
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 5 deletions.
8 changes: 8 additions & 0 deletions drivers/gpu/drm/i915/i915_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 *
Expand Down
23 changes: 18 additions & 5 deletions drivers/gpu/drm/i915/i915_sw_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);

Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}

Expand Down Expand Up @@ -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);
}

Expand All @@ -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;
}
Expand Down
7 changes: 7 additions & 0 deletions drivers/gpu/drm/i915/i915_sw_fence.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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_ */
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/selftests/lib_sw_fence.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down

0 comments on commit ef46884

Please sign in to comment.