[Intel-gfx] [PATCH 4/4] drm/i915/execlists: Delay writing to ELSP until HW has processed the previous write

Michel Thierry michel.thierry at intel.com
Mon Nov 20 16:17:01 UTC 2017


On 11/20/2017 4:34 AM, Chris Wilson wrote:
> The hardware needs some time to process the information received in the
> ExecList Submission Port, and expects us to not write anything more until
> it has 'acknowledged' this new submission by sending an IDLE_ACTIVE or
> PREEMPTED CSB event.
> 
> If we do not follow this, the driver could write new data into the ELSP
> before HW had finishing fetching the previous one, putting us in
> 'undefined behaviour' space.
> 
> This seems to be the problem causing the spurious PREEMPTED & COMPLETE
> events after a COMPLETE like the one below:
> 
> [] vcs0: sw rd pointer = 2, hw wr pointer = 0, current 'head' = 3.
> [] vcs0:  Execlist CSB[0]: 0x00000018 _ 0x00000007
> [] vcs0:  Execlist CSB[1]: 0x00000001 _ 0x00000000
> [] vcs0:  Execlist CSB[2]: 0x00000018 _ 0x00000007  <<< COMPLETE
> [] vcs0:  Execlist CSB[3]: 0x00000012 _ 0x00000007  <<< PREEMPTED & COMPLETE
> [] vcs0:  Execlist CSB[4]: 0x00008002 _ 0x00000006
> [] vcs0:  Execlist CSB[5]: 0x00000014 _ 0x00000006
> 
> The ELSP writes that lead to this CSB sequence show that the HW hadn't
> started executing the previous execlist (the one with only ctx 0x6) by the
> time the new one was submitted; this is a bit more clear in the data
> show in the EXECLIST_STATUS register at the time of the ELSP write.
> 
> [] vcs0: ELSP[0] = 0x0_0        [execlist1] - status_reg = 0x0_302
> [] vcs0: ELSP[1] = 0x6_fedb2119 [execlist0] - status_reg = 0x0_8302
> 
> [] vcs0: ELSP[2] = 0x7_fedaf119 [execlist1] - status_reg = 0x0_8308
> [] vcs0: ELSP[3] = 0x6_fedb2119 [execlist0] - status_reg = 0x7_8308
> 
> Note that having to wait for this ack does not disable lite-restores,
> although it may reduce their numbers.
> 
> v2: Rewrote Michel's patch, his digging and his fix, my spelling.
> v3: Reorder to ack early to allow preemption
> 
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=102035
> Suggested-by: Michel Thierry <michel.thierry at intel.com>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Michel Thierry <michel.thierry at intel.com>

Isn't it nice to come back after the weekend and see everything is ok?

Reviewed-by: Michel Thierry <michel.thierry at intel.com>

Thanks,

> ---
>   drivers/gpu/drm/i915/intel_lrc.c        | 22 ++++++++++++++++++++++
>   drivers/gpu/drm/i915/intel_ringbuffer.h |  1 +
>   2 files changed, 23 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index 4aed00323780..8d0c49388863 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -477,6 +477,7 @@ static void execlists_submit_ports(struct intel_engine_cs *engine)
>   
>   		elsp_write(desc, elsp);
>   	}
> +	execlists_clear_active(&engine->execlists, EXECLISTS_ACTIVE_HWACK);
>   }
>   
>   static bool ctx_single_port_submission(const struct i915_gem_context *ctx)
> @@ -529,6 +530,7 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
>   		elsp_write(0, elsp);
>   
>   	elsp_write(ce->lrc_desc, elsp);
> +	execlists_clear_active(&engine->execlists, EXECLISTS_ACTIVE_HWACK);
>   }
>   
>   static void execlists_dequeue(struct intel_engine_cs *engine)
> @@ -575,9 +577,20 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
>   		 * know the next preemption status we see corresponds
>   		 * to this ELSP update.
>   		 */
> +		GEM_BUG_ON(!port_count(&port[0]));
>   		if (port_count(&port[0]) > 1)
>   			goto unlock;
>   
> +		/*
> +		 * If we write to ELSP a second time before the HW has had
> +		 * a chance to respond to the previous write, we can confuse
> +		 * the HW and hit "undefined behaviour". After writing to ELSP,
> +		 * we must then wait until we see a context-switch event from
> +		 * the HW to indicate that it has had a chance to respond.
> +		 */
> +		if (!execlists_is_active(execlists, EXECLISTS_ACTIVE_HWACK))
> +			goto unlock;
> +
>   		if (HAS_LOGICAL_RING_PREEMPTION(engine->i915) &&
>   		    rb_entry(rb, struct i915_priolist, node)->priority >
>   		    max(last->priotree.priority, 0)) {
> @@ -871,6 +884,15 @@ static void execlists_submission_tasklet(unsigned long data)
>   			GEM_TRACE("%s csb[%dd]: status=0x%08x:0x%08x\n",
>   				  engine->name, head,
>   				  status, buf[2*head + 1]);
> +
> +			if (status & (GEN8_CTX_STATUS_IDLE_ACTIVE |
> +				      GEN8_CTX_STATUS_PREEMPTED))
> +				execlists_set_active(execlists,
> +						     EXECLISTS_ACTIVE_HWACK);
> +			if (status & GEN8_CTX_STATUS_ACTIVE_IDLE)
> +				execlists_clear_active(execlists,
> +						       EXECLISTS_ACTIVE_HWACK);
> +
>   			if (!(status & GEN8_CTX_STATUS_COMPLETED_MASK))
>   				continue;
>   
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index f867aa6c31fc..add7a30c1a61 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -252,6 +252,7 @@ struct intel_engine_execlists {
>   	unsigned int active;
>   #define EXECLISTS_ACTIVE_USER 0
>   #define EXECLISTS_ACTIVE_PREEMPT 1
> +#define EXECLISTS_ACTIVE_HWACK 2
>   
>   	/**
>   	 * @port_mask: number of execlist ports - 1
> 


More information about the Intel-gfx mailing list