Commit 9ddc8ec0 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Eliminate the trylock for awaiting an earlier request

We currently use an error-prone mutex_trylock to grab another timeline
to find an earlier request along it. However, with a bit of a
sleight-of-hand, we can reduce the mutex_trylock to a spin_lock on the
immediate request and careful pointer chasing to acquire a reference on
the previous request.
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191216165317.2742896-1-chris@chris-wilson.co.uk
parent f8b74877
...@@ -756,34 +756,37 @@ i915_request_create(struct intel_context *ce) ...@@ -756,34 +756,37 @@ i915_request_create(struct intel_context *ce)
static int static int
i915_request_await_start(struct i915_request *rq, struct i915_request *signal) i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
{ {
struct intel_timeline *tl;
struct dma_fence *fence; struct dma_fence *fence;
int err; int err;
GEM_BUG_ON(i915_request_timeline(rq) == GEM_BUG_ON(i915_request_timeline(rq) ==
rcu_access_pointer(signal->timeline)); rcu_access_pointer(signal->timeline));
fence = NULL;
rcu_read_lock(); rcu_read_lock();
tl = rcu_dereference(signal->timeline); spin_lock_irq(&signal->lock);
if (i915_request_started(signal) || !kref_get_unless_zero(&tl->kref)) if (!i915_request_started(signal) &&
tl = NULL; !list_is_first(&signal->link,
rcu_read_unlock(); &rcu_dereference(signal->timeline)->requests)) {
if (!tl) /* already started or maybe even completed */ struct i915_request *prev = list_prev_entry(signal, link);
return 0;
fence = ERR_PTR(-EAGAIN); /*
if (mutex_trylock(&tl->mutex)) { * Peek at the request before us in the timeline. That
fence = NULL; * request will only be valid before it is retired, so
if (!i915_request_started(signal) && * after acquiring a reference to it, confirm that it is
!list_is_first(&signal->link, &tl->requests)) { * still part of the signaler's timeline.
signal = list_prev_entry(signal, link); */
fence = dma_fence_get(&signal->fence); if (i915_request_get_rcu(prev)) {
if (list_next_entry(prev, link) == signal)
fence = &prev->fence;
else
i915_request_put(prev);
} }
mutex_unlock(&tl->mutex);
} }
intel_timeline_put(tl); spin_unlock_irq(&signal->lock);
if (IS_ERR_OR_NULL(fence)) rcu_read_unlock();
return PTR_ERR_OR_ZERO(fence); if (!fence)
return 0;
err = 0; err = 0;
if (intel_timeline_sync_is_later(i915_request_timeline(rq), fence)) if (intel_timeline_sync_is_later(i915_request_timeline(rq), fence))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment