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: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20191216165317.2742896-1-chris@chris-wilson.co.uk
This commit is contained in:
parent
f8b7487734
commit
9ddc8ec027
@ -756,34 +756,37 @@ err_unlock:
|
|||||||
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));
|
||||||
|
|
||||||
rcu_read_lock();
|
|
||||||
tl = rcu_dereference(signal->timeline);
|
|
||||||
if (i915_request_started(signal) || !kref_get_unless_zero(&tl->kref))
|
|
||||||
tl = NULL;
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (!tl) /* already started or maybe even completed */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
fence = ERR_PTR(-EAGAIN);
|
|
||||||
if (mutex_trylock(&tl->mutex)) {
|
|
||||||
fence = NULL;
|
fence = NULL;
|
||||||
|
rcu_read_lock();
|
||||||
|
spin_lock_irq(&signal->lock);
|
||||||
if (!i915_request_started(signal) &&
|
if (!i915_request_started(signal) &&
|
||||||
!list_is_first(&signal->link, &tl->requests)) {
|
!list_is_first(&signal->link,
|
||||||
signal = list_prev_entry(signal, link);
|
&rcu_dereference(signal->timeline)->requests)) {
|
||||||
fence = dma_fence_get(&signal->fence);
|
struct i915_request *prev = list_prev_entry(signal, link);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Peek at the request before us in the timeline. That
|
||||||
|
* request will only be valid before it is retired, so
|
||||||
|
* after acquiring a reference to it, confirm that it is
|
||||||
|
* still part of the signaler's timeline.
|
||||||
|
*/
|
||||||
|
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))
|
||||||
|
Loading…
Reference in New Issue
Block a user