diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ringbuffer.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 38 | 
1 files changed, 36 insertions, 2 deletions
| diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d0ef50bf930a..187bb0ceb4ac 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -91,6 +91,7 @@ static int  gen4_render_ring_flush(struct i915_request *rq, u32 mode)  {  	u32 cmd, *cs; +	int i;  	/*  	 * read/write caches: @@ -127,12 +128,45 @@ gen4_render_ring_flush(struct i915_request *rq, u32 mode)  			cmd |= MI_INVALIDATE_ISP;  	} -	cs = intel_ring_begin(rq, 2); +	i = 2; +	if (mode & EMIT_INVALIDATE) +		i += 20; + +	cs = intel_ring_begin(rq, i);  	if (IS_ERR(cs))  		return PTR_ERR(cs);  	*cs++ = cmd; -	*cs++ = MI_NOOP; + +	/* +	 * A random delay to let the CS invalidate take effect? Without this +	 * delay, the GPU relocation path fails as the CS does not see +	 * the updated contents. Just as important, if we apply the flushes +	 * to the EMIT_FLUSH branch (i.e. immediately after the relocation +	 * write and before the invalidate on the next batch), the relocations +	 * still fail. This implies that is a delay following invalidation +	 * that is required to reset the caches as opposed to a delay to +	 * ensure the memory is written. +	 */ +	if (mode & EMIT_INVALIDATE) { +		*cs++ = GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE; +		*cs++ = i915_ggtt_offset(rq->engine->scratch) | +			PIPE_CONTROL_GLOBAL_GTT; +		*cs++ = 0; +		*cs++ = 0; + +		for (i = 0; i < 12; i++) +			*cs++ = MI_FLUSH; + +		*cs++ = GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE; +		*cs++ = i915_ggtt_offset(rq->engine->scratch) | +			PIPE_CONTROL_GLOBAL_GTT; +		*cs++ = 0; +		*cs++ = 0; +	} + +	*cs++ = cmd; +  	intel_ring_advance(rq, cs);  	return 0; | 
