[Intel-gfx] [RFC 4/4] drm/i915/guc: Repurpose GuC wq reservation

Chris Wilson chris at chris-wilson.co.uk
Tue Mar 28 19:48:27 UTC 2017


On Tue, Mar 28, 2017 at 08:00:29PM +0200, Michał Winiarski wrote:
> Now that we're only driving GuC submissions from the tasklet, we can
> simply skip the submission if GuC wq is full. This allows us to
> completely remove reservation from the request_alloc path, and only
> use it to manage wq between tasklets belonging to different engines.

Hmm, this sounds like a very good idea.

> Cc: Arkadiusz Hiler <arkadiusz.hiler at intel.com>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
> Cc: Michal Wajdeczko <michal.wajdeczko at intel.com>
> Cc: Oscar Mateo <oscar.mateo at intel.com>
> Signed-off-by: Michał Winiarski <michal.winiarski at intel.com>
> ---
>  drivers/gpu/drm/i915/i915_guc_submission.c | 54 ++++++++++++------------------
>  drivers/gpu/drm/i915/intel_lrc.c           | 25 ++------------
>  drivers/gpu/drm/i915/intel_uc.h            |  2 --
>  3 files changed, 24 insertions(+), 57 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 9975244..4a7ef70 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -407,11 +407,11 @@ static void guc_stage_desc_fini(struct intel_guc *guc,
>  }
>  
>  /**
> - * i915_guc_wq_reserve() - reserve space in the GuC's workqueue
> - * @request:	request associated with the commands
> + * guc_wq_reserve() - reserve space in the GuC's workqueue
> + * @client:	GuC client used for submission
>   *
>   * Return:	0 if space is available
> - *		-EAGAIN if space is not currently available
> + *		-ENOSPC if space is not currently available
>   *
>   * This function must be called (and must return 0) before a request
>   * is submitted to the GuC via i915_guc_submit() below. Once a result
> @@ -419,18 +419,17 @@ static void guc_stage_desc_fini(struct intel_guc *guc,
>   * call to submit().
>   *
>   * Reservation allows the caller to determine in advance that space
> - * will be available for the next submission before committing resources
> - * to it, and helps avoid late failures with complicated recovery paths.
> + * will be available for the next submission.
>   */
> -int i915_guc_wq_reserve(struct drm_i915_gem_request *request)
> +static int guc_wq_reserve(struct i915_guc_client *client)
>  {
>  	const size_t wqi_size = sizeof(struct guc_wq_item);
> -	struct i915_guc_client *client = request->i915->guc.execbuf_client;
>  	struct guc_process_desc *desc = __get_process_desc(client);
>  	u32 freespace;
>  	int ret;
>  
> -	spin_lock_irq(&client->wq_lock);
> +	spin_lock(&client->wq_lock);
> +
>  	freespace = CIRC_SPACE(client->wq_tail, desc->head, client->wq_size);
>  	freespace -= client->wq_rsvd;
>  	if (likely(freespace >= wqi_size)) {
> @@ -438,29 +437,12 @@ int i915_guc_wq_reserve(struct drm_i915_gem_request *request)
>  		ret = 0;
>  	} else {
>  		client->no_wq_space++;
> -		ret = -EAGAIN;
> +		ret = -ENOSPC;
>  	}
> -	spin_unlock_irq(&client->wq_lock);
> -
> -	return ret;
> -}
>  
> -static void guc_client_update_wq_rsvd(struct i915_guc_client *client, int size)
> -{
> -	unsigned long flags;
> -
> -	spin_lock_irqsave(&client->wq_lock, flags);
> -	client->wq_rsvd += size;
> -	spin_unlock_irqrestore(&client->wq_lock, flags);
> -}
> +	spin_unlock(&client->wq_lock);
>  
> -void i915_guc_wq_unreserve(struct drm_i915_gem_request *request)
> -{
> -	const int wqi_size = sizeof(struct guc_wq_item);
> -	struct i915_guc_client *client = request->i915->guc.execbuf_client;
> -
> -	GEM_BUG_ON(READ_ONCE(client->wq_rsvd) < wqi_size);
> -	guc_client_update_wq_rsvd(client, -wqi_size);
> +	return ret;
>  }
>  
>  /* Construct a Work Item and append it to the GuC's Work Queue */
> @@ -475,7 +457,9 @@ static void guc_wq_item_append(struct i915_guc_client *client,
>  	struct guc_wq_item *wqi;
>  	u32 freespace, tail, wq_off;
>  
> -	/* Free space is guaranteed, see i915_guc_wq_reserve() above */
> +	lockdep_assert_held(&client->wq_lock);
> +
> +	/* Free space is guaranteed, see guc_wq_reserve() above */
>  	freespace = CIRC_SPACE(client->wq_tail, desc->head, client->wq_size);
>  	GEM_BUG_ON(freespace < wqi_size);
>  
> @@ -526,6 +510,7 @@ static void guc_reset_wq(struct i915_guc_client *client)
>  	desc->tail = 0;
>  
>  	client->wq_tail = 0;
> +	client->wq_rsvd = 0;
>  }
>  
>  static int guc_ring_doorbell(struct i915_guc_client *client)
> @@ -585,7 +570,7 @@ static int guc_ring_doorbell(struct i915_guc_client *client)
>   * __i915_guc_submit() - Submit commands through GuC
>   * @rq:		request associated with the commands
>   *
> - * The caller must have already called i915_guc_wq_reserve() above with
> + * The caller must have already called guc_wq_reserve() above with
>   * a result of 0 (success), guaranteeing that there is space in the work
>   * queue for the new request, so enqueuing the item cannot fail.
>   *
> @@ -603,14 +588,13 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq)
>  	unsigned int engine_id = engine->id;
>  	struct intel_guc *guc = &rq->i915->guc;
>  	struct i915_guc_client *client = guc->execbuf_client;
> -	unsigned long flags;
>  	int b_ret;
>  
>  	/* WA to flush out the pending GMADR writes to ring buffer. */
>  	if (i915_vma_is_map_and_fenceable(rq->ring->vma))
>  		POSTING_READ_FW(GUC_STATUS);
>  
> -	spin_lock_irqsave(&client->wq_lock, flags);
> +	spin_lock(&client->wq_lock);
>  
>  	guc_wq_item_append(client, rq);
>  	b_ret = guc_ring_doorbell(client);
> @@ -623,7 +607,7 @@ static void __i915_guc_submit(struct drm_i915_gem_request *rq)
>  	guc->submissions[engine_id] += 1;
>  	guc->last_seqno[engine_id] = rq->global_seqno;
>  
> -	spin_unlock_irqrestore(&client->wq_lock, flags);
> +	spin_unlock(&client->wq_lock);
>  }
>  
>  static void i915_guc_submit(struct drm_i915_gem_request *rq)
> @@ -659,6 +643,7 @@ static bool i915_guc_dequeue(struct intel_engine_cs *engine)
>  {
>  	struct execlist_port *port = engine->execlist_port;
>  	struct drm_i915_gem_request *last = port[0].request;
> +	struct i915_guc_client *client = engine->i915->guc.execbuf_client;
>  	struct rb_node *rb;
>  	bool submit = false;
>  
> @@ -680,6 +665,9 @@ static bool i915_guc_dequeue(struct intel_engine_cs *engine)
>  		struct drm_i915_gem_request *rq =
>  			rb_entry(rb, typeof(*rq), priotree.node);
>  
> +		if (guc_wq_reserve(client) != 0)
> +			break;

We shouldn't have to reserve for every request in this case, just for
the batch of requests for the same context as they will share the tail
update.

I don't see a reason why this would depend upon the earlier patches, so
can we spin this off and focus on getting this improvement in?
-Chris

-- 
Chris Wilson, Intel Open Source Technology Centre


More information about the Intel-gfx mailing list