[Intel-gfx] [PATCH 2/3] drm/i915/gt: Pull intel_timeline.requests list under a spinlock
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Mon Dec 16 16:18:53 UTC 2019
On 12/12/2019 01:46, Chris Wilson wrote:
> Currently we use the intel_timeline.mutex to guard constructing and
> retiring requests in the timeline, including the adding and removing of
> the request from the list of requests (intel_timeline.requests).
> However, we want to peek at neighbouring elements in the request list
> while constructing a request on another timeline (see
> i915_request_await_start) and this implies nesting timeline mutexes. To
> avoid the nested mutex, we currently use a mutex_trylock() but this is
> fraught with a potential race causing an -EBUSY. We can eliminate the
> nested mutex here with a spinlock guarding list operations within the
> broader mutex, so callers can choose between locking everything with the
> mutex or just the list with the spinlock. (The mutex caters for
> virtually all of the current users, but maybe being able to easily peek
> at the request list, we will do so more often in the future.)
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> ---
> drivers/gpu/drm/i915/gt/intel_timeline.c | 1 +
> .../gpu/drm/i915/gt/intel_timeline_types.h | 1 +
> .../gpu/drm/i915/gt/selftests/mock_timeline.c | 1 +
> drivers/gpu/drm/i915/i915_request.c | 58 +++++++++++--------
> 4 files changed, 36 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gt/intel_timeline.c b/drivers/gpu/drm/i915/gt/intel_timeline.c
> index d71aafb66d6e..728da39e8ace 100644
> --- a/drivers/gpu/drm/i915/gt/intel_timeline.c
> +++ b/drivers/gpu/drm/i915/gt/intel_timeline.c
> @@ -256,6 +256,7 @@ int intel_timeline_init(struct intel_timeline *timeline,
>
> INIT_ACTIVE_FENCE(&timeline->last_request);
> INIT_LIST_HEAD(&timeline->requests);
> + spin_lock_init(&timeline->request_lock);
>
> i915_syncmap_init(&timeline->sync);
>
> diff --git a/drivers/gpu/drm/i915/gt/intel_timeline_types.h b/drivers/gpu/drm/i915/gt/intel_timeline_types.h
> index aaf15cbe1ce1..7c9f49f46626 100644
> --- a/drivers/gpu/drm/i915/gt/intel_timeline_types.h
> +++ b/drivers/gpu/drm/i915/gt/intel_timeline_types.h
> @@ -57,6 +57,7 @@ struct intel_timeline {
> * outstanding.
> */
> struct list_head requests;
> + spinlock_t request_lock;
>
> /*
> * Contains an RCU guarded pointer to the last request. No reference is
> diff --git a/drivers/gpu/drm/i915/gt/selftests/mock_timeline.c b/drivers/gpu/drm/i915/gt/selftests/mock_timeline.c
> index aeb1d1f616e8..540729250fef 100644
> --- a/drivers/gpu/drm/i915/gt/selftests/mock_timeline.c
> +++ b/drivers/gpu/drm/i915/gt/selftests/mock_timeline.c
> @@ -17,6 +17,7 @@ void mock_timeline_init(struct intel_timeline *timeline, u64 context)
>
> INIT_ACTIVE_FENCE(&timeline->last_request);
> INIT_LIST_HEAD(&timeline->requests);
> + spin_lock_init(&timeline->request_lock);
>
> i915_syncmap_init(&timeline->sync);
>
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index fb8738987aeb..5d8b11e64373 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -184,6 +184,27 @@ remove_from_client(struct i915_request *request)
> rcu_read_unlock();
> }
>
> +static inline void remove_from_timeline(struct i915_request *rq)
> +{
> + struct intel_timeline *tl = i915_request_timeline(rq);
> +
> + /*
> + * We know the GPU must have read the request to have
> + * sent us the seqno + interrupt, so use the position
> + * of tail of the request to update the last known position
> + * of the GPU head.
> + *
> + * Note this requires that we are always called in request
> + * completion order.
> + */
> + GEM_BUG_ON(!list_is_first(&rq->link, &tl->requests));
> + rq->ring->head = rq->postfix;
> +
> + spin_lock(&tl->request_lock);
> + list_del(&rq->link);
> + spin_unlock(&tl->request_lock);
> +}
> +
> static void free_capture_list(struct i915_request *request)
> {
> struct i915_capture_list *capture;
> @@ -231,19 +252,6 @@ bool i915_request_retire(struct i915_request *rq)
> GEM_BUG_ON(!i915_sw_fence_signaled(&rq->submit));
> trace_i915_request_retire(rq);
>
> - /*
> - * We know the GPU must have read the request to have
> - * sent us the seqno + interrupt, so use the position
> - * of tail of the request to update the last known position
> - * of the GPU head.
> - *
> - * Note this requires that we are always called in request
> - * completion order.
> - */
> - GEM_BUG_ON(!list_is_first(&rq->link,
> - &i915_request_timeline(rq)->requests));
> - rq->ring->head = rq->postfix;
> -
> /*
> * We only loosely track inflight requests across preemption,
> * and so we may find ourselves attempting to retire a _completed_
> @@ -270,7 +278,7 @@ bool i915_request_retire(struct i915_request *rq)
> spin_unlock_irq(&rq->lock);
>
> remove_from_client(rq);
> - list_del(&rq->link);
> + remove_from_timeline(rq);
>
> intel_context_exit(rq->hw_context);
> intel_context_unpin(rq->hw_context);
> @@ -783,19 +791,17 @@ i915_request_await_start(struct i915_request *rq, struct i915_request *signal)
> if (!tl) /* already started or maybe even completed */
> return 0;
>
> - fence = ERR_PTR(-EAGAIN);
> - if (mutex_trylock(&tl->mutex)) {
> - fence = NULL;
> - if (!i915_request_started(signal) &&
> - !list_is_first(&signal->link, &tl->requests)) {
> - signal = list_prev_entry(signal, link);
> - fence = dma_fence_get(&signal->fence);
> - }
> - mutex_unlock(&tl->mutex);
> + fence = NULL;
> + spin_lock(&tl->request_lock);
> + if (!i915_request_started(signal) &&
> + !list_is_first(&signal->link, &tl->requests)) {
> + signal = list_prev_entry(signal, link);
> + fence = dma_fence_get(&signal->fence);
> }
> + spin_unlock(&tl->request_lock);
> intel_timeline_put(tl);
> - if (IS_ERR_OR_NULL(fence))
> - return PTR_ERR_OR_ZERO(fence);
> + if (!fence)
> + return 0;
>
> err = 0;
> if (intel_timeline_sync_is_later(i915_request_timeline(rq), fence))
> @@ -1238,7 +1244,9 @@ __i915_request_add_to_timeline(struct i915_request *rq)
> 0);
> }
>
> + spin_lock(&timeline->request_lock);
> list_add_tail(&rq->link, &timeline->requests);
> + spin_unlock(&timeline->request_lock);
>
> /*
> * Make sure that no request gazumped us - if it was allocated after
>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
Regards,
Tvrtko
More information about the Intel-gfx
mailing list