xref: /dflybsd-src/sys/dev/drm/i915/intel_ringbuffer.c (revision 1487f78699db6b645ec307a207e4611f50a7cc53)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2008-2010 Intel Corporation
3e3adcf8fSFrançois Tigeot  *
4e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10e3adcf8fSFrançois Tigeot  *
11e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13e3adcf8fSFrançois Tigeot  * Software.
14e3adcf8fSFrançois Tigeot  *
15e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20e3adcf8fSFrançois Tigeot  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21e3adcf8fSFrançois Tigeot  * IN THE SOFTWARE.
22e3adcf8fSFrançois Tigeot  *
23e3adcf8fSFrançois Tigeot  * Authors:
24e3adcf8fSFrançois Tigeot  *    Eric Anholt <eric@anholt.net>
25e3adcf8fSFrançois Tigeot  *    Zou Nan hai <nanhai.zou@intel.com>
26e3adcf8fSFrançois Tigeot  *    Xiang Hai hao<haihao.xiang@intel.com>
27e3adcf8fSFrançois Tigeot  *
28e3adcf8fSFrançois Tigeot  */
29e3adcf8fSFrançois Tigeot 
30aee94f86SFrançois Tigeot #include <linux/log2.h>
3118e26a6dSFrançois Tigeot #include <drm/drmP.h>
32e3adcf8fSFrançois Tigeot #include "i915_drv.h"
33a2fdbec6SFrançois Tigeot #include <drm/i915_drm.h>
34a2fdbec6SFrançois Tigeot #include "i915_trace.h"
35e3adcf8fSFrançois Tigeot #include "intel_drv.h"
36e3adcf8fSFrançois Tigeot 
37*1487f786SFrançois Tigeot /* Rough estimate of the typical request size, performing a flush,
38*1487f786SFrançois Tigeot  * set-context and then emitting the batch.
39*1487f786SFrançois Tigeot  */
40*1487f786SFrançois Tigeot #define LEGACY_REQUEST_SIZE 200
41*1487f786SFrançois Tigeot 
421b13d190SFrançois Tigeot int __intel_ring_space(int head, int tail, int size)
43e3adcf8fSFrançois Tigeot {
442c9916cdSFrançois Tigeot 	int space = head - tail;
452c9916cdSFrançois Tigeot 	if (space <= 0)
46ba55f2f5SFrançois Tigeot 		space += size;
472c9916cdSFrançois Tigeot 	return space - I915_RING_FREE_SPACE;
482c9916cdSFrançois Tigeot }
492c9916cdSFrançois Tigeot 
502c9916cdSFrançois Tigeot void intel_ring_update_space(struct intel_ringbuffer *ringbuf)
512c9916cdSFrançois Tigeot {
522c9916cdSFrançois Tigeot 	if (ringbuf->last_retired_head != -1) {
532c9916cdSFrançois Tigeot 		ringbuf->head = ringbuf->last_retired_head;
542c9916cdSFrançois Tigeot 		ringbuf->last_retired_head = -1;
552c9916cdSFrançois Tigeot 	}
562c9916cdSFrançois Tigeot 
572c9916cdSFrançois Tigeot 	ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,
582c9916cdSFrançois Tigeot 					    ringbuf->tail, ringbuf->size);
59e3adcf8fSFrançois Tigeot }
60e3adcf8fSFrançois Tigeot 
618621f407SFrançois Tigeot bool intel_engine_stopped(struct intel_engine_cs *engine)
62ba55f2f5SFrançois Tigeot {
63*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
648621f407SFrançois Tigeot 	return dev_priv->gpu_error.stop_rings & intel_engine_flag(engine);
65ba55f2f5SFrançois Tigeot }
66ba55f2f5SFrançois Tigeot 
678621f407SFrançois Tigeot static void __intel_ring_advance(struct intel_engine_cs *engine)
689edbd4a0SFrançois Tigeot {
698621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = engine->buffer;
70ba55f2f5SFrançois Tigeot 	ringbuf->tail &= ringbuf->size - 1;
718621f407SFrançois Tigeot 	if (intel_engine_stopped(engine))
729edbd4a0SFrançois Tigeot 		return;
738621f407SFrançois Tigeot 	engine->write_tail(engine, ringbuf->tail);
749edbd4a0SFrançois Tigeot }
759edbd4a0SFrançois Tigeot 
76e3adcf8fSFrançois Tigeot static int
77a05eeebfSFrançois Tigeot gen2_render_ring_flush(struct drm_i915_gem_request *req,
78686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
79686a02f1SFrançois Tigeot 		       u32	flush_domains)
80686a02f1SFrançois Tigeot {
818621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
82686a02f1SFrançois Tigeot 	u32 cmd;
83686a02f1SFrançois Tigeot 	int ret;
84686a02f1SFrançois Tigeot 
85686a02f1SFrançois Tigeot 	cmd = MI_FLUSH;
86686a02f1SFrançois Tigeot 	if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0)
87686a02f1SFrançois Tigeot 		cmd |= MI_NO_WRITE_FLUSH;
88686a02f1SFrançois Tigeot 
89686a02f1SFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
90686a02f1SFrançois Tigeot 		cmd |= MI_READ_FLUSH;
91686a02f1SFrançois Tigeot 
92a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
93686a02f1SFrançois Tigeot 	if (ret)
94686a02f1SFrançois Tigeot 		return ret;
95686a02f1SFrançois Tigeot 
968621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
978621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
988621f407SFrançois Tigeot 	intel_ring_advance(engine);
99686a02f1SFrançois Tigeot 
100686a02f1SFrançois Tigeot 	return 0;
101686a02f1SFrançois Tigeot }
102686a02f1SFrançois Tigeot 
103686a02f1SFrançois Tigeot static int
104a05eeebfSFrançois Tigeot gen4_render_ring_flush(struct drm_i915_gem_request *req,
105686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
106686a02f1SFrançois Tigeot 		       u32	flush_domains)
107e3adcf8fSFrançois Tigeot {
1088621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
109686a02f1SFrançois Tigeot 	u32 cmd;
110e3adcf8fSFrançois Tigeot 	int ret;
111e3adcf8fSFrançois Tigeot 
112e3adcf8fSFrançois Tigeot 	/*
113e3adcf8fSFrançois Tigeot 	 * read/write caches:
114e3adcf8fSFrançois Tigeot 	 *
115e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER is always invalidated, but is
116e3adcf8fSFrançois Tigeot 	 * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
117e3adcf8fSFrançois Tigeot 	 * also flushed at 2d versus 3d pipeline switches.
118e3adcf8fSFrançois Tigeot 	 *
119e3adcf8fSFrançois Tigeot 	 * read-only caches:
120e3adcf8fSFrançois Tigeot 	 *
121e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
122e3adcf8fSFrançois Tigeot 	 * MI_READ_FLUSH is set, and is always flushed on 965.
123e3adcf8fSFrançois Tigeot 	 *
124e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_COMMAND may not exist?
125e3adcf8fSFrançois Tigeot 	 *
126e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
127e3adcf8fSFrançois Tigeot 	 * invalidated when MI_EXE_FLUSH is set.
128e3adcf8fSFrançois Tigeot 	 *
129e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
130e3adcf8fSFrançois Tigeot 	 * invalidated with every MI_FLUSH.
131e3adcf8fSFrançois Tigeot 	 *
132e3adcf8fSFrançois Tigeot 	 * TLBs:
133e3adcf8fSFrançois Tigeot 	 *
134e3adcf8fSFrançois Tigeot 	 * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
135e3adcf8fSFrançois Tigeot 	 * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
136e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
137e3adcf8fSFrançois Tigeot 	 * are flushed at any MI_FLUSH.
138e3adcf8fSFrançois Tigeot 	 */
139e3adcf8fSFrançois Tigeot 
140e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
141686a02f1SFrançois Tigeot 	if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER)
142e3adcf8fSFrançois Tigeot 		cmd &= ~MI_NO_WRITE_FLUSH;
143e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
144e3adcf8fSFrançois Tigeot 		cmd |= MI_EXE_FLUSH;
145e3adcf8fSFrançois Tigeot 
146e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
147*1487f786SFrançois Tigeot 	    (IS_G4X(req->i915) || IS_GEN5(req->i915)))
148e3adcf8fSFrançois Tigeot 		cmd |= MI_INVALIDATE_ISP;
149e3adcf8fSFrançois Tigeot 
150a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
151e3adcf8fSFrançois Tigeot 	if (ret)
152e3adcf8fSFrançois Tigeot 		return ret;
153e3adcf8fSFrançois Tigeot 
1548621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
1558621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
1568621f407SFrançois Tigeot 	intel_ring_advance(engine);
157e3adcf8fSFrançois Tigeot 
158e3adcf8fSFrançois Tigeot 	return 0;
159e3adcf8fSFrançois Tigeot }
160e3adcf8fSFrançois Tigeot 
161e3adcf8fSFrançois Tigeot /**
162e3adcf8fSFrançois Tigeot  * Emits a PIPE_CONTROL with a non-zero post-sync operation, for
163e3adcf8fSFrançois Tigeot  * implementing two workarounds on gen6.  From section 1.4.7.1
164e3adcf8fSFrançois Tigeot  * "PIPE_CONTROL" of the Sandy Bridge PRM volume 2 part 1:
165e3adcf8fSFrançois Tigeot  *
166e3adcf8fSFrançois Tigeot  * [DevSNB-C+{W/A}] Before any depth stall flush (including those
167e3adcf8fSFrançois Tigeot  * produced by non-pipelined state commands), software needs to first
168e3adcf8fSFrançois Tigeot  * send a PIPE_CONTROL with no bits set except Post-Sync Operation !=
169e3adcf8fSFrançois Tigeot  * 0.
170e3adcf8fSFrançois Tigeot  *
171e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Before a PIPE_CONTROL with Write Cache Flush Enable
172e3adcf8fSFrançois Tigeot  * =1, a PIPE_CONTROL with any non-zero post-sync-op is required.
173e3adcf8fSFrançois Tigeot  *
174e3adcf8fSFrançois Tigeot  * And the workaround for these two requires this workaround first:
175e3adcf8fSFrançois Tigeot  *
176e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
177e3adcf8fSFrançois Tigeot  * BEFORE the pipe-control with a post-sync op and no write-cache
178e3adcf8fSFrançois Tigeot  * flushes.
179e3adcf8fSFrançois Tigeot  *
180e3adcf8fSFrançois Tigeot  * And this last workaround is tricky because of the requirements on
181e3adcf8fSFrançois Tigeot  * that bit.  From section 1.4.7.2.3 "Stall" of the Sandy Bridge PRM
182e3adcf8fSFrançois Tigeot  * volume 2 part 1:
183e3adcf8fSFrançois Tigeot  *
184e3adcf8fSFrançois Tigeot  *     "1 of the following must also be set:
185e3adcf8fSFrançois Tigeot  *      - Render Target Cache Flush Enable ([12] of DW1)
186e3adcf8fSFrançois Tigeot  *      - Depth Cache Flush Enable ([0] of DW1)
187e3adcf8fSFrançois Tigeot  *      - Stall at Pixel Scoreboard ([1] of DW1)
188e3adcf8fSFrançois Tigeot  *      - Depth Stall ([13] of DW1)
189e3adcf8fSFrançois Tigeot  *      - Post-Sync Operation ([13] of DW1)
190e3adcf8fSFrançois Tigeot  *      - Notify Enable ([8] of DW1)"
191e3adcf8fSFrançois Tigeot  *
192e3adcf8fSFrançois Tigeot  * The cache flushes require the workaround flush that triggered this
193e3adcf8fSFrançois Tigeot  * one, so we can't use it.  Depth stall would trigger the same.
194e3adcf8fSFrançois Tigeot  * Post-sync nonzero is what triggered this second workaround, so we
195e3adcf8fSFrançois Tigeot  * can't use that one either.  Notify enable is IRQs, which aren't
196e3adcf8fSFrançois Tigeot  * really our business.  That leaves only stall at scoreboard.
197e3adcf8fSFrançois Tigeot  */
198e3adcf8fSFrançois Tigeot static int
199a05eeebfSFrançois Tigeot intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
200e3adcf8fSFrançois Tigeot {
2018621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2028621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
203e3adcf8fSFrançois Tigeot 	int ret;
204e3adcf8fSFrançois Tigeot 
205a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
206e3adcf8fSFrançois Tigeot 	if (ret)
207e3adcf8fSFrançois Tigeot 		return ret;
208e3adcf8fSFrançois Tigeot 
2098621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
2108621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
211e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_STALL_AT_SCOREBOARD);
2128621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
2138621f407SFrançois Tigeot 	intel_ring_emit(engine, 0); /* low dword */
2148621f407SFrançois Tigeot 	intel_ring_emit(engine, 0); /* high dword */
2158621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
2168621f407SFrançois Tigeot 	intel_ring_advance(engine);
217e3adcf8fSFrançois Tigeot 
218a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
219e3adcf8fSFrançois Tigeot 	if (ret)
220e3adcf8fSFrançois Tigeot 		return ret;
221e3adcf8fSFrançois Tigeot 
2228621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
2238621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_QW_WRITE);
2248621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
2258621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2268621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2278621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
2288621f407SFrançois Tigeot 	intel_ring_advance(engine);
229e3adcf8fSFrançois Tigeot 
230e3adcf8fSFrançois Tigeot 	return 0;
231e3adcf8fSFrançois Tigeot }
232e3adcf8fSFrançois Tigeot 
233e3adcf8fSFrançois Tigeot static int
234a05eeebfSFrançois Tigeot gen6_render_ring_flush(struct drm_i915_gem_request *req,
235e3adcf8fSFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
236e3adcf8fSFrançois Tigeot {
2378621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
238e3adcf8fSFrançois Tigeot 	u32 flags = 0;
2398621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
240e3adcf8fSFrançois Tigeot 	int ret;
241e3adcf8fSFrançois Tigeot 
242e3adcf8fSFrançois Tigeot 	/* Force SNB workarounds for PIPE_CONTROL flushes */
243a05eeebfSFrançois Tigeot 	ret = intel_emit_post_sync_nonzero_flush(req);
244686a02f1SFrançois Tigeot 	if (ret)
245686a02f1SFrançois Tigeot 		return ret;
246e3adcf8fSFrançois Tigeot 
247e3adcf8fSFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
248e3adcf8fSFrançois Tigeot 	 * number of bits based on the write domains has little performance
249e3adcf8fSFrançois Tigeot 	 * impact.
250e3adcf8fSFrançois Tigeot 	 */
251b5c29a34SFrançois Tigeot 	if (flush_domains) {
252e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
253b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
254b5c29a34SFrançois Tigeot 		/*
255b5c29a34SFrançois Tigeot 		 * Ensure that any following seqno writes only happen
256b5c29a34SFrançois Tigeot 		 * when the render cache is indeed flushed.
257b5c29a34SFrançois Tigeot 		 */
258b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CS_STALL;
259b5c29a34SFrançois Tigeot 	}
260b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
261686a02f1SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
262e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
263e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
264e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
265e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
266e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
267686a02f1SFrançois Tigeot 		/*
268b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
269686a02f1SFrançois Tigeot 		 */
270b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL;
271b5c29a34SFrançois Tigeot 	}
272e3adcf8fSFrançois Tigeot 
273a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
274e3adcf8fSFrançois Tigeot 	if (ret)
275e3adcf8fSFrançois Tigeot 		return ret;
276e3adcf8fSFrançois Tigeot 
2778621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
2788621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
2798621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
2808621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2818621f407SFrançois Tigeot 	intel_ring_advance(engine);
282b5c29a34SFrançois Tigeot 
283b5c29a34SFrançois Tigeot 	return 0;
284b5c29a34SFrançois Tigeot }
285b5c29a34SFrançois Tigeot 
286b5c29a34SFrançois Tigeot static int
287a05eeebfSFrançois Tigeot gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
288b5c29a34SFrançois Tigeot {
2898621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
290b5c29a34SFrançois Tigeot 	int ret;
291b5c29a34SFrançois Tigeot 
292a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
293b5c29a34SFrançois Tigeot 	if (ret)
294b5c29a34SFrançois Tigeot 		return ret;
295b5c29a34SFrançois Tigeot 
2968621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
2978621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
298b5c29a34SFrançois Tigeot 			      PIPE_CONTROL_STALL_AT_SCOREBOARD);
2998621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3008621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3018621f407SFrançois Tigeot 	intel_ring_advance(engine);
302b5c29a34SFrançois Tigeot 
303b5c29a34SFrançois Tigeot 	return 0;
304b5c29a34SFrançois Tigeot }
305b5c29a34SFrançois Tigeot 
306b5c29a34SFrançois Tigeot static int
307a05eeebfSFrançois Tigeot gen7_render_ring_flush(struct drm_i915_gem_request *req,
308b5c29a34SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
309b5c29a34SFrançois Tigeot {
3108621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
311b5c29a34SFrançois Tigeot 	u32 flags = 0;
3128621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
313b5c29a34SFrançois Tigeot 	int ret;
314b5c29a34SFrançois Tigeot 
315b5c29a34SFrançois Tigeot 	/*
316b5c29a34SFrançois Tigeot 	 * Ensure that any following seqno writes only happen when the render
317b5c29a34SFrançois Tigeot 	 * cache is indeed flushed.
318b5c29a34SFrançois Tigeot 	 *
319b5c29a34SFrançois Tigeot 	 * Workaround: 4th PIPE_CONTROL command (except the ones with only
320b5c29a34SFrançois Tigeot 	 * read-cache invalidate bits set) must have the CS_STALL bit set. We
321b5c29a34SFrançois Tigeot 	 * don't try to be clever and just set it unconditionally.
322b5c29a34SFrançois Tigeot 	 */
323b5c29a34SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
324b5c29a34SFrançois Tigeot 
325b5c29a34SFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
326b5c29a34SFrançois Tigeot 	 * number of bits based on the write domains has little performance
327b5c29a34SFrançois Tigeot 	 * impact.
328b5c29a34SFrançois Tigeot 	 */
329b5c29a34SFrançois Tigeot 	if (flush_domains) {
330b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
331b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
332aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
333b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
334b5c29a34SFrançois Tigeot 	}
335b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
336b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
337b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
338b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
339b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
340b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
341b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
3422c9916cdSFrançois Tigeot 		flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR;
343b5c29a34SFrançois Tigeot 		/*
344b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
345b5c29a34SFrançois Tigeot 		 */
346b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
347a2fdbec6SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
348b5c29a34SFrançois Tigeot 
3490dbf0ea8SMatthew Dillon 		flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD;
3500dbf0ea8SMatthew Dillon 
351b5c29a34SFrançois Tigeot 		/* Workaround: we must issue a pipe_control with CS-stall bit
352b5c29a34SFrançois Tigeot 		 * set before a pipe_control command that has the state cache
353b5c29a34SFrançois Tigeot 		 * invalidate bit set. */
354a05eeebfSFrançois Tigeot 		gen7_render_ring_cs_stall_wa(req);
355b5c29a34SFrançois Tigeot 	}
356b5c29a34SFrançois Tigeot 
357a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
358b5c29a34SFrançois Tigeot 	if (ret)
359b5c29a34SFrançois Tigeot 		return ret;
360b5c29a34SFrançois Tigeot 
3618621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
3628621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
3638621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr);
3648621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3658621f407SFrançois Tigeot 	intel_ring_advance(engine);
366e3adcf8fSFrançois Tigeot 
367e3adcf8fSFrançois Tigeot 	return 0;
368e3adcf8fSFrançois Tigeot }
369e3adcf8fSFrançois Tigeot 
3709edbd4a0SFrançois Tigeot static int
371a05eeebfSFrançois Tigeot gen8_emit_pipe_control(struct drm_i915_gem_request *req,
37224edb884SFrançois Tigeot 		       u32 flags, u32 scratch_addr)
37324edb884SFrançois Tigeot {
3748621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
37524edb884SFrançois Tigeot 	int ret;
37624edb884SFrançois Tigeot 
377a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
37824edb884SFrançois Tigeot 	if (ret)
37924edb884SFrançois Tigeot 		return ret;
38024edb884SFrançois Tigeot 
3818621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
3828621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
3838621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr);
3848621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3858621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3868621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3878621f407SFrançois Tigeot 	intel_ring_advance(engine);
38824edb884SFrançois Tigeot 
38924edb884SFrançois Tigeot 	return 0;
39024edb884SFrançois Tigeot }
39124edb884SFrançois Tigeot 
39224edb884SFrançois Tigeot static int
393a05eeebfSFrançois Tigeot gen8_render_ring_flush(struct drm_i915_gem_request *req,
3949edbd4a0SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
3959edbd4a0SFrançois Tigeot {
3969edbd4a0SFrançois Tigeot 	u32 flags = 0;
3978621f407SFrançois Tigeot 	u32 scratch_addr = req->engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
3989edbd4a0SFrançois Tigeot 	int ret;
3999edbd4a0SFrançois Tigeot 
4009edbd4a0SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
4019edbd4a0SFrançois Tigeot 
4029edbd4a0SFrançois Tigeot 	if (flush_domains) {
4039edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
4049edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
405aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
406b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
4079edbd4a0SFrançois Tigeot 	}
4089edbd4a0SFrançois Tigeot 	if (invalidate_domains) {
4099edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
4109edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
4119edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
4129edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
4139edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
4149edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
4159edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
4169edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
4179edbd4a0SFrançois Tigeot 
41824edb884SFrançois Tigeot 		/* WaCsStallBeforeStateCacheInvalidate:bdw,chv */
419a05eeebfSFrançois Tigeot 		ret = gen8_emit_pipe_control(req,
42024edb884SFrançois Tigeot 					     PIPE_CONTROL_CS_STALL |
42124edb884SFrançois Tigeot 					     PIPE_CONTROL_STALL_AT_SCOREBOARD,
42224edb884SFrançois Tigeot 					     0);
4239edbd4a0SFrançois Tigeot 		if (ret)
4249edbd4a0SFrançois Tigeot 			return ret;
42524edb884SFrançois Tigeot 	}
4269edbd4a0SFrançois Tigeot 
427a05eeebfSFrançois Tigeot 	return gen8_emit_pipe_control(req, flags, scratch_addr);
4289edbd4a0SFrançois Tigeot }
4299edbd4a0SFrançois Tigeot 
4308621f407SFrançois Tigeot static void ring_write_tail(struct intel_engine_cs *engine,
431b5c29a34SFrançois Tigeot 			    u32 value)
432e3adcf8fSFrançois Tigeot {
433*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
4348621f407SFrançois Tigeot 	I915_WRITE_TAIL(engine, value);
435e3adcf8fSFrançois Tigeot }
436e3adcf8fSFrançois Tigeot 
4378621f407SFrançois Tigeot u64 intel_ring_get_active_head(struct intel_engine_cs *engine)
438e3adcf8fSFrançois Tigeot {
439*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
440ba55f2f5SFrançois Tigeot 	u64 acthd;
441e3adcf8fSFrançois Tigeot 
442*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
4438621f407SFrançois Tigeot 		acthd = I915_READ64_2x32(RING_ACTHD(engine->mmio_base),
4448621f407SFrançois Tigeot 					 RING_ACTHD_UDW(engine->mmio_base));
445*1487f786SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 4)
4468621f407SFrançois Tigeot 		acthd = I915_READ(RING_ACTHD(engine->mmio_base));
447ba55f2f5SFrançois Tigeot 	else
448ba55f2f5SFrançois Tigeot 		acthd = I915_READ(ACTHD);
449ba55f2f5SFrançois Tigeot 
450ba55f2f5SFrançois Tigeot 	return acthd;
451e3adcf8fSFrançois Tigeot }
452e3adcf8fSFrançois Tigeot 
4538621f407SFrançois Tigeot static void ring_setup_phys_status_page(struct intel_engine_cs *engine)
4545d0b1887SFrançois Tigeot {
455*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
4565d0b1887SFrançois Tigeot 	u32 addr;
4575d0b1887SFrançois Tigeot 
4585d0b1887SFrançois Tigeot 	addr = dev_priv->status_page_dmah->busaddr;
459*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 4)
4605d0b1887SFrançois Tigeot 		addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0;
4615d0b1887SFrançois Tigeot 	I915_WRITE(HWS_PGA, addr);
4625d0b1887SFrançois Tigeot }
4635d0b1887SFrançois Tigeot 
4648621f407SFrançois Tigeot static void intel_ring_setup_status_page(struct intel_engine_cs *engine)
465477eb7f9SFrançois Tigeot {
466*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
467aee94f86SFrançois Tigeot 	i915_reg_t mmio;
468477eb7f9SFrançois Tigeot 
469477eb7f9SFrançois Tigeot 	/* The ring status page addresses are no longer next to the rest of
470477eb7f9SFrançois Tigeot 	 * the ring registers as of gen7.
471477eb7f9SFrançois Tigeot 	 */
472*1487f786SFrançois Tigeot 	if (IS_GEN7(dev_priv)) {
4738621f407SFrançois Tigeot 		switch (engine->id) {
474477eb7f9SFrançois Tigeot 		case RCS:
475477eb7f9SFrançois Tigeot 			mmio = RENDER_HWS_PGA_GEN7;
476477eb7f9SFrançois Tigeot 			break;
477477eb7f9SFrançois Tigeot 		case BCS:
478477eb7f9SFrançois Tigeot 			mmio = BLT_HWS_PGA_GEN7;
479477eb7f9SFrançois Tigeot 			break;
480477eb7f9SFrançois Tigeot 		/*
481477eb7f9SFrançois Tigeot 		 * VCS2 actually doesn't exist on Gen7. Only shut up
482477eb7f9SFrançois Tigeot 		 * gcc switch check warning
483477eb7f9SFrançois Tigeot 		 */
484477eb7f9SFrançois Tigeot 		case VCS2:
485477eb7f9SFrançois Tigeot 		case VCS:
486477eb7f9SFrançois Tigeot 			mmio = BSD_HWS_PGA_GEN7;
487477eb7f9SFrançois Tigeot 			break;
488477eb7f9SFrançois Tigeot 		case VECS:
489477eb7f9SFrançois Tigeot 			mmio = VEBOX_HWS_PGA_GEN7;
490477eb7f9SFrançois Tigeot 			break;
491477eb7f9SFrançois Tigeot 		}
492*1487f786SFrançois Tigeot 	} else if (IS_GEN6(dev_priv)) {
4938621f407SFrançois Tigeot 		mmio = RING_HWS_PGA_GEN6(engine->mmio_base);
494477eb7f9SFrançois Tigeot 	} else {
495477eb7f9SFrançois Tigeot 		/* XXX: gen8 returns to sanity */
4968621f407SFrançois Tigeot 		mmio = RING_HWS_PGA(engine->mmio_base);
497477eb7f9SFrançois Tigeot 	}
498477eb7f9SFrançois Tigeot 
4998621f407SFrançois Tigeot 	I915_WRITE(mmio, (u32)engine->status_page.gfx_addr);
500477eb7f9SFrançois Tigeot 	POSTING_READ(mmio);
501477eb7f9SFrançois Tigeot 
502477eb7f9SFrançois Tigeot 	/*
503477eb7f9SFrançois Tigeot 	 * Flush the TLB for this page
504477eb7f9SFrançois Tigeot 	 *
505477eb7f9SFrançois Tigeot 	 * FIXME: These two bits have disappeared on gen8, so a question
506477eb7f9SFrançois Tigeot 	 * arises: do we still need this and if so how should we go about
507477eb7f9SFrançois Tigeot 	 * invalidating the TLB?
508477eb7f9SFrançois Tigeot 	 */
509*1487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 6, 7)) {
5108621f407SFrançois Tigeot 		i915_reg_t reg = RING_INSTPM(engine->mmio_base);
511477eb7f9SFrançois Tigeot 
512477eb7f9SFrançois Tigeot 		/* ring should be idle before issuing a sync flush*/
5138621f407SFrançois Tigeot 		WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0);
514477eb7f9SFrançois Tigeot 
515477eb7f9SFrançois Tigeot 		I915_WRITE(reg,
516477eb7f9SFrançois Tigeot 			   _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
517477eb7f9SFrançois Tigeot 					      INSTPM_SYNC_FLUSH));
518*1487f786SFrançois Tigeot 		if (intel_wait_for_register(dev_priv,
519*1487f786SFrançois Tigeot 					    reg, INSTPM_SYNC_FLUSH, 0,
520477eb7f9SFrançois Tigeot 					    1000))
521477eb7f9SFrançois Tigeot 			DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
5228621f407SFrançois Tigeot 				  engine->name);
523477eb7f9SFrançois Tigeot 	}
524477eb7f9SFrançois Tigeot }
525477eb7f9SFrançois Tigeot 
5268621f407SFrançois Tigeot static bool stop_ring(struct intel_engine_cs *engine)
527e3adcf8fSFrançois Tigeot {
528*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
529e3adcf8fSFrançois Tigeot 
530*1487f786SFrançois Tigeot 	if (!IS_GEN2(dev_priv)) {
5318621f407SFrançois Tigeot 		I915_WRITE_MODE(engine, _MASKED_BIT_ENABLE(STOP_RING));
532*1487f786SFrançois Tigeot 		if (intel_wait_for_register(dev_priv,
533*1487f786SFrançois Tigeot 					    RING_MI_MODE(engine->mmio_base),
534*1487f786SFrançois Tigeot 					    MODE_IDLE,
535*1487f786SFrançois Tigeot 					    MODE_IDLE,
536*1487f786SFrançois Tigeot 					    1000)) {
5378621f407SFrançois Tigeot 			DRM_ERROR("%s : timed out trying to stop ring\n",
5388621f407SFrançois Tigeot 				  engine->name);
5391b13d190SFrançois Tigeot 			/* Sometimes we observe that the idle flag is not
5401b13d190SFrançois Tigeot 			 * set even though the ring is empty. So double
5411b13d190SFrançois Tigeot 			 * check before giving up.
5421b13d190SFrançois Tigeot 			 */
5438621f407SFrançois Tigeot 			if (I915_READ_HEAD(engine) != I915_READ_TAIL(engine))
544ba55f2f5SFrançois Tigeot 				return false;
545ba55f2f5SFrançois Tigeot 		}
546ba55f2f5SFrançois Tigeot 	}
547686a02f1SFrançois Tigeot 
5488621f407SFrançois Tigeot 	I915_WRITE_CTL(engine, 0);
5498621f407SFrançois Tigeot 	I915_WRITE_HEAD(engine, 0);
5508621f407SFrançois Tigeot 	engine->write_tail(engine, 0);
551e3adcf8fSFrançois Tigeot 
552*1487f786SFrançois Tigeot 	if (!IS_GEN2(dev_priv)) {
5538621f407SFrançois Tigeot 		(void)I915_READ_CTL(engine);
5548621f407SFrançois Tigeot 		I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING));
555ba55f2f5SFrançois Tigeot 	}
556e3adcf8fSFrançois Tigeot 
5578621f407SFrançois Tigeot 	return (I915_READ_HEAD(engine) & HEAD_ADDR) == 0;
558ba55f2f5SFrançois Tigeot }
559ba55f2f5SFrançois Tigeot 
5608621f407SFrançois Tigeot void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
561ba55f2f5SFrançois Tigeot {
5628621f407SFrançois Tigeot 	memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
5638621f407SFrançois Tigeot }
5648621f407SFrançois Tigeot 
5658621f407SFrançois Tigeot static int init_ring_common(struct intel_engine_cs *engine)
5668621f407SFrançois Tigeot {
567*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
5688621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = engine->buffer;
569ba55f2f5SFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
570ba55f2f5SFrançois Tigeot 	int ret = 0;
571ba55f2f5SFrançois Tigeot 
5722c9916cdSFrançois Tigeot 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
573ba55f2f5SFrançois Tigeot 
5748621f407SFrançois Tigeot 	if (!stop_ring(engine)) {
575ba55f2f5SFrançois Tigeot 		/* G45 ring initialization often fails to reset head to zero */
576b5c29a34SFrançois Tigeot 		DRM_DEBUG_KMS("%s head not reset to zero "
577e3adcf8fSFrançois Tigeot 			      "ctl %08x head %08x tail %08x start %08x\n",
5788621f407SFrançois Tigeot 			      engine->name,
5798621f407SFrançois Tigeot 			      I915_READ_CTL(engine),
5808621f407SFrançois Tigeot 			      I915_READ_HEAD(engine),
5818621f407SFrançois Tigeot 			      I915_READ_TAIL(engine),
5828621f407SFrançois Tigeot 			      I915_READ_START(engine));
583e3adcf8fSFrançois Tigeot 
5848621f407SFrançois Tigeot 		if (!stop_ring(engine)) {
585e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to set %s head to zero "
586e3adcf8fSFrançois Tigeot 				  "ctl %08x head %08x tail %08x start %08x\n",
5878621f407SFrançois Tigeot 				  engine->name,
5888621f407SFrançois Tigeot 				  I915_READ_CTL(engine),
5898621f407SFrançois Tigeot 				  I915_READ_HEAD(engine),
5908621f407SFrançois Tigeot 				  I915_READ_TAIL(engine),
5918621f407SFrançois Tigeot 				  I915_READ_START(engine));
592686a02f1SFrançois Tigeot 			ret = -EIO;
593686a02f1SFrançois Tigeot 			goto out;
594e3adcf8fSFrançois Tigeot 		}
595ba55f2f5SFrançois Tigeot 	}
596ba55f2f5SFrançois Tigeot 
597*1487f786SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev_priv))
5988621f407SFrançois Tigeot 		intel_ring_setup_status_page(engine);
599ba55f2f5SFrançois Tigeot 	else
6008621f407SFrançois Tigeot 		ring_setup_phys_status_page(engine);
601ba55f2f5SFrançois Tigeot 
6020f370975SMatthew Dillon 	/* Enforce ordering by reading HEAD register back */
6038621f407SFrançois Tigeot 	I915_READ_HEAD(engine);
6040f370975SMatthew Dillon 
605ba55f2f5SFrançois Tigeot 	/* Initialize the ring. This must happen _after_ we've cleared the ring
606ba55f2f5SFrançois Tigeot 	 * registers with the above sequence (the readback of the HEAD registers
607ba55f2f5SFrançois Tigeot 	 * also enforces ordering), otherwise the hw might lose the new ring
608ba55f2f5SFrançois Tigeot 	 * register values. */
6098621f407SFrançois Tigeot 	I915_WRITE_START(engine, i915_gem_obj_ggtt_offset(obj));
6101b13d190SFrançois Tigeot 
6111b13d190SFrançois Tigeot 	/* WaClearRingBufHeadRegAtInit:ctg,elk */
6128621f407SFrançois Tigeot 	if (I915_READ_HEAD(engine))
6131b13d190SFrançois Tigeot 		DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
6148621f407SFrançois Tigeot 			  engine->name, I915_READ_HEAD(engine));
6158621f407SFrançois Tigeot 	I915_WRITE_HEAD(engine, 0);
6168621f407SFrançois Tigeot 	(void)I915_READ_HEAD(engine);
6171b13d190SFrançois Tigeot 
6188621f407SFrançois Tigeot 	I915_WRITE_CTL(engine,
619ba55f2f5SFrançois Tigeot 			((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES)
620ba55f2f5SFrançois Tigeot 			| RING_VALID);
621ba55f2f5SFrançois Tigeot 
622ba55f2f5SFrançois Tigeot 	/* If the head is still not zero, the ring is dead */
6238621f407SFrançois Tigeot 	if (wait_for((I915_READ_CTL(engine) & RING_VALID) != 0 &&
6248621f407SFrançois Tigeot 		     I915_READ_START(engine) == i915_gem_obj_ggtt_offset(obj) &&
6258621f407SFrançois Tigeot 		     (I915_READ_HEAD(engine) & HEAD_ADDR) == 0, 50)) {
626ba55f2f5SFrançois Tigeot 		DRM_ERROR("%s initialization failed "
627ba55f2f5SFrançois Tigeot 			  "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08lx]\n",
6288621f407SFrançois Tigeot 			  engine->name,
6298621f407SFrançois Tigeot 			  I915_READ_CTL(engine),
6308621f407SFrançois Tigeot 			  I915_READ_CTL(engine) & RING_VALID,
6318621f407SFrançois Tigeot 			  I915_READ_HEAD(engine), I915_READ_TAIL(engine),
6328621f407SFrançois Tigeot 			  I915_READ_START(engine),
6338621f407SFrançois Tigeot 			  (unsigned long)i915_gem_obj_ggtt_offset(obj));
634ba55f2f5SFrançois Tigeot 		ret = -EIO;
635ba55f2f5SFrançois Tigeot 		goto out;
636ba55f2f5SFrançois Tigeot 	}
637e3adcf8fSFrançois Tigeot 
6382c9916cdSFrançois Tigeot 	ringbuf->last_retired_head = -1;
6398621f407SFrançois Tigeot 	ringbuf->head = I915_READ_HEAD(engine);
6408621f407SFrançois Tigeot 	ringbuf->tail = I915_READ_TAIL(engine) & TAIL_ADDR;
6412c9916cdSFrançois Tigeot 	intel_ring_update_space(ringbuf);
642e3adcf8fSFrançois Tigeot 
6438621f407SFrançois Tigeot 	intel_engine_init_hangcheck(engine);
6445d0b1887SFrançois Tigeot 
645686a02f1SFrançois Tigeot out:
6462c9916cdSFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
647686a02f1SFrançois Tigeot 
648686a02f1SFrançois Tigeot 	return ret;
649e3adcf8fSFrançois Tigeot }
650e3adcf8fSFrançois Tigeot 
6511b13d190SFrançois Tigeot void
6528621f407SFrançois Tigeot intel_fini_pipe_control(struct intel_engine_cs *engine)
6531b13d190SFrançois Tigeot {
6548621f407SFrançois Tigeot 	if (engine->scratch.obj == NULL)
6551b13d190SFrançois Tigeot 		return;
6561b13d190SFrançois Tigeot 
657*1487f786SFrançois Tigeot 	if (INTEL_GEN(engine->i915) >= 5) {
6588621f407SFrançois Tigeot 		kunmap(sg_page(engine->scratch.obj->pages->sgl));
6598621f407SFrançois Tigeot 		i915_gem_object_ggtt_unpin(engine->scratch.obj);
6601b13d190SFrançois Tigeot 	}
6611b13d190SFrançois Tigeot 
6628621f407SFrançois Tigeot 	drm_gem_object_unreference(&engine->scratch.obj->base);
6638621f407SFrançois Tigeot 	engine->scratch.obj = NULL;
6641b13d190SFrançois Tigeot }
6651b13d190SFrançois Tigeot 
6661b13d190SFrançois Tigeot int
6678621f407SFrançois Tigeot intel_init_pipe_control(struct intel_engine_cs *engine)
668e3adcf8fSFrançois Tigeot {
669e3adcf8fSFrançois Tigeot 	int ret;
670e3adcf8fSFrançois Tigeot 
6718621f407SFrançois Tigeot 	WARN_ON(engine->scratch.obj);
672e3adcf8fSFrançois Tigeot 
673*1487f786SFrançois Tigeot 	engine->scratch.obj = i915_gem_object_create(engine->i915->dev, 4096);
674*1487f786SFrançois Tigeot 	if (IS_ERR(engine->scratch.obj)) {
675e3adcf8fSFrançois Tigeot 		DRM_ERROR("Failed to allocate seqno page\n");
676*1487f786SFrançois Tigeot 		ret = PTR_ERR(engine->scratch.obj);
677*1487f786SFrançois Tigeot 		engine->scratch.obj = NULL;
678e3adcf8fSFrançois Tigeot 		goto err;
679e3adcf8fSFrançois Tigeot 	}
680e3adcf8fSFrançois Tigeot 
6818621f407SFrançois Tigeot 	ret = i915_gem_object_set_cache_level(engine->scratch.obj,
6828621f407SFrançois Tigeot 					      I915_CACHE_LLC);
683ba55f2f5SFrançois Tigeot 	if (ret)
684ba55f2f5SFrançois Tigeot 		goto err_unref;
685e3adcf8fSFrançois Tigeot 
6868621f407SFrançois Tigeot 	ret = i915_gem_obj_ggtt_pin(engine->scratch.obj, 4096, 0);
687e3adcf8fSFrançois Tigeot 	if (ret)
688e3adcf8fSFrançois Tigeot 		goto err_unref;
689e3adcf8fSFrançois Tigeot 
6908621f407SFrançois Tigeot 	engine->scratch.gtt_offset = i915_gem_obj_ggtt_offset(engine->scratch.obj);
6918621f407SFrançois Tigeot 	engine->scratch.cpu_page = kmap(sg_page(engine->scratch.obj->pages->sgl));
6928621f407SFrançois Tigeot 	if (engine->scratch.cpu_page == NULL) {
6935d0b1887SFrançois Tigeot 		ret = -ENOMEM;
694e3adcf8fSFrançois Tigeot 		goto err_unpin;
6955d0b1887SFrançois Tigeot 	}
696a2fdbec6SFrançois Tigeot 
697a2fdbec6SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
6988621f407SFrançois Tigeot 			 engine->name, engine->scratch.gtt_offset);
699e3adcf8fSFrançois Tigeot 	return 0;
700e3adcf8fSFrançois Tigeot 
701e3adcf8fSFrançois Tigeot err_unpin:
7028621f407SFrançois Tigeot 	i915_gem_object_ggtt_unpin(engine->scratch.obj);
703e3adcf8fSFrançois Tigeot err_unref:
7048621f407SFrançois Tigeot 	drm_gem_object_unreference(&engine->scratch.obj->base);
705e3adcf8fSFrançois Tigeot err:
706e3adcf8fSFrançois Tigeot 	return ret;
707e3adcf8fSFrançois Tigeot }
708e3adcf8fSFrançois Tigeot 
709a05eeebfSFrançois Tigeot static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
7101b13d190SFrançois Tigeot {
7118621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
712*1487f786SFrançois Tigeot 	struct i915_workarounds *w = &req->i915->workarounds;
713*1487f786SFrançois Tigeot 	int ret, i;
7141b13d190SFrançois Tigeot 
715352ff8bdSFrançois Tigeot 	if (w->count == 0)
7162c9916cdSFrançois Tigeot 		return 0;
7171b13d190SFrançois Tigeot 
7188621f407SFrançois Tigeot 	engine->gpu_caches_dirty = true;
719a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7201b13d190SFrançois Tigeot 	if (ret)
7211b13d190SFrançois Tigeot 		return ret;
7221b13d190SFrançois Tigeot 
723a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, (w->count * 2 + 2));
7242c9916cdSFrançois Tigeot 	if (ret)
7252c9916cdSFrançois Tigeot 		return ret;
7262c9916cdSFrançois Tigeot 
7278621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(w->count));
7282c9916cdSFrançois Tigeot 	for (i = 0; i < w->count; i++) {
7298621f407SFrançois Tigeot 		intel_ring_emit_reg(engine, w->reg[i].addr);
7308621f407SFrançois Tigeot 		intel_ring_emit(engine, w->reg[i].value);
7312c9916cdSFrançois Tigeot 	}
7328621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
7332c9916cdSFrançois Tigeot 
7348621f407SFrançois Tigeot 	intel_ring_advance(engine);
7352c9916cdSFrançois Tigeot 
7368621f407SFrançois Tigeot 	engine->gpu_caches_dirty = true;
737a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7382c9916cdSFrançois Tigeot 	if (ret)
7392c9916cdSFrançois Tigeot 		return ret;
7402c9916cdSFrançois Tigeot 
7412c9916cdSFrançois Tigeot 	DRM_DEBUG_DRIVER("Number of Workarounds emitted: %d\n", w->count);
7422c9916cdSFrançois Tigeot 
7432c9916cdSFrançois Tigeot 	return 0;
7442c9916cdSFrançois Tigeot }
7452c9916cdSFrançois Tigeot 
746a05eeebfSFrançois Tigeot static int intel_rcs_ctx_init(struct drm_i915_gem_request *req)
7472c9916cdSFrançois Tigeot {
7482c9916cdSFrançois Tigeot 	int ret;
7492c9916cdSFrançois Tigeot 
750a05eeebfSFrançois Tigeot 	ret = intel_ring_workarounds_emit(req);
7512c9916cdSFrançois Tigeot 	if (ret != 0)
7522c9916cdSFrançois Tigeot 		return ret;
7532c9916cdSFrançois Tigeot 
754a05eeebfSFrançois Tigeot 	ret = i915_gem_render_state_init(req);
7552c9916cdSFrançois Tigeot 	if (ret)
7562c9916cdSFrançois Tigeot 		return ret;
757c0e85e96SFrançois Tigeot 
758c0e85e96SFrançois Tigeot 	return 0;
7592c9916cdSFrançois Tigeot }
7602c9916cdSFrançois Tigeot 
7612c9916cdSFrançois Tigeot static int wa_add(struct drm_i915_private *dev_priv,
762aee94f86SFrançois Tigeot 		  i915_reg_t addr,
763aee94f86SFrançois Tigeot 		  const u32 mask, const u32 val)
7642c9916cdSFrançois Tigeot {
7652c9916cdSFrançois Tigeot 	const u32 idx = dev_priv->workarounds.count;
7662c9916cdSFrançois Tigeot 
7672c9916cdSFrançois Tigeot 	if (WARN_ON(idx >= I915_MAX_WA_REGS))
7682c9916cdSFrançois Tigeot 		return -ENOSPC;
7692c9916cdSFrançois Tigeot 
7702c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].addr = addr;
7712c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].value = val;
7722c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].mask = mask;
7732c9916cdSFrançois Tigeot 
7742c9916cdSFrançois Tigeot 	dev_priv->workarounds.count++;
7752c9916cdSFrançois Tigeot 
7762c9916cdSFrançois Tigeot 	return 0;
7772c9916cdSFrançois Tigeot }
7782c9916cdSFrançois Tigeot 
779a05eeebfSFrançois Tigeot #define WA_REG(addr, mask, val) do { \
7802c9916cdSFrançois Tigeot 		const int r = wa_add(dev_priv, (addr), (mask), (val)); \
7812c9916cdSFrançois Tigeot 		if (r) \
7822c9916cdSFrançois Tigeot 			return r; \
783a05eeebfSFrançois Tigeot 	} while (0)
7842c9916cdSFrançois Tigeot 
7852c9916cdSFrançois Tigeot #define WA_SET_BIT_MASKED(addr, mask) \
7862c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask))
7872c9916cdSFrançois Tigeot 
7882c9916cdSFrançois Tigeot #define WA_CLR_BIT_MASKED(addr, mask) \
7892c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_DISABLE(mask))
7902c9916cdSFrançois Tigeot 
7912c9916cdSFrançois Tigeot #define WA_SET_FIELD_MASKED(addr, mask, value) \
7922c9916cdSFrançois Tigeot 	WA_REG(addr, mask, _MASKED_FIELD(mask, value))
7932c9916cdSFrançois Tigeot 
7942c9916cdSFrançois Tigeot #define WA_SET_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) | (mask))
7952c9916cdSFrançois Tigeot #define WA_CLR_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) & ~(mask))
7962c9916cdSFrançois Tigeot 
7972c9916cdSFrançois Tigeot #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
7982c9916cdSFrançois Tigeot 
7998621f407SFrançois Tigeot static int wa_ring_whitelist_reg(struct intel_engine_cs *engine,
8008621f407SFrançois Tigeot 				 i915_reg_t reg)
801c0e85e96SFrançois Tigeot {
802*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
803c0e85e96SFrançois Tigeot 	struct i915_workarounds *wa = &dev_priv->workarounds;
8048621f407SFrançois Tigeot 	const uint32_t index = wa->hw_whitelist_count[engine->id];
805c0e85e96SFrançois Tigeot 
806c0e85e96SFrançois Tigeot 	if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS))
807c0e85e96SFrançois Tigeot 		return -EINVAL;
808c0e85e96SFrançois Tigeot 
8098621f407SFrançois Tigeot 	WA_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index),
810c0e85e96SFrançois Tigeot 		 i915_mmio_reg_offset(reg));
8118621f407SFrançois Tigeot 	wa->hw_whitelist_count[engine->id]++;
812c0e85e96SFrançois Tigeot 
813c0e85e96SFrançois Tigeot 	return 0;
814c0e85e96SFrançois Tigeot }
815c0e85e96SFrançois Tigeot 
8168621f407SFrançois Tigeot static int gen8_init_workarounds(struct intel_engine_cs *engine)
8172c9916cdSFrançois Tigeot {
818*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
8192c9916cdSFrançois Tigeot 
820a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
821a05eeebfSFrançois Tigeot 
822352ff8bdSFrançois Tigeot 	/* WaDisableAsyncFlipPerfMode:bdw,chv */
823a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE);
824a05eeebfSFrançois Tigeot 
825352ff8bdSFrançois Tigeot 	/* WaDisablePartialInstShootdown:bdw,chv */
8262c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
827352ff8bdSFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
8281b13d190SFrançois Tigeot 
8291b13d190SFrançois Tigeot 	/* Use Force Non-Coherent whenever executing a 3D context. This is a
8301b13d190SFrançois Tigeot 	 * workaround for for a possible hang in the unlikely event a TLB
8311b13d190SFrançois Tigeot 	 * invalidation occurs during a PSD flush.
8321b13d190SFrançois Tigeot 	 */
833352ff8bdSFrançois Tigeot 	/* WaForceEnableNonCoherent:bdw,chv */
834352ff8bdSFrançois Tigeot 	/* WaHdcDisableFetchWhenMasked:bdw,chv */
8352c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
8362c9916cdSFrançois Tigeot 			  HDC_DONOT_FETCH_MEM_WHEN_MASKED |
837352ff8bdSFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
8382c9916cdSFrançois Tigeot 
8392c9916cdSFrançois Tigeot 	/* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
8402c9916cdSFrançois Tigeot 	 * "The Hierarchical Z RAW Stall Optimization allows non-overlapping
8412c9916cdSFrançois Tigeot 	 *  polygons in the same 8x4 pixel/sample area to be processed without
8422c9916cdSFrançois Tigeot 	 *  stalling waiting for the earlier ones to write to Hierarchical Z
8432c9916cdSFrançois Tigeot 	 *  buffer."
8442c9916cdSFrançois Tigeot 	 *
845352ff8bdSFrançois Tigeot 	 * This optimization is off by default for BDW and CHV; turn it on.
8462c9916cdSFrançois Tigeot 	 */
8472c9916cdSFrançois Tigeot 	WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
8481b13d190SFrançois Tigeot 
849352ff8bdSFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:bdw,chv */
850352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
8511b13d190SFrançois Tigeot 
8521b13d190SFrançois Tigeot 	/*
8531b13d190SFrançois Tigeot 	 * BSpec recommends 8x4 when MSAA is used,
8541b13d190SFrançois Tigeot 	 * however in practice 16x4 seems fastest.
8551b13d190SFrançois Tigeot 	 *
8561b13d190SFrançois Tigeot 	 * Note that PS/WM thread counts depend on the WIZ hashing
8571b13d190SFrançois Tigeot 	 * disable bit, which we don't touch here, but it's good
8581b13d190SFrançois Tigeot 	 * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
8591b13d190SFrançois Tigeot 	 */
8602c9916cdSFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
8612c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_MASK,
8622c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_16x4);
8631b13d190SFrançois Tigeot 
8641b13d190SFrançois Tigeot 	return 0;
8651b13d190SFrançois Tigeot }
8661b13d190SFrançois Tigeot 
8678621f407SFrançois Tigeot static int bdw_init_workarounds(struct intel_engine_cs *engine)
8681b13d190SFrançois Tigeot {
869*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
870352ff8bdSFrançois Tigeot 	int ret;
8711b13d190SFrançois Tigeot 
8728621f407SFrançois Tigeot 	ret = gen8_init_workarounds(engine);
873352ff8bdSFrançois Tigeot 	if (ret)
874352ff8bdSFrançois Tigeot 		return ret;
875a05eeebfSFrançois Tigeot 
876352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bdw (pre-production) */
877352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
878a05eeebfSFrançois Tigeot 
879352ff8bdSFrançois Tigeot 	/* WaDisableDopClockGating:bdw */
880352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
881352ff8bdSFrançois Tigeot 			  DOP_CLOCK_GATING_DISABLE);
8821b13d190SFrançois Tigeot 
883352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
884352ff8bdSFrançois Tigeot 			  GEN8_SAMPLER_POWER_BYPASS_DIS);
885352ff8bdSFrançois Tigeot 
8862c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
887352ff8bdSFrançois Tigeot 			  /* WaForceContextSaveRestoreNonCoherent:bdw */
888352ff8bdSFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
889352ff8bdSFrançois Tigeot 			  /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
890*1487f786SFrançois Tigeot 			  (IS_BDW_GT3(dev_priv) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
8911b13d190SFrançois Tigeot 
892352ff8bdSFrançois Tigeot 	return 0;
893352ff8bdSFrançois Tigeot }
8941b13d190SFrançois Tigeot 
8958621f407SFrançois Tigeot static int chv_init_workarounds(struct intel_engine_cs *engine)
896352ff8bdSFrançois Tigeot {
897*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
898352ff8bdSFrançois Tigeot 	int ret;
899352ff8bdSFrançois Tigeot 
9008621f407SFrançois Tigeot 	ret = gen8_init_workarounds(engine);
901352ff8bdSFrançois Tigeot 	if (ret)
902352ff8bdSFrançois Tigeot 		return ret;
903352ff8bdSFrançois Tigeot 
904352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:chv */
905352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
9062c9916cdSFrançois Tigeot 
9072c9916cdSFrançois Tigeot 	/* Improve HiZ throughput on CHV. */
9082c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
9092c9916cdSFrançois Tigeot 
9102c9916cdSFrançois Tigeot 	return 0;
9112c9916cdSFrançois Tigeot }
9122c9916cdSFrançois Tigeot 
9138621f407SFrançois Tigeot static int gen9_init_workarounds(struct intel_engine_cs *engine)
914477eb7f9SFrançois Tigeot {
915*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
916c0e85e96SFrançois Tigeot 	int ret;
917477eb7f9SFrançois Tigeot 
9188621f407SFrançois Tigeot 	/* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl */
9198621f407SFrançois Tigeot 	I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE));
9208621f407SFrançois Tigeot 
9218621f407SFrançois Tigeot 	/* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl */
922352ff8bdSFrançois Tigeot 	I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
923352ff8bdSFrançois Tigeot 		   GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
924352ff8bdSFrançois Tigeot 
9258621f407SFrançois Tigeot 	/* WaDisableKillLogic:bxt,skl,kbl */
926352ff8bdSFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
927352ff8bdSFrançois Tigeot 		   ECOCHK_DIS_TLB);
928352ff8bdSFrançois Tigeot 
9298621f407SFrançois Tigeot 	/* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl */
9308621f407SFrançois Tigeot 	/* WaDisablePartialInstShootdown:skl,bxt,kbl */
931477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
9328621f407SFrançois Tigeot 			  FLOW_CONTROL_ENABLE |
933477eb7f9SFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
934477eb7f9SFrançois Tigeot 
9358621f407SFrançois Tigeot 	/* Syncing dependencies between camera and graphics:skl,bxt,kbl */
936477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
937477eb7f9SFrançois Tigeot 			  GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
938477eb7f9SFrançois Tigeot 
93919c468b4SFrançois Tigeot 	/* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
940*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
941*1487f786SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
942477eb7f9SFrançois Tigeot 		WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
943477eb7f9SFrançois Tigeot 				  GEN9_DG_MIRROR_FIX_ENABLE);
944477eb7f9SFrançois Tigeot 
94519c468b4SFrançois Tigeot 	/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
946*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
947*1487f786SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
948477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
949477eb7f9SFrançois Tigeot 				  GEN9_RHWO_OPTIMIZATION_DISABLE);
950a05eeebfSFrançois Tigeot 		/*
951a05eeebfSFrançois Tigeot 		 * WA also requires GEN9_SLICE_COMMON_ECO_CHICKEN0[14:14] to be set
952a05eeebfSFrançois Tigeot 		 * but we do that in per ctx batchbuffer as there is an issue
953a05eeebfSFrançois Tigeot 		 * with this register not getting restored on ctx restore
954a05eeebfSFrançois Tigeot 		 */
955477eb7f9SFrançois Tigeot 	}
956477eb7f9SFrançois Tigeot 
9578621f407SFrançois Tigeot 	/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl */
9588621f407SFrançois Tigeot 	/* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl */
959477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
9608621f407SFrançois Tigeot 			  GEN9_ENABLE_YV12_BUGFIX |
9618621f407SFrançois Tigeot 			  GEN9_ENABLE_GPGPU_PREEMPTION);
962477eb7f9SFrançois Tigeot 
9638621f407SFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:skl,bxt,kbl */
9648621f407SFrançois Tigeot 	/* WaDisablePartialResolveInVc:skl,bxt,kbl */
965352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE |
966352ff8bdSFrançois Tigeot 					 GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE));
967477eb7f9SFrançois Tigeot 
9688621f407SFrançois Tigeot 	/* WaCcsTlbPrefetchDisable:skl,bxt,kbl */
969477eb7f9SFrançois Tigeot 	WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
970477eb7f9SFrançois Tigeot 			  GEN9_CCS_TLB_PREFETCH_ENABLE);
971477eb7f9SFrançois Tigeot 
97219c468b4SFrançois Tigeot 	/* WaDisableMaskBasedCammingInRCC:skl,bxt */
973*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_C0) ||
974*1487f786SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
97519c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
97619c468b4SFrançois Tigeot 				  PIXEL_MASK_CAMMING_DISABLE);
97719c468b4SFrançois Tigeot 
9788621f407SFrançois Tigeot 	/* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl */
9798621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
9808621f407SFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
9818621f407SFrançois Tigeot 			  HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE);
98219c468b4SFrançois Tigeot 
9838621f407SFrançois Tigeot 	/* WaForceEnableNonCoherent and WaDisableHDCInvalidation are
9848621f407SFrançois Tigeot 	 * both tied to WaForceContextSaveRestoreNonCoherent
9858621f407SFrançois Tigeot 	 * in some hsds for skl. We keep the tie for all gen9. The
9868621f407SFrançois Tigeot 	 * documentation is a bit hazy and so we want to get common behaviour,
9878621f407SFrançois Tigeot 	 * even though there is no clear evidence we would need both on kbl/bxt.
9888621f407SFrançois Tigeot 	 * This area has been source of system hangs so we play it safe
9898621f407SFrançois Tigeot 	 * and mimic the skl regardless of what bspec says.
9908621f407SFrançois Tigeot 	 *
9918621f407SFrançois Tigeot 	 * Use Force Non-Coherent whenever executing a 3D context. This
9928621f407SFrançois Tigeot 	 * is a workaround for a possible hang in the unlikely event
9938621f407SFrançois Tigeot 	 * a TLB invalidation occurs during a PSD flush.
9948621f407SFrançois Tigeot 	 */
9958621f407SFrançois Tigeot 
9968621f407SFrançois Tigeot 	/* WaForceEnableNonCoherent:skl,bxt,kbl */
9978621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
9988621f407SFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
9998621f407SFrançois Tigeot 
10008621f407SFrançois Tigeot 	/* WaDisableHDCInvalidation:skl,bxt,kbl */
10018621f407SFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
10028621f407SFrançois Tigeot 		   BDW_DISABLE_HDC_INVALIDATION);
10038621f407SFrançois Tigeot 
10048621f407SFrançois Tigeot 	/* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl */
10058621f407SFrançois Tigeot 	if (IS_SKYLAKE(dev_priv) ||
10068621f407SFrançois Tigeot 	    IS_KABYLAKE(dev_priv) ||
10078621f407SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
1008352ff8bdSFrançois Tigeot 		WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
1009352ff8bdSFrançois Tigeot 				  GEN8_SAMPLER_POWER_BYPASS_DIS);
1010352ff8bdSFrançois Tigeot 
10118621f407SFrançois Tigeot 	/* WaDisableSTUnitPowerOptimization:skl,bxt,kbl */
1012352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
1013352ff8bdSFrançois Tigeot 
10148621f407SFrançois Tigeot 	/* WaOCLCoherentLineFlush:skl,bxt,kbl */
1015c0e85e96SFrançois Tigeot 	I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) |
1016c0e85e96SFrançois Tigeot 				    GEN8_LQSC_FLUSH_COHERENT_LINES));
1017c0e85e96SFrançois Tigeot 
10188621f407SFrançois Tigeot 	/* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt */
10198621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG);
1020c0e85e96SFrançois Tigeot 	if (ret)
1021c0e85e96SFrançois Tigeot 		return ret;
1022c0e85e96SFrançois Tigeot 
10238621f407SFrançois Tigeot 	/* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl */
10248621f407SFrançois Tigeot 	ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1);
10258621f407SFrançois Tigeot 	if (ret)
10268621f407SFrançois Tigeot 		return ret;
10278621f407SFrançois Tigeot 
10288621f407SFrançois Tigeot 	/* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl */
10298621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1);
1030c0e85e96SFrançois Tigeot 	if (ret)
1031c0e85e96SFrançois Tigeot 		return ret;
1032c0e85e96SFrançois Tigeot 
1033477eb7f9SFrançois Tigeot 	return 0;
1034477eb7f9SFrançois Tigeot }
1035477eb7f9SFrançois Tigeot 
10368621f407SFrançois Tigeot static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
1037477eb7f9SFrançois Tigeot {
1038*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1039477eb7f9SFrançois Tigeot 	u8 vals[3] = { 0, 0, 0 };
1040477eb7f9SFrançois Tigeot 	unsigned int i;
1041477eb7f9SFrançois Tigeot 
1042477eb7f9SFrançois Tigeot 	for (i = 0; i < 3; i++) {
1043477eb7f9SFrançois Tigeot 		u8 ss;
1044477eb7f9SFrançois Tigeot 
1045477eb7f9SFrançois Tigeot 		/*
1046477eb7f9SFrançois Tigeot 		 * Only consider slices where one, and only one, subslice has 7
1047477eb7f9SFrançois Tigeot 		 * EUs
1048477eb7f9SFrançois Tigeot 		 */
1049aee94f86SFrançois Tigeot 		if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
1050477eb7f9SFrançois Tigeot 			continue;
1051477eb7f9SFrançois Tigeot 
1052477eb7f9SFrançois Tigeot 		/*
1053477eb7f9SFrançois Tigeot 		 * subslice_7eu[i] != 0 (because of the check above) and
1054477eb7f9SFrançois Tigeot 		 * ss_max == 4 (maximum number of subslices possible per slice)
1055477eb7f9SFrançois Tigeot 		 *
1056477eb7f9SFrançois Tigeot 		 * ->    0 <= ss <= 3;
1057477eb7f9SFrançois Tigeot 		 */
1058477eb7f9SFrançois Tigeot 		ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
1059477eb7f9SFrançois Tigeot 		vals[i] = 3 - ss;
1060477eb7f9SFrançois Tigeot 	}
1061477eb7f9SFrançois Tigeot 
1062477eb7f9SFrançois Tigeot 	if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0)
1063477eb7f9SFrançois Tigeot 		return 0;
1064477eb7f9SFrançois Tigeot 
1065477eb7f9SFrançois Tigeot 	/* Tune IZ hashing. See intel_device_info_runtime_init() */
1066477eb7f9SFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
1067477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(2) |
1068477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(1) |
1069477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(0),
1070477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(2, vals[2]) |
1071477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(1, vals[1]) |
1072477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(0, vals[0]));
1073477eb7f9SFrançois Tigeot 
1074477eb7f9SFrançois Tigeot 	return 0;
1075477eb7f9SFrançois Tigeot }
1076477eb7f9SFrançois Tigeot 
10778621f407SFrançois Tigeot static int skl_init_workarounds(struct intel_engine_cs *engine)
1078477eb7f9SFrançois Tigeot {
1079*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1080352ff8bdSFrançois Tigeot 	int ret;
1081477eb7f9SFrançois Tigeot 
10828621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
1083352ff8bdSFrançois Tigeot 	if (ret)
1084352ff8bdSFrançois Tigeot 		return ret;
1085352ff8bdSFrançois Tigeot 
1086c0e85e96SFrançois Tigeot 	/*
1087c0e85e96SFrançois Tigeot 	 * Actual WA is to disable percontext preemption granularity control
1088c0e85e96SFrançois Tigeot 	 * until D0 which is the default case so this is equivalent to
1089c0e85e96SFrançois Tigeot 	 * !WaDisablePerCtxtPreemptionGranularityControl:skl
1090c0e85e96SFrançois Tigeot 	 */
1091*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_E0, REVID_FOREVER)) {
1092c0e85e96SFrançois Tigeot 		I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
1093c0e85e96SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
1094c0e85e96SFrançois Tigeot 	}
1095c0e85e96SFrançois Tigeot 
1096*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) {
1097352ff8bdSFrançois Tigeot 		/* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
1098352ff8bdSFrançois Tigeot 		I915_WRITE(FF_SLICE_CS_CHICKEN2,
1099352ff8bdSFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
1100352ff8bdSFrançois Tigeot 	}
1101352ff8bdSFrançois Tigeot 
1102352ff8bdSFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
1103352ff8bdSFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
1104352ff8bdSFrançois Tigeot 	 */
1105*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0))
1106352ff8bdSFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:skl */
1107352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
1108352ff8bdSFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
1109352ff8bdSFrançois Tigeot 
1110352ff8bdSFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:skl */
1111*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, REVID_FOREVER)) {
1112352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
1113352ff8bdSFrançois Tigeot 					   GEN9_GAPS_TSV_CREDIT_DISABLE));
1114352ff8bdSFrançois Tigeot 	}
1115477eb7f9SFrançois Tigeot 
1116477eb7f9SFrançois Tigeot 	/* WaDisablePowerCompilerClockGating:skl */
1117*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_B0, SKL_REVID_B0))
1118477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(HIZ_CHICKEN,
1119477eb7f9SFrançois Tigeot 				  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
1120477eb7f9SFrançois Tigeot 
1121a05eeebfSFrançois Tigeot 	/* WaBarrierPerformanceFixDisable:skl */
1122*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_D0))
1123a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
1124a05eeebfSFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE |
1125a05eeebfSFrançois Tigeot 				  HDC_BARRIER_PERFORMANCE_DISABLE);
1126a05eeebfSFrançois Tigeot 
1127a05eeebfSFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:skl */
1128*1487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0))
1129a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(
1130a05eeebfSFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
1131a05eeebfSFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
1132a05eeebfSFrançois Tigeot 
11338621f407SFrançois Tigeot 	/* WaDisableGafsUnitClkGating:skl */
11348621f407SFrançois Tigeot 	WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
11358621f407SFrançois Tigeot 
1136c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:skl */
11378621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
1138c0e85e96SFrançois Tigeot 	if (ret)
1139c0e85e96SFrançois Tigeot 		return ret;
1140c0e85e96SFrançois Tigeot 
11418621f407SFrançois Tigeot 	return skl_tune_iz_hashing(engine);
1142477eb7f9SFrançois Tigeot }
1143477eb7f9SFrançois Tigeot 
11448621f407SFrançois Tigeot static int bxt_init_workarounds(struct intel_engine_cs *engine)
114519c468b4SFrançois Tigeot {
1146*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1147352ff8bdSFrançois Tigeot 	int ret;
114819c468b4SFrançois Tigeot 
11498621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
1150352ff8bdSFrançois Tigeot 	if (ret)
1151352ff8bdSFrançois Tigeot 		return ret;
1152352ff8bdSFrançois Tigeot 
1153352ff8bdSFrançois Tigeot 	/* WaStoreMultiplePTEenable:bxt */
1154352ff8bdSFrançois Tigeot 	/* This is a requirement according to Hardware specification */
1155*1487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
1156352ff8bdSFrançois Tigeot 		I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
1157352ff8bdSFrançois Tigeot 
1158352ff8bdSFrançois Tigeot 	/* WaSetClckGatingDisableMedia:bxt */
1159*1487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
1160352ff8bdSFrançois Tigeot 		I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
1161352ff8bdSFrançois Tigeot 					    ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
1162352ff8bdSFrançois Tigeot 	}
116319c468b4SFrançois Tigeot 
116419c468b4SFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bxt */
116519c468b4SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
116619c468b4SFrançois Tigeot 			  STALL_DOP_GATING_DISABLE);
116719c468b4SFrançois Tigeot 
1168*1487f786SFrançois Tigeot 	/* WaDisablePooledEuLoadBalancingFix:bxt */
1169*1487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER)) {
1170*1487f786SFrançois Tigeot 		WA_SET_BIT_MASKED(FF_SLICE_CS_CHICKEN2,
1171*1487f786SFrançois Tigeot 				  GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE);
1172*1487f786SFrançois Tigeot 	}
1173*1487f786SFrançois Tigeot 
117419c468b4SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:bxt */
1175*1487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0)) {
117619c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(
117719c468b4SFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
117819c468b4SFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
117919c468b4SFrançois Tigeot 	}
118019c468b4SFrançois Tigeot 
1181c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt */
1182c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForInstancedDraw:bxt */
1183c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemtionForInstanceId:bxt */
1184c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:bxt */
1185*1487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
11868621f407SFrançois Tigeot 		ret = wa_ring_whitelist_reg(engine, GEN9_CS_DEBUG_MODE1);
1187c0e85e96SFrançois Tigeot 		if (ret)
1188c0e85e96SFrançois Tigeot 			return ret;
1189c0e85e96SFrançois Tigeot 
11908621f407SFrançois Tigeot 		ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
1191c0e85e96SFrançois Tigeot 		if (ret)
1192c0e85e96SFrançois Tigeot 			return ret;
1193c0e85e96SFrançois Tigeot 	}
1194c0e85e96SFrançois Tigeot 
1195*1487f786SFrançois Tigeot 	/* WaProgramL3SqcReg1DefaultForPerf:bxt */
1196*1487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER))
1197*1487f786SFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG1, L3_GENERAL_PRIO_CREDITS(62) |
1198*1487f786SFrançois Tigeot 					   L3_HIGH_PRIO_CREDITS(2));
1199*1487f786SFrançois Tigeot 
12008621f407SFrançois Tigeot 	/* WaInsertDummyPushConstPs:bxt */
12018621f407SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
12028621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
12038621f407SFrançois Tigeot 				  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
12048621f407SFrançois Tigeot 
120519c468b4SFrançois Tigeot 	return 0;
120619c468b4SFrançois Tigeot }
120719c468b4SFrançois Tigeot 
12088621f407SFrançois Tigeot static int kbl_init_workarounds(struct intel_engine_cs *engine)
12092c9916cdSFrançois Tigeot {
1210*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
12118621f407SFrançois Tigeot 	int ret;
12128621f407SFrançois Tigeot 
12138621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
12148621f407SFrançois Tigeot 	if (ret)
12158621f407SFrançois Tigeot 		return ret;
12168621f407SFrançois Tigeot 
12178621f407SFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:kbl */
12188621f407SFrançois Tigeot 	I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
12198621f407SFrançois Tigeot 				   GEN9_GAPS_TSV_CREDIT_DISABLE));
12208621f407SFrançois Tigeot 
12218621f407SFrançois Tigeot 	/* WaDisableDynamicCreditSharing:kbl */
12228621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
12238621f407SFrançois Tigeot 		WA_SET_BIT(GAMT_CHKN_BIT_REG,
12248621f407SFrançois Tigeot 			   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING);
12258621f407SFrançois Tigeot 
12268621f407SFrançois Tigeot 	/* WaDisableFenceDestinationToSLM:kbl (pre-prod) */
12278621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0))
12288621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
12298621f407SFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE);
12308621f407SFrançois Tigeot 
12318621f407SFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
12328621f407SFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
12338621f407SFrançois Tigeot 	 */
12348621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
12358621f407SFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:kbl */
12368621f407SFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
12378621f407SFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
12388621f407SFrançois Tigeot 
12398621f407SFrançois Tigeot 	/* WaInsertDummyPushConstPs:kbl */
12408621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
12418621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
12428621f407SFrançois Tigeot 				  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
12438621f407SFrançois Tigeot 
12448621f407SFrançois Tigeot 	/* WaDisableGafsUnitClkGating:kbl */
12458621f407SFrançois Tigeot 	WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
12468621f407SFrançois Tigeot 
12478621f407SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:kbl */
12488621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(
12498621f407SFrançois Tigeot 		GEN7_HALF_SLICE_CHICKEN1,
12508621f407SFrançois Tigeot 		GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
12518621f407SFrançois Tigeot 
12528621f407SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:kbl */
12538621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
12548621f407SFrançois Tigeot 	if (ret)
12558621f407SFrançois Tigeot 		return ret;
12568621f407SFrançois Tigeot 
12578621f407SFrançois Tigeot 	return 0;
12588621f407SFrançois Tigeot }
12598621f407SFrançois Tigeot 
12608621f407SFrançois Tigeot int init_workarounds_ring(struct intel_engine_cs *engine)
12618621f407SFrançois Tigeot {
1262*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
12632c9916cdSFrançois Tigeot 
12648621f407SFrançois Tigeot 	WARN_ON(engine->id != RCS);
12652c9916cdSFrançois Tigeot 
12662c9916cdSFrançois Tigeot 	dev_priv->workarounds.count = 0;
1267c0e85e96SFrançois Tigeot 	dev_priv->workarounds.hw_whitelist_count[RCS] = 0;
12682c9916cdSFrançois Tigeot 
1269*1487f786SFrançois Tigeot 	if (IS_BROADWELL(dev_priv))
12708621f407SFrançois Tigeot 		return bdw_init_workarounds(engine);
12712c9916cdSFrançois Tigeot 
1272*1487f786SFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv))
12738621f407SFrançois Tigeot 		return chv_init_workarounds(engine);
12741b13d190SFrançois Tigeot 
1275*1487f786SFrançois Tigeot 	if (IS_SKYLAKE(dev_priv))
12768621f407SFrançois Tigeot 		return skl_init_workarounds(engine);
127719c468b4SFrançois Tigeot 
1278*1487f786SFrançois Tigeot 	if (IS_BROXTON(dev_priv))
12798621f407SFrançois Tigeot 		return bxt_init_workarounds(engine);
12808621f407SFrançois Tigeot 
12818621f407SFrançois Tigeot 	if (IS_KABYLAKE(dev_priv))
12828621f407SFrançois Tigeot 		return kbl_init_workarounds(engine);
1283477eb7f9SFrançois Tigeot 
12841b13d190SFrançois Tigeot 	return 0;
12851b13d190SFrançois Tigeot }
12861b13d190SFrançois Tigeot 
12878621f407SFrançois Tigeot static int init_render_ring(struct intel_engine_cs *engine)
1288e3adcf8fSFrançois Tigeot {
1289*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
12908621f407SFrançois Tigeot 	int ret = init_ring_common(engine);
129124edb884SFrançois Tigeot 	if (ret)
129224edb884SFrançois Tigeot 		return ret;
1293e3adcf8fSFrançois Tigeot 
1294ba55f2f5SFrançois Tigeot 	/* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */
1295*1487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 4, 6))
1296f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
1297f4e1c372SFrançois Tigeot 
1298f4e1c372SFrançois Tigeot 	/* We need to disable the AsyncFlip performance optimisations in order
1299f4e1c372SFrançois Tigeot 	 * to use MI_WAIT_FOR_EVENT within the CS. It should already be
1300f4e1c372SFrançois Tigeot 	 * programmed to '1' on all products.
13015d0b1887SFrançois Tigeot 	 *
1302a05eeebfSFrançois Tigeot 	 * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
1303f4e1c372SFrançois Tigeot 	 */
1304*1487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 6, 7))
1305f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
1306f4e1c372SFrançois Tigeot 
1307f4e1c372SFrançois Tigeot 	/* Required for the hardware to program scanline values for waiting */
1308ba55f2f5SFrançois Tigeot 	/* WaEnableFlushTlbInvalidationMode:snb */
1309*1487f786SFrançois Tigeot 	if (IS_GEN6(dev_priv))
1310f4e1c372SFrançois Tigeot 		I915_WRITE(GFX_MODE,
1311ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT));
1312f4e1c372SFrançois Tigeot 
1313ba55f2f5SFrançois Tigeot 	/* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */
1314*1487f786SFrançois Tigeot 	if (IS_GEN7(dev_priv))
1315e3adcf8fSFrançois Tigeot 		I915_WRITE(GFX_MODE_GEN7,
1316ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
1317f4e1c372SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
1318e3adcf8fSFrançois Tigeot 
1319*1487f786SFrançois Tigeot 	if (IS_GEN6(dev_priv)) {
1320e3adcf8fSFrançois Tigeot 		/* From the Sandybridge PRM, volume 1 part 3, page 24:
1321e3adcf8fSFrançois Tigeot 		 * "If this bit is set, STCunit will have LRA as replacement
1322e3adcf8fSFrançois Tigeot 		 *  policy. [...] This bit must be reset.  LRA replacement
1323e3adcf8fSFrançois Tigeot 		 *  policy is not supported."
1324e3adcf8fSFrançois Tigeot 		 */
1325e3adcf8fSFrançois Tigeot 		I915_WRITE(CACHE_MODE_0,
1326f4e1c372SFrançois Tigeot 			   _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
1327e3adcf8fSFrançois Tigeot 	}
1328e3adcf8fSFrançois Tigeot 
1329*1487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 6, 7))
1330f4e1c372SFrançois Tigeot 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
1331f4e1c372SFrançois Tigeot 
1332*1487f786SFrançois Tigeot 	if (HAS_L3_DPF(dev_priv))
1333*1487f786SFrançois Tigeot 		I915_WRITE_IMR(engine, ~GT_PARITY_ERROR(dev_priv));
1334e3adcf8fSFrançois Tigeot 
13358621f407SFrançois Tigeot 	return init_workarounds_ring(engine);
1336e3adcf8fSFrançois Tigeot }
1337e3adcf8fSFrançois Tigeot 
13388621f407SFrançois Tigeot static void render_ring_cleanup(struct intel_engine_cs *engine)
1339e3adcf8fSFrançois Tigeot {
1340*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
134124edb884SFrançois Tigeot 
134224edb884SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
134324edb884SFrançois Tigeot 		i915_gem_object_ggtt_unpin(dev_priv->semaphore_obj);
134424edb884SFrançois Tigeot 		drm_gem_object_unreference(&dev_priv->semaphore_obj->base);
134524edb884SFrançois Tigeot 		dev_priv->semaphore_obj = NULL;
134624edb884SFrançois Tigeot 	}
1347b5c29a34SFrançois Tigeot 
13488621f407SFrançois Tigeot 	intel_fini_pipe_control(engine);
1349e3adcf8fSFrançois Tigeot }
1350e3adcf8fSFrançois Tigeot 
1351a05eeebfSFrançois Tigeot static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req,
135224edb884SFrançois Tigeot 			   unsigned int num_dwords)
135324edb884SFrançois Tigeot {
135424edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 8
13558621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
1356*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = signaller_req->i915;
135724edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
13588621f407SFrançois Tigeot 	enum intel_engine_id id;
13598621f407SFrançois Tigeot 	int ret, num_rings;
136024edb884SFrançois Tigeot 
1361*1487f786SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
136224edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
136324edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
136424edb884SFrançois Tigeot 
1365a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
136624edb884SFrançois Tigeot 	if (ret)
136724edb884SFrançois Tigeot 		return ret;
136824edb884SFrançois Tigeot 
13698621f407SFrançois Tigeot 	for_each_engine_id(waiter, dev_priv, id) {
13702c9916cdSFrançois Tigeot 		u32 seqno;
13718621f407SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
137224edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
137324edb884SFrançois Tigeot 			continue;
137424edb884SFrançois Tigeot 
1375a05eeebfSFrançois Tigeot 		seqno = i915_gem_request_get_seqno(signaller_req);
137624edb884SFrançois Tigeot 		intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
137724edb884SFrançois Tigeot 		intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
137824edb884SFrançois Tigeot 					   PIPE_CONTROL_QW_WRITE |
1379*1487f786SFrançois Tigeot 					   PIPE_CONTROL_CS_STALL);
138024edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset));
138124edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
13822c9916cdSFrançois Tigeot 		intel_ring_emit(signaller, seqno);
138324edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
138424edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
13858621f407SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->hw_id));
138624edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
138724edb884SFrançois Tigeot 	}
138824edb884SFrançois Tigeot 
138924edb884SFrançois Tigeot 	return 0;
139024edb884SFrançois Tigeot }
139124edb884SFrançois Tigeot 
1392a05eeebfSFrançois Tigeot static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req,
139324edb884SFrançois Tigeot 			   unsigned int num_dwords)
139424edb884SFrançois Tigeot {
139524edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 6
13968621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
1397*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = signaller_req->i915;
139824edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
13998621f407SFrançois Tigeot 	enum intel_engine_id id;
14008621f407SFrançois Tigeot 	int ret, num_rings;
140124edb884SFrançois Tigeot 
1402*1487f786SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
140324edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
140424edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
140524edb884SFrançois Tigeot 
1406a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
140724edb884SFrançois Tigeot 	if (ret)
140824edb884SFrançois Tigeot 		return ret;
140924edb884SFrançois Tigeot 
14108621f407SFrançois Tigeot 	for_each_engine_id(waiter, dev_priv, id) {
14112c9916cdSFrançois Tigeot 		u32 seqno;
14128621f407SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
141324edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
141424edb884SFrançois Tigeot 			continue;
141524edb884SFrançois Tigeot 
1416a05eeebfSFrançois Tigeot 		seqno = i915_gem_request_get_seqno(signaller_req);
141724edb884SFrançois Tigeot 		intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
141824edb884SFrançois Tigeot 					   MI_FLUSH_DW_OP_STOREDW);
141924edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
142024edb884SFrançois Tigeot 					   MI_FLUSH_DW_USE_GTT);
142124edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
14222c9916cdSFrançois Tigeot 		intel_ring_emit(signaller, seqno);
142324edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
14248621f407SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->hw_id));
142524edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
142624edb884SFrançois Tigeot 	}
142724edb884SFrançois Tigeot 
142824edb884SFrançois Tigeot 	return 0;
142924edb884SFrançois Tigeot }
143024edb884SFrançois Tigeot 
1431a05eeebfSFrançois Tigeot static int gen6_signal(struct drm_i915_gem_request *signaller_req,
1432ba55f2f5SFrançois Tigeot 		       unsigned int num_dwords)
1433e3adcf8fSFrançois Tigeot {
14348621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
1435*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = signaller_req->i915;
1436ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *useless;
14378621f407SFrançois Tigeot 	enum intel_engine_id id;
14388621f407SFrançois Tigeot 	int ret, num_rings;
1439ba55f2f5SFrançois Tigeot 
144024edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 3
1441*1487f786SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
144224edb884SFrançois Tigeot 	num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2);
144324edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
1444ba55f2f5SFrançois Tigeot 
1445a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
1446ba55f2f5SFrançois Tigeot 	if (ret)
1447ba55f2f5SFrançois Tigeot 		return ret;
1448ba55f2f5SFrançois Tigeot 
14498621f407SFrançois Tigeot 	for_each_engine_id(useless, dev_priv, id) {
14508621f407SFrançois Tigeot 		i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[id];
1451aee94f86SFrançois Tigeot 
1452aee94f86SFrançois Tigeot 		if (i915_mmio_reg_valid(mbox_reg)) {
1453a05eeebfSFrançois Tigeot 			u32 seqno = i915_gem_request_get_seqno(signaller_req);
1454aee94f86SFrançois Tigeot 
1455ba55f2f5SFrançois Tigeot 			intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
1456aee94f86SFrançois Tigeot 			intel_ring_emit_reg(signaller, mbox_reg);
14572c9916cdSFrançois Tigeot 			intel_ring_emit(signaller, seqno);
1458ba55f2f5SFrançois Tigeot 		}
1459ba55f2f5SFrançois Tigeot 	}
1460ba55f2f5SFrançois Tigeot 
146124edb884SFrançois Tigeot 	/* If num_dwords was rounded, make sure the tail pointer is correct */
146224edb884SFrançois Tigeot 	if (num_rings % 2 == 0)
146324edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_NOOP);
146424edb884SFrançois Tigeot 
1465ba55f2f5SFrançois Tigeot 	return 0;
1466e3adcf8fSFrançois Tigeot }
1467e3adcf8fSFrançois Tigeot 
1468e3adcf8fSFrançois Tigeot /**
1469e3adcf8fSFrançois Tigeot  * gen6_add_request - Update the semaphore mailbox registers
1470e3adcf8fSFrançois Tigeot  *
1471a05eeebfSFrançois Tigeot  * @request - request to write to the ring
1472e3adcf8fSFrançois Tigeot  *
1473e3adcf8fSFrançois Tigeot  * Update the mailbox registers in the *other* rings with the current seqno.
1474e3adcf8fSFrançois Tigeot  * This acts like a signal in the canonical semaphore.
1475e3adcf8fSFrançois Tigeot  */
1476e3adcf8fSFrançois Tigeot static int
1477a05eeebfSFrançois Tigeot gen6_add_request(struct drm_i915_gem_request *req)
1478e3adcf8fSFrançois Tigeot {
14798621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1480ba55f2f5SFrançois Tigeot 	int ret;
1481e3adcf8fSFrançois Tigeot 
14828621f407SFrançois Tigeot 	if (engine->semaphore.signal)
14838621f407SFrançois Tigeot 		ret = engine->semaphore.signal(req, 4);
148424edb884SFrançois Tigeot 	else
1485a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 4);
148624edb884SFrançois Tigeot 
14879edbd4a0SFrançois Tigeot 	if (ret)
14889edbd4a0SFrançois Tigeot 		return ret;
14899edbd4a0SFrançois Tigeot 
14908621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
14918621f407SFrançois Tigeot 	intel_ring_emit(engine,
14928621f407SFrançois Tigeot 			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
14938621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
14948621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
14958621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1496e3adcf8fSFrançois Tigeot 
1497e3adcf8fSFrançois Tigeot 	return 0;
1498e3adcf8fSFrançois Tigeot }
1499e3adcf8fSFrançois Tigeot 
1500*1487f786SFrançois Tigeot static int
1501*1487f786SFrançois Tigeot gen8_render_add_request(struct drm_i915_gem_request *req)
1502*1487f786SFrançois Tigeot {
1503*1487f786SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1504*1487f786SFrançois Tigeot 	int ret;
1505*1487f786SFrançois Tigeot 
1506*1487f786SFrançois Tigeot 	if (engine->semaphore.signal)
1507*1487f786SFrançois Tigeot 		ret = engine->semaphore.signal(req, 8);
1508*1487f786SFrançois Tigeot 	else
1509*1487f786SFrançois Tigeot 		ret = intel_ring_begin(req, 8);
1510*1487f786SFrançois Tigeot 	if (ret)
1511*1487f786SFrançois Tigeot 		return ret;
1512*1487f786SFrançois Tigeot 
1513*1487f786SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
1514*1487f786SFrançois Tigeot 	intel_ring_emit(engine, (PIPE_CONTROL_GLOBAL_GTT_IVB |
1515*1487f786SFrançois Tigeot 				 PIPE_CONTROL_CS_STALL |
1516*1487f786SFrançois Tigeot 				 PIPE_CONTROL_QW_WRITE));
1517*1487f786SFrançois Tigeot 	intel_ring_emit(engine, intel_hws_seqno_address(req->engine));
1518*1487f786SFrançois Tigeot 	intel_ring_emit(engine, 0);
1519*1487f786SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
1520*1487f786SFrançois Tigeot 	/* We're thrashing one dword of HWS. */
1521*1487f786SFrançois Tigeot 	intel_ring_emit(engine, 0);
1522*1487f786SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
1523*1487f786SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
1524*1487f786SFrançois Tigeot 	__intel_ring_advance(engine);
1525*1487f786SFrançois Tigeot 
1526*1487f786SFrançois Tigeot 	return 0;
1527*1487f786SFrançois Tigeot }
1528*1487f786SFrançois Tigeot 
1529*1487f786SFrançois Tigeot static inline bool i915_gem_has_seqno_wrapped(struct drm_i915_private *dev_priv,
1530a2fdbec6SFrançois Tigeot 					      u32 seqno)
1531a2fdbec6SFrançois Tigeot {
1532a2fdbec6SFrançois Tigeot 	return dev_priv->last_seqno < seqno;
1533a2fdbec6SFrançois Tigeot }
1534a2fdbec6SFrançois Tigeot 
1535e3adcf8fSFrançois Tigeot /**
1536e3adcf8fSFrançois Tigeot  * intel_ring_sync - sync the waiter to the signaller on seqno
1537e3adcf8fSFrançois Tigeot  *
1538e3adcf8fSFrançois Tigeot  * @waiter - ring that is waiting
1539e3adcf8fSFrançois Tigeot  * @signaller - ring which has, or will signal
1540e3adcf8fSFrançois Tigeot  * @seqno - seqno which the waiter will block on
1541e3adcf8fSFrançois Tigeot  */
154224edb884SFrançois Tigeot 
154324edb884SFrançois Tigeot static int
1544a05eeebfSFrançois Tigeot gen8_ring_sync(struct drm_i915_gem_request *waiter_req,
154524edb884SFrançois Tigeot 	       struct intel_engine_cs *signaller,
154624edb884SFrançois Tigeot 	       u32 seqno)
154724edb884SFrançois Tigeot {
15488621f407SFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->engine;
1549*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = waiter_req->i915;
1550*1487f786SFrançois Tigeot 	u64 offset = GEN8_WAIT_OFFSET(waiter, signaller->id);
1551*1487f786SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt;
155224edb884SFrançois Tigeot 	int ret;
155324edb884SFrançois Tigeot 
1554a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
155524edb884SFrançois Tigeot 	if (ret)
155624edb884SFrançois Tigeot 		return ret;
155724edb884SFrançois Tigeot 
155824edb884SFrançois Tigeot 	intel_ring_emit(waiter, MI_SEMAPHORE_WAIT |
155924edb884SFrançois Tigeot 				MI_SEMAPHORE_GLOBAL_GTT |
156024edb884SFrançois Tigeot 				MI_SEMAPHORE_SAD_GTE_SDD);
156124edb884SFrançois Tigeot 	intel_ring_emit(waiter, seqno);
1562*1487f786SFrançois Tigeot 	intel_ring_emit(waiter, lower_32_bits(offset));
1563*1487f786SFrançois Tigeot 	intel_ring_emit(waiter, upper_32_bits(offset));
156424edb884SFrançois Tigeot 	intel_ring_advance(waiter);
1565*1487f786SFrançois Tigeot 
1566*1487f786SFrançois Tigeot 	/* When the !RCS engines idle waiting upon a semaphore, they lose their
1567*1487f786SFrançois Tigeot 	 * pagetables and we must reload them before executing the batch.
1568*1487f786SFrançois Tigeot 	 * We do this on the i915_switch_context() following the wait and
1569*1487f786SFrançois Tigeot 	 * before the dispatch.
1570*1487f786SFrançois Tigeot 	 */
1571*1487f786SFrançois Tigeot 	ppgtt = waiter_req->ctx->ppgtt;
1572*1487f786SFrançois Tigeot 	if (ppgtt && waiter_req->engine->id != RCS)
1573*1487f786SFrançois Tigeot 		ppgtt->pd_dirty_rings |= intel_engine_flag(waiter_req->engine);
157424edb884SFrançois Tigeot 	return 0;
157524edb884SFrançois Tigeot }
157624edb884SFrançois Tigeot 
1577e3adcf8fSFrançois Tigeot static int
1578a05eeebfSFrançois Tigeot gen6_ring_sync(struct drm_i915_gem_request *waiter_req,
1579ba55f2f5SFrançois Tigeot 	       struct intel_engine_cs *signaller,
1580e3adcf8fSFrançois Tigeot 	       u32 seqno)
1581e3adcf8fSFrançois Tigeot {
15828621f407SFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->engine;
1583e3adcf8fSFrançois Tigeot 	u32 dw1 = MI_SEMAPHORE_MBOX |
1584e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_COMPARE |
1585e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_REGISTER;
1586ba55f2f5SFrançois Tigeot 	u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id];
1587ba55f2f5SFrançois Tigeot 	int ret;
1588e3adcf8fSFrançois Tigeot 
1589686a02f1SFrançois Tigeot 	/* Throughout all of the GEM code, seqno passed implies our current
1590686a02f1SFrançois Tigeot 	 * seqno is >= the last seqno executed. However for hardware the
1591686a02f1SFrançois Tigeot 	 * comparison is strictly greater than.
1592686a02f1SFrançois Tigeot 	 */
1593686a02f1SFrançois Tigeot 	seqno -= 1;
1594686a02f1SFrançois Tigeot 
1595ba55f2f5SFrançois Tigeot 	WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
1596686a02f1SFrançois Tigeot 
1597a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
1598e3adcf8fSFrançois Tigeot 	if (ret)
1599e3adcf8fSFrançois Tigeot 		return ret;
1600e3adcf8fSFrançois Tigeot 
1601a2fdbec6SFrançois Tigeot 	/* If seqno wrap happened, omit the wait with no-ops */
1602*1487f786SFrançois Tigeot 	if (likely(!i915_gem_has_seqno_wrapped(waiter_req->i915, seqno))) {
1603ba55f2f5SFrançois Tigeot 		intel_ring_emit(waiter, dw1 | wait_mbox);
1604e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, seqno);
1605e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, 0);
1606e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1607a2fdbec6SFrançois Tigeot 	} else {
1608a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1609a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1610a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1611a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1612a2fdbec6SFrançois Tigeot 	}
1613e3adcf8fSFrançois Tigeot 	intel_ring_advance(waiter);
1614e3adcf8fSFrançois Tigeot 
1615e3adcf8fSFrançois Tigeot 	return 0;
1616e3adcf8fSFrançois Tigeot }
1617e3adcf8fSFrançois Tigeot 
1618e3adcf8fSFrançois Tigeot #define PIPE_CONTROL_FLUSH(ring__, addr__)					\
1619e3adcf8fSFrançois Tigeot do {									\
1620e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |		\
1621e3adcf8fSFrançois Tigeot 		 PIPE_CONTROL_DEPTH_STALL);				\
1622e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT);			\
1623e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, 0);							\
1624e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, 0);							\
1625e3adcf8fSFrançois Tigeot } while (0)
1626e3adcf8fSFrançois Tigeot 
1627e3adcf8fSFrançois Tigeot static int
1628a05eeebfSFrançois Tigeot pc_render_add_request(struct drm_i915_gem_request *req)
1629e3adcf8fSFrançois Tigeot {
16308621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
16318621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
1632e3adcf8fSFrançois Tigeot 	int ret;
1633e3adcf8fSFrançois Tigeot 
1634e3adcf8fSFrançois Tigeot 	/* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently
1635e3adcf8fSFrançois Tigeot 	 * incoherent with writes to memory, i.e. completely fubar,
1636e3adcf8fSFrançois Tigeot 	 * so we need to use PIPE_NOTIFY instead.
1637e3adcf8fSFrançois Tigeot 	 *
1638e3adcf8fSFrançois Tigeot 	 * However, we also need to workaround the qword write
1639e3adcf8fSFrançois Tigeot 	 * incoherence by flushing the 6 PIPE_NOTIFY buffers out to
1640e3adcf8fSFrançois Tigeot 	 * memory before requesting an interrupt.
1641e3adcf8fSFrançois Tigeot 	 */
1642a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 32);
1643e3adcf8fSFrançois Tigeot 	if (ret)
1644e3adcf8fSFrançois Tigeot 		return ret;
1645e3adcf8fSFrançois Tigeot 
16468621f407SFrançois Tigeot 	intel_ring_emit(engine,
16478621f407SFrançois Tigeot 			GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
1648e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_WRITE_FLUSH |
1649e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
16508621f407SFrançois Tigeot 	intel_ring_emit(engine,
16518621f407SFrançois Tigeot 			engine->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
16528621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
16538621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
16548621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1655ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
16568621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1657ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16588621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1659ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16608621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1661ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16628621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1663ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16648621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1665b5c29a34SFrançois Tigeot 
16668621f407SFrançois Tigeot 	intel_ring_emit(engine,
16678621f407SFrançois Tigeot 			GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
1668e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_WRITE_FLUSH |
1669e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
1670e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_NOTIFY);
16718621f407SFrançois Tigeot 	intel_ring_emit(engine,
16728621f407SFrançois Tigeot 			engine->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
16738621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
16748621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
16758621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1676e3adcf8fSFrançois Tigeot 
1677e3adcf8fSFrançois Tigeot 	return 0;
1678e3adcf8fSFrançois Tigeot }
1679e3adcf8fSFrançois Tigeot 
16808621f407SFrançois Tigeot static void
16818621f407SFrançois Tigeot gen6_seqno_barrier(struct intel_engine_cs *engine)
1682e3adcf8fSFrançois Tigeot {
1683*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
16848621f407SFrançois Tigeot 
1685e3adcf8fSFrançois Tigeot 	/* Workaround to force correct ordering between irq and seqno writes on
1686e3adcf8fSFrançois Tigeot 	 * ivb (and maybe also on snb) by reading from a CS register (like
16878621f407SFrançois Tigeot 	 * ACTHD) before reading the status page.
16888621f407SFrançois Tigeot 	 *
16898621f407SFrançois Tigeot 	 * Note that this effectively stalls the read by the time it takes to
16908621f407SFrançois Tigeot 	 * do a memory transaction, which more or less ensures that the write
16918621f407SFrançois Tigeot 	 * from the GPU has sufficient time to invalidate the CPU cacheline.
16928621f407SFrançois Tigeot 	 * Alternatively we could delay the interrupt from the CS ring to give
16938621f407SFrançois Tigeot 	 * the write time to land, but that would incur a delay after every
16948621f407SFrançois Tigeot 	 * batch i.e. much more frequent than a delay when waiting for the
16958621f407SFrançois Tigeot 	 * interrupt (with the same net latency).
16968621f407SFrançois Tigeot 	 *
16978621f407SFrançois Tigeot 	 * Also note that to prevent whole machine hangs on gen7, we have to
16988621f407SFrançois Tigeot 	 * take the spinlock to guard against concurrent cacheline access.
16998621f407SFrançois Tigeot 	 */
17008621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->uncore.lock);
17018621f407SFrançois Tigeot 	POSTING_READ_FW(RING_ACTHD(engine->mmio_base));
17028621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->uncore.lock);
1703e3adcf8fSFrançois Tigeot }
1704e3adcf8fSFrançois Tigeot 
1705b030f26bSFrançois Tigeot static u32
17068621f407SFrançois Tigeot ring_get_seqno(struct intel_engine_cs *engine)
1707e3adcf8fSFrançois Tigeot {
17088621f407SFrançois Tigeot 	return intel_read_status_page(engine, I915_GEM_HWS_INDEX);
1709e3adcf8fSFrançois Tigeot }
1710e3adcf8fSFrançois Tigeot 
1711a2fdbec6SFrançois Tigeot static void
17128621f407SFrançois Tigeot ring_set_seqno(struct intel_engine_cs *engine, u32 seqno)
1713a2fdbec6SFrançois Tigeot {
17148621f407SFrançois Tigeot 	intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
1715a2fdbec6SFrançois Tigeot }
1716a2fdbec6SFrançois Tigeot 
1717b030f26bSFrançois Tigeot static u32
17188621f407SFrançois Tigeot pc_render_get_seqno(struct intel_engine_cs *engine)
1719e3adcf8fSFrançois Tigeot {
17208621f407SFrançois Tigeot 	return engine->scratch.cpu_page[0];
1721e3adcf8fSFrançois Tigeot }
1722e3adcf8fSFrançois Tigeot 
1723a2fdbec6SFrançois Tigeot static void
17248621f407SFrançois Tigeot pc_render_set_seqno(struct intel_engine_cs *engine, u32 seqno)
1725a2fdbec6SFrançois Tigeot {
17268621f407SFrançois Tigeot 	engine->scratch.cpu_page[0] = seqno;
1727a2fdbec6SFrançois Tigeot }
1728a2fdbec6SFrançois Tigeot 
1729e3adcf8fSFrançois Tigeot static bool
17308621f407SFrançois Tigeot gen5_ring_get_irq(struct intel_engine_cs *engine)
1731e3adcf8fSFrançois Tigeot {
1732*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17335e269720SFrançois Tigeot 	unsigned long flags;
1734e3adcf8fSFrançois Tigeot 
17352c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
1736e3adcf8fSFrançois Tigeot 		return false;
1737e3adcf8fSFrançois Tigeot 
17385e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17398621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0)
17408621f407SFrançois Tigeot 		gen5_enable_gt_irq(dev_priv, engine->irq_enable_mask);
17415e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1742e3adcf8fSFrançois Tigeot 
1743e3adcf8fSFrançois Tigeot 	return true;
1744e3adcf8fSFrançois Tigeot }
1745e3adcf8fSFrançois Tigeot 
1746e3adcf8fSFrançois Tigeot static void
17478621f407SFrançois Tigeot gen5_ring_put_irq(struct intel_engine_cs *engine)
1748e3adcf8fSFrançois Tigeot {
1749*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17505e269720SFrançois Tigeot 	unsigned long flags;
1751e3adcf8fSFrançois Tigeot 
17525e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17538621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0)
17548621f407SFrançois Tigeot 		gen5_disable_gt_irq(dev_priv, engine->irq_enable_mask);
17555e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1756686a02f1SFrançois Tigeot }
1757686a02f1SFrançois Tigeot 
1758686a02f1SFrançois Tigeot static bool
17598621f407SFrançois Tigeot i9xx_ring_get_irq(struct intel_engine_cs *engine)
1760686a02f1SFrançois Tigeot {
1761*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17625e269720SFrançois Tigeot 	unsigned long flags;
1763686a02f1SFrançois Tigeot 
17642c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
1765686a02f1SFrançois Tigeot 		return false;
1766686a02f1SFrançois Tigeot 
17675e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17688621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
17698621f407SFrançois Tigeot 		dev_priv->irq_mask &= ~engine->irq_enable_mask;
1770686a02f1SFrançois Tigeot 		I915_WRITE(IMR, dev_priv->irq_mask);
1771686a02f1SFrançois Tigeot 		POSTING_READ(IMR);
1772686a02f1SFrançois Tigeot 	}
17735e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1774686a02f1SFrançois Tigeot 
1775686a02f1SFrançois Tigeot 	return true;
1776686a02f1SFrançois Tigeot }
1777686a02f1SFrançois Tigeot 
1778686a02f1SFrançois Tigeot static void
17798621f407SFrançois Tigeot i9xx_ring_put_irq(struct intel_engine_cs *engine)
1780686a02f1SFrançois Tigeot {
1781*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17825e269720SFrançois Tigeot 	unsigned long flags;
1783686a02f1SFrançois Tigeot 
17845e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17858621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
17868621f407SFrançois Tigeot 		dev_priv->irq_mask |= engine->irq_enable_mask;
1787686a02f1SFrançois Tigeot 		I915_WRITE(IMR, dev_priv->irq_mask);
1788686a02f1SFrançois Tigeot 		POSTING_READ(IMR);
1789686a02f1SFrançois Tigeot 	}
17905e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1791686a02f1SFrançois Tigeot }
1792686a02f1SFrançois Tigeot 
1793686a02f1SFrançois Tigeot static bool
17948621f407SFrançois Tigeot i8xx_ring_get_irq(struct intel_engine_cs *engine)
1795686a02f1SFrançois Tigeot {
1796*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17975e269720SFrançois Tigeot 	unsigned long flags;
1798686a02f1SFrançois Tigeot 
17992c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
1800686a02f1SFrançois Tigeot 		return false;
1801686a02f1SFrançois Tigeot 
18025e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18038621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
18048621f407SFrançois Tigeot 		dev_priv->irq_mask &= ~engine->irq_enable_mask;
1805686a02f1SFrançois Tigeot 		I915_WRITE16(IMR, dev_priv->irq_mask);
1806686a02f1SFrançois Tigeot 		POSTING_READ16(IMR);
1807686a02f1SFrançois Tigeot 	}
18085e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1809686a02f1SFrançois Tigeot 
1810686a02f1SFrançois Tigeot 	return true;
1811686a02f1SFrançois Tigeot }
1812686a02f1SFrançois Tigeot 
1813686a02f1SFrançois Tigeot static void
18148621f407SFrançois Tigeot i8xx_ring_put_irq(struct intel_engine_cs *engine)
1815686a02f1SFrançois Tigeot {
1816*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
18175e269720SFrançois Tigeot 	unsigned long flags;
1818686a02f1SFrançois Tigeot 
18195e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18208621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
18218621f407SFrançois Tigeot 		dev_priv->irq_mask |= engine->irq_enable_mask;
1822686a02f1SFrançois Tigeot 		I915_WRITE16(IMR, dev_priv->irq_mask);
1823686a02f1SFrançois Tigeot 		POSTING_READ16(IMR);
1824e3adcf8fSFrançois Tigeot 	}
18255e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1826e3adcf8fSFrançois Tigeot }
1827e3adcf8fSFrançois Tigeot 
1828e3adcf8fSFrançois Tigeot static int
1829a05eeebfSFrançois Tigeot bsd_ring_flush(struct drm_i915_gem_request *req,
1830b5c29a34SFrançois Tigeot 	       u32     invalidate_domains,
1831b5c29a34SFrançois Tigeot 	       u32     flush_domains)
1832e3adcf8fSFrançois Tigeot {
18338621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1834e3adcf8fSFrançois Tigeot 	int ret;
1835e3adcf8fSFrançois Tigeot 
1836a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1837e3adcf8fSFrançois Tigeot 	if (ret)
1838e3adcf8fSFrançois Tigeot 		return ret;
1839e3adcf8fSFrançois Tigeot 
18408621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_FLUSH);
18418621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
18428621f407SFrançois Tigeot 	intel_ring_advance(engine);
1843e3adcf8fSFrançois Tigeot 	return 0;
1844e3adcf8fSFrançois Tigeot }
1845e3adcf8fSFrançois Tigeot 
1846e3adcf8fSFrançois Tigeot static int
1847a05eeebfSFrançois Tigeot i9xx_add_request(struct drm_i915_gem_request *req)
1848e3adcf8fSFrançois Tigeot {
18498621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1850e3adcf8fSFrançois Tigeot 	int ret;
1851e3adcf8fSFrançois Tigeot 
1852a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
1853e3adcf8fSFrançois Tigeot 	if (ret)
1854e3adcf8fSFrançois Tigeot 		return ret;
1855e3adcf8fSFrançois Tigeot 
18568621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
18578621f407SFrançois Tigeot 	intel_ring_emit(engine,
18588621f407SFrançois Tigeot 			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
18598621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
18608621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
18618621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1862e3adcf8fSFrançois Tigeot 
1863e3adcf8fSFrançois Tigeot 	return 0;
1864e3adcf8fSFrançois Tigeot }
1865e3adcf8fSFrançois Tigeot 
1866e3adcf8fSFrançois Tigeot static bool
18678621f407SFrançois Tigeot gen6_ring_get_irq(struct intel_engine_cs *engine)
1868e3adcf8fSFrançois Tigeot {
1869*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
18705e269720SFrançois Tigeot 	unsigned long flags;
1871e3adcf8fSFrançois Tigeot 
18722c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
1873e3adcf8fSFrançois Tigeot 		return false;
1874e3adcf8fSFrançois Tigeot 
18755e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18768621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
1877*1487f786SFrançois Tigeot 		if (HAS_L3_DPF(dev_priv) && engine->id == RCS)
18788621f407SFrançois Tigeot 			I915_WRITE_IMR(engine,
18798621f407SFrançois Tigeot 				       ~(engine->irq_enable_mask |
1880*1487f786SFrançois Tigeot 					 GT_PARITY_ERROR(dev_priv)));
1881686a02f1SFrançois Tigeot 		else
18828621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
18838621f407SFrançois Tigeot 		gen5_enable_gt_irq(dev_priv, engine->irq_enable_mask);
1884e3adcf8fSFrançois Tigeot 	}
18855e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1886e3adcf8fSFrançois Tigeot 
1887e3adcf8fSFrançois Tigeot 	return true;
1888e3adcf8fSFrançois Tigeot }
1889e3adcf8fSFrançois Tigeot 
1890e3adcf8fSFrançois Tigeot static void
18918621f407SFrançois Tigeot gen6_ring_put_irq(struct intel_engine_cs *engine)
1892e3adcf8fSFrançois Tigeot {
1893*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
18945e269720SFrançois Tigeot 	unsigned long flags;
1895e3adcf8fSFrançois Tigeot 
18965e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18978621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
1898*1487f786SFrançois Tigeot 		if (HAS_L3_DPF(dev_priv) && engine->id == RCS)
1899*1487f786SFrançois Tigeot 			I915_WRITE_IMR(engine, ~GT_PARITY_ERROR(dev_priv));
1900686a02f1SFrançois Tigeot 		else
19018621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~0);
19028621f407SFrançois Tigeot 		gen5_disable_gt_irq(dev_priv, engine->irq_enable_mask);
1903e3adcf8fSFrançois Tigeot 	}
19045e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1905e3adcf8fSFrançois Tigeot }
1906e3adcf8fSFrançois Tigeot 
19075d0b1887SFrançois Tigeot static bool
19088621f407SFrançois Tigeot hsw_vebox_get_irq(struct intel_engine_cs *engine)
19095d0b1887SFrançois Tigeot {
1910*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
19115e269720SFrançois Tigeot 	unsigned long flags;
19125d0b1887SFrançois Tigeot 
19132c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
19145d0b1887SFrançois Tigeot 		return false;
19155d0b1887SFrançois Tigeot 
19165e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19178621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
19188621f407SFrançois Tigeot 		I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
19198621f407SFrançois Tigeot 		gen6_enable_pm_irq(dev_priv, engine->irq_enable_mask);
19205d0b1887SFrançois Tigeot 	}
19215e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19225d0b1887SFrançois Tigeot 
19235d0b1887SFrançois Tigeot 	return true;
19245d0b1887SFrançois Tigeot }
19255d0b1887SFrançois Tigeot 
19265d0b1887SFrançois Tigeot static void
19278621f407SFrançois Tigeot hsw_vebox_put_irq(struct intel_engine_cs *engine)
19285d0b1887SFrançois Tigeot {
1929*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
19305e269720SFrançois Tigeot 	unsigned long flags;
19315d0b1887SFrançois Tigeot 
19325e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19338621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
19348621f407SFrançois Tigeot 		I915_WRITE_IMR(engine, ~0);
19358621f407SFrançois Tigeot 		gen6_disable_pm_irq(dev_priv, engine->irq_enable_mask);
19365d0b1887SFrançois Tigeot 	}
19375e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19389edbd4a0SFrançois Tigeot }
19399edbd4a0SFrançois Tigeot 
19409edbd4a0SFrançois Tigeot static bool
19418621f407SFrançois Tigeot gen8_ring_get_irq(struct intel_engine_cs *engine)
19429edbd4a0SFrançois Tigeot {
1943*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
19445e269720SFrançois Tigeot 	unsigned long flags;
19459edbd4a0SFrançois Tigeot 
19462c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
19479edbd4a0SFrançois Tigeot 		return false;
19489edbd4a0SFrançois Tigeot 
19495e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19508621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
1951*1487f786SFrançois Tigeot 		if (HAS_L3_DPF(dev_priv) && engine->id == RCS) {
19528621f407SFrançois Tigeot 			I915_WRITE_IMR(engine,
19538621f407SFrançois Tigeot 				       ~(engine->irq_enable_mask |
19549edbd4a0SFrançois Tigeot 					 GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
19559edbd4a0SFrançois Tigeot 		} else {
19568621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
19579edbd4a0SFrançois Tigeot 		}
19588621f407SFrançois Tigeot 		POSTING_READ(RING_IMR(engine->mmio_base));
19599edbd4a0SFrançois Tigeot 	}
19605e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19619edbd4a0SFrançois Tigeot 
19629edbd4a0SFrançois Tigeot 	return true;
19639edbd4a0SFrançois Tigeot }
19649edbd4a0SFrançois Tigeot 
19659edbd4a0SFrançois Tigeot static void
19668621f407SFrançois Tigeot gen8_ring_put_irq(struct intel_engine_cs *engine)
19679edbd4a0SFrançois Tigeot {
1968*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
19695e269720SFrançois Tigeot 	unsigned long flags;
19709edbd4a0SFrançois Tigeot 
19715e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19728621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
1973*1487f786SFrançois Tigeot 		if (HAS_L3_DPF(dev_priv) && engine->id == RCS) {
19748621f407SFrançois Tigeot 			I915_WRITE_IMR(engine,
19759edbd4a0SFrançois Tigeot 				       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
19769edbd4a0SFrançois Tigeot 		} else {
19778621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~0);
19789edbd4a0SFrançois Tigeot 		}
19798621f407SFrançois Tigeot 		POSTING_READ(RING_IMR(engine->mmio_base));
19809edbd4a0SFrançois Tigeot 	}
19815e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19825d0b1887SFrançois Tigeot }
19835d0b1887SFrançois Tigeot 
1984e3adcf8fSFrançois Tigeot static int
1985a05eeebfSFrançois Tigeot i965_dispatch_execbuffer(struct drm_i915_gem_request *req,
1986ba55f2f5SFrançois Tigeot 			 u64 offset, u32 length,
1987477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1988e3adcf8fSFrançois Tigeot {
19898621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1990e3adcf8fSFrançois Tigeot 	int ret;
1991e3adcf8fSFrançois Tigeot 
1992a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1993e3adcf8fSFrançois Tigeot 	if (ret)
1994e3adcf8fSFrançois Tigeot 		return ret;
1995e3adcf8fSFrançois Tigeot 
19968621f407SFrançois Tigeot 	intel_ring_emit(engine,
1997686a02f1SFrançois Tigeot 			MI_BATCH_BUFFER_START |
1998b5c29a34SFrançois Tigeot 			MI_BATCH_GTT |
1999477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2000477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
20018621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
20028621f407SFrançois Tigeot 	intel_ring_advance(engine);
2003e3adcf8fSFrançois Tigeot 
2004e3adcf8fSFrançois Tigeot 	return 0;
2005e3adcf8fSFrançois Tigeot }
2006e3adcf8fSFrançois Tigeot 
2007b5c29a34SFrançois Tigeot /* Just userspace ABI convention to limit the wa batch bo to a resonable size */
2008b5c29a34SFrançois Tigeot #define I830_BATCH_LIMIT (256*1024)
200924edb884SFrançois Tigeot #define I830_TLB_ENTRIES (2)
201024edb884SFrançois Tigeot #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
2011e3adcf8fSFrançois Tigeot static int
2012a05eeebfSFrançois Tigeot i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
2013ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
2014477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
2015e3adcf8fSFrançois Tigeot {
20168621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
20178621f407SFrançois Tigeot 	u32 cs_offset = engine->scratch.gtt_offset;
2018e3adcf8fSFrançois Tigeot 	int ret;
2019e3adcf8fSFrançois Tigeot 
2020a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
202124edb884SFrançois Tigeot 	if (ret)
202224edb884SFrançois Tigeot 		return ret;
202324edb884SFrançois Tigeot 
202424edb884SFrançois Tigeot 	/* Evict the invalid PTE TLBs */
20258621f407SFrançois Tigeot 	intel_ring_emit(engine, COLOR_BLT_CMD | BLT_WRITE_RGBA);
20268621f407SFrançois Tigeot 	intel_ring_emit(engine, BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | 4096);
20278621f407SFrançois Tigeot 	intel_ring_emit(engine, I830_TLB_ENTRIES << 16 | 4); /* load each page */
20288621f407SFrançois Tigeot 	intel_ring_emit(engine, cs_offset);
20298621f407SFrançois Tigeot 	intel_ring_emit(engine, 0xdeadbeef);
20308621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
20318621f407SFrançois Tigeot 	intel_ring_advance(engine);
203224edb884SFrançois Tigeot 
2033477eb7f9SFrançois Tigeot 	if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
203424edb884SFrançois Tigeot 		if (len > I830_BATCH_LIMIT)
203524edb884SFrançois Tigeot 			return -ENOSPC;
203624edb884SFrançois Tigeot 
2037a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 6 + 2);
203824edb884SFrançois Tigeot 		if (ret)
203924edb884SFrançois Tigeot 			return ret;
204024edb884SFrançois Tigeot 
204124edb884SFrançois Tigeot 		/* Blit the batch (which has now all relocs applied) to the
204224edb884SFrançois Tigeot 		 * stable batch scratch bo area (so that the CS never
204324edb884SFrançois Tigeot 		 * stumbles over its tlb invalidation bug) ...
204424edb884SFrançois Tigeot 		 */
20458621f407SFrançois Tigeot 		intel_ring_emit(engine, SRC_COPY_BLT_CMD | BLT_WRITE_RGBA);
20468621f407SFrançois Tigeot 		intel_ring_emit(engine,
20478621f407SFrançois Tigeot 				BLT_DEPTH_32 | BLT_ROP_SRC_COPY | 4096);
20488621f407SFrançois Tigeot 		intel_ring_emit(engine, DIV_ROUND_UP(len, 4096) << 16 | 4096);
20498621f407SFrançois Tigeot 		intel_ring_emit(engine, cs_offset);
20508621f407SFrançois Tigeot 		intel_ring_emit(engine, 4096);
20518621f407SFrançois Tigeot 		intel_ring_emit(engine, offset);
205224edb884SFrançois Tigeot 
20538621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_FLUSH);
20548621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
20558621f407SFrançois Tigeot 		intel_ring_advance(engine);
205624edb884SFrançois Tigeot 
205724edb884SFrançois Tigeot 		/* ... and execute it. */
205824edb884SFrançois Tigeot 		offset = cs_offset;
205924edb884SFrançois Tigeot 	}
206024edb884SFrançois Tigeot 
2061c0e85e96SFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2062e3adcf8fSFrançois Tigeot 	if (ret)
2063e3adcf8fSFrançois Tigeot 		return ret;
2064e3adcf8fSFrançois Tigeot 
20658621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
20668621f407SFrançois Tigeot 	intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
2067477eb7f9SFrançois Tigeot 					  0 : MI_BATCH_NON_SECURE));
20688621f407SFrançois Tigeot 	intel_ring_advance(engine);
2069686a02f1SFrançois Tigeot 
2070686a02f1SFrançois Tigeot 	return 0;
2071686a02f1SFrançois Tigeot }
2072686a02f1SFrançois Tigeot 
2073686a02f1SFrançois Tigeot static int
2074a05eeebfSFrançois Tigeot i915_dispatch_execbuffer(struct drm_i915_gem_request *req,
2075ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
2076477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
2077686a02f1SFrançois Tigeot {
20788621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2079686a02f1SFrançois Tigeot 	int ret;
2080686a02f1SFrançois Tigeot 
2081a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2082e3adcf8fSFrançois Tigeot 	if (ret)
2083e3adcf8fSFrançois Tigeot 		return ret;
2084e3adcf8fSFrançois Tigeot 
20858621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
20868621f407SFrançois Tigeot 	intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
2087477eb7f9SFrançois Tigeot 					  0 : MI_BATCH_NON_SECURE));
20888621f407SFrançois Tigeot 	intel_ring_advance(engine);
2089e3adcf8fSFrançois Tigeot 
2090e3adcf8fSFrançois Tigeot 	return 0;
2091e3adcf8fSFrançois Tigeot }
2092e3adcf8fSFrançois Tigeot 
20938621f407SFrançois Tigeot static void cleanup_phys_status_page(struct intel_engine_cs *engine)
2094c0e85e96SFrançois Tigeot {
2095*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2096c0e85e96SFrançois Tigeot 
2097c0e85e96SFrançois Tigeot 	if (!dev_priv->status_page_dmah)
2098c0e85e96SFrançois Tigeot 		return;
2099c0e85e96SFrançois Tigeot 
2100*1487f786SFrançois Tigeot 	drm_pci_free(dev_priv->dev, dev_priv->status_page_dmah);
21018621f407SFrançois Tigeot 	engine->status_page.page_addr = NULL;
2102c0e85e96SFrançois Tigeot }
2103c0e85e96SFrançois Tigeot 
21048621f407SFrançois Tigeot static void cleanup_status_page(struct intel_engine_cs *engine)
2105e3adcf8fSFrançois Tigeot {
2106e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
2107e3adcf8fSFrançois Tigeot 
21088621f407SFrançois Tigeot 	obj = engine->status_page.obj;
2109e3adcf8fSFrançois Tigeot 	if (obj == NULL)
2110e3adcf8fSFrançois Tigeot 		return;
2111e3adcf8fSFrançois Tigeot 
21127ec9f8e5SFrançois Tigeot 	kunmap(sg_page(obj->pages->sgl));
2113ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
2114e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
21158621f407SFrançois Tigeot 	engine->status_page.obj = NULL;
2116e3adcf8fSFrançois Tigeot }
2117e3adcf8fSFrançois Tigeot 
21188621f407SFrançois Tigeot static int init_status_page(struct intel_engine_cs *engine)
2119e3adcf8fSFrançois Tigeot {
21208621f407SFrançois Tigeot 	struct drm_i915_gem_object *obj = engine->status_page.obj;
2121ba55f2f5SFrançois Tigeot 
2122c0e85e96SFrançois Tigeot 	if (obj == NULL) {
212324edb884SFrançois Tigeot 		unsigned flags;
2124e3adcf8fSFrançois Tigeot 		int ret;
2125e3adcf8fSFrançois Tigeot 
2126*1487f786SFrançois Tigeot 		obj = i915_gem_object_create(engine->i915->dev, 4096);
2127*1487f786SFrançois Tigeot 		if (IS_ERR(obj)) {
2128e3adcf8fSFrançois Tigeot 			DRM_ERROR("Failed to allocate status page\n");
2129*1487f786SFrançois Tigeot 			return PTR_ERR(obj);
2130e3adcf8fSFrançois Tigeot 		}
2131e3adcf8fSFrançois Tigeot 
2132ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
2133ba55f2f5SFrançois Tigeot 		if (ret)
2134e3adcf8fSFrançois Tigeot 			goto err_unref;
2135ba55f2f5SFrançois Tigeot 
213624edb884SFrançois Tigeot 		flags = 0;
2137*1487f786SFrançois Tigeot 		if (!HAS_LLC(engine->i915))
213824edb884SFrançois Tigeot 			/* On g33, we cannot place HWS above 256MiB, so
213924edb884SFrançois Tigeot 			 * restrict its pinning to the low mappable arena.
214024edb884SFrançois Tigeot 			 * Though this restriction is not documented for
214124edb884SFrançois Tigeot 			 * gen4, gen5, or byt, they also behave similarly
214224edb884SFrançois Tigeot 			 * and hang if the HWS is placed at the top of the
214324edb884SFrançois Tigeot 			 * GTT. To generalise, it appears that all !llc
214424edb884SFrançois Tigeot 			 * platforms have issues with us placing the HWS
214524edb884SFrançois Tigeot 			 * above the mappable region (even though we never
214624edb884SFrançois Tigeot 			 * actualy map it).
214724edb884SFrançois Tigeot 			 */
214824edb884SFrançois Tigeot 			flags |= PIN_MAPPABLE;
214924edb884SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 4096, flags);
2150ba55f2f5SFrançois Tigeot 		if (ret) {
2151ba55f2f5SFrançois Tigeot err_unref:
2152ba55f2f5SFrançois Tigeot 			drm_gem_object_unreference(&obj->base);
2153ba55f2f5SFrançois Tigeot 			return ret;
2154ba55f2f5SFrançois Tigeot 		}
2155ba55f2f5SFrançois Tigeot 
21568621f407SFrançois Tigeot 		engine->status_page.obj = obj;
2157e3adcf8fSFrançois Tigeot 	}
2158e3adcf8fSFrançois Tigeot 
21598621f407SFrançois Tigeot 	engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
21608621f407SFrançois Tigeot 	engine->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
21618621f407SFrançois Tigeot 	memset(engine->status_page.page_addr, 0, PAGE_SIZE);
2162e3adcf8fSFrançois Tigeot 
2163b5c29a34SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
21648621f407SFrançois Tigeot 			engine->name, engine->status_page.gfx_addr);
2165e3adcf8fSFrançois Tigeot 
2166e3adcf8fSFrançois Tigeot 	return 0;
2167e3adcf8fSFrançois Tigeot }
2168e3adcf8fSFrançois Tigeot 
21698621f407SFrançois Tigeot static int init_phys_status_page(struct intel_engine_cs *engine)
2170686a02f1SFrançois Tigeot {
2171*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2172686a02f1SFrançois Tigeot 
2173686a02f1SFrançois Tigeot 	if (!dev_priv->status_page_dmah) {
2174686a02f1SFrançois Tigeot 		dev_priv->status_page_dmah =
2175*1487f786SFrançois Tigeot 			drm_pci_alloc(dev_priv->dev, PAGE_SIZE, PAGE_SIZE);
2176686a02f1SFrançois Tigeot 		if (!dev_priv->status_page_dmah)
2177686a02f1SFrançois Tigeot 			return -ENOMEM;
2178686a02f1SFrançois Tigeot 	}
2179686a02f1SFrançois Tigeot 
21808621f407SFrançois Tigeot 	engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
21818621f407SFrançois Tigeot 	memset(engine->status_page.page_addr, 0, PAGE_SIZE);
2182686a02f1SFrançois Tigeot 
2183686a02f1SFrançois Tigeot 	return 0;
2184686a02f1SFrançois Tigeot }
2185686a02f1SFrançois Tigeot 
21862c9916cdSFrançois Tigeot void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
21872c9916cdSFrançois Tigeot {
2188*1487f786SFrançois Tigeot 	GEM_BUG_ON(ringbuf->vma == NULL);
2189*1487f786SFrançois Tigeot 	GEM_BUG_ON(ringbuf->virtual_start == NULL);
2190*1487f786SFrançois Tigeot 
2191aee94f86SFrançois Tigeot 	if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
21928621f407SFrançois Tigeot 		i915_gem_object_unpin_map(ringbuf->obj);
2193aee94f86SFrançois Tigeot 	else
2194*1487f786SFrançois Tigeot 		i915_vma_unpin_iomap(ringbuf->vma);
21952c9916cdSFrançois Tigeot 	ringbuf->virtual_start = NULL;
2196*1487f786SFrançois Tigeot 
21972c9916cdSFrançois Tigeot 	i915_gem_object_ggtt_unpin(ringbuf->obj);
2198*1487f786SFrançois Tigeot 	ringbuf->vma = NULL;
21992c9916cdSFrançois Tigeot }
22002c9916cdSFrançois Tigeot 
2201*1487f786SFrançois Tigeot int intel_pin_and_map_ringbuffer_obj(struct drm_i915_private *dev_priv,
22022c9916cdSFrançois Tigeot 				     struct intel_ringbuffer *ringbuf)
22032c9916cdSFrançois Tigeot {
22042c9916cdSFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
2205c0e85e96SFrançois Tigeot 	/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
2206c0e85e96SFrançois Tigeot 	unsigned flags = PIN_OFFSET_BIAS | 4096;
22078621f407SFrançois Tigeot 	void *addr;
22082c9916cdSFrançois Tigeot 	int ret;
22092c9916cdSFrançois Tigeot 
2210aee94f86SFrançois Tigeot 	if (HAS_LLC(dev_priv) && !obj->stolen) {
2211c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, flags);
2212aee94f86SFrançois Tigeot 		if (ret)
2213aee94f86SFrançois Tigeot 			return ret;
2214aee94f86SFrançois Tigeot 
2215aee94f86SFrançois Tigeot 		ret = i915_gem_object_set_to_cpu_domain(obj, true);
22168621f407SFrançois Tigeot 		if (ret)
22178621f407SFrançois Tigeot 			goto err_unpin;
2218aee94f86SFrançois Tigeot 
22198621f407SFrançois Tigeot 		addr = i915_gem_object_pin_map(obj);
22208621f407SFrançois Tigeot 		if (IS_ERR(addr)) {
22218621f407SFrançois Tigeot 			ret = PTR_ERR(addr);
22228621f407SFrançois Tigeot 			goto err_unpin;
2223aee94f86SFrançois Tigeot 		}
2224aee94f86SFrançois Tigeot 	} else {
2225c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
2226c0e85e96SFrançois Tigeot 					    flags | PIN_MAPPABLE);
22272c9916cdSFrançois Tigeot 		if (ret)
22282c9916cdSFrançois Tigeot 			return ret;
22292c9916cdSFrançois Tigeot 
22302c9916cdSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(obj, true);
22318621f407SFrançois Tigeot 		if (ret)
22328621f407SFrançois Tigeot 			goto err_unpin;
22332c9916cdSFrançois Tigeot 
2234c0e85e96SFrançois Tigeot 		/* Access through the GTT requires the device to be awake. */
2235c0e85e96SFrançois Tigeot 		assert_rpm_wakelock_held(dev_priv);
2236c0e85e96SFrançois Tigeot 
2237*1487f786SFrançois Tigeot 		addr = i915_vma_pin_iomap(i915_gem_obj_to_ggtt(obj));
2238*1487f786SFrançois Tigeot 		if (IS_ERR(addr)) {
2239*1487f786SFrançois Tigeot 			ret = PTR_ERR(addr);
22408621f407SFrançois Tigeot 			goto err_unpin;
22412c9916cdSFrançois Tigeot 		}
2242aee94f86SFrançois Tigeot 	}
22432c9916cdSFrançois Tigeot 
22448621f407SFrançois Tigeot 	ringbuf->virtual_start = addr;
2245c0e85e96SFrançois Tigeot 	ringbuf->vma = i915_gem_obj_to_ggtt(obj);
22462c9916cdSFrançois Tigeot 	return 0;
22478621f407SFrançois Tigeot 
22488621f407SFrançois Tigeot err_unpin:
22498621f407SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
22508621f407SFrançois Tigeot 	return ret;
22512c9916cdSFrançois Tigeot }
22522c9916cdSFrançois Tigeot 
2253352ff8bdSFrançois Tigeot static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
2254e3adcf8fSFrançois Tigeot {
225524edb884SFrançois Tigeot 	drm_gem_object_unreference(&ringbuf->obj->base);
225624edb884SFrançois Tigeot 	ringbuf->obj = NULL;
225724edb884SFrançois Tigeot }
225824edb884SFrançois Tigeot 
2259352ff8bdSFrançois Tigeot static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
226024edb884SFrançois Tigeot 				      struct intel_ringbuffer *ringbuf)
226124edb884SFrançois Tigeot {
2262e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
2263e3adcf8fSFrançois Tigeot 
2264a2fdbec6SFrançois Tigeot 	obj = NULL;
2265a2fdbec6SFrançois Tigeot 	if (!HAS_LLC(dev))
2266ba55f2f5SFrançois Tigeot 		obj = i915_gem_object_create_stolen(dev, ringbuf->size);
2267a2fdbec6SFrançois Tigeot 	if (obj == NULL)
2268*1487f786SFrançois Tigeot 		obj = i915_gem_object_create(dev, ringbuf->size);
2269*1487f786SFrançois Tigeot 	if (IS_ERR(obj))
2270*1487f786SFrançois Tigeot 		return PTR_ERR(obj);
2271e3adcf8fSFrançois Tigeot 
227224edb884SFrançois Tigeot 	/* mark ring buffers as read-only from GPU side by default */
227324edb884SFrançois Tigeot 	obj->gt_ro = 1;
227424edb884SFrançois Tigeot 
2275ba55f2f5SFrançois Tigeot 	ringbuf->obj = obj;
2276ba55f2f5SFrançois Tigeot 
22772c9916cdSFrançois Tigeot 	return 0;
2278ba55f2f5SFrançois Tigeot }
2279ba55f2f5SFrançois Tigeot 
2280352ff8bdSFrançois Tigeot struct intel_ringbuffer *
2281352ff8bdSFrançois Tigeot intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
2282352ff8bdSFrançois Tigeot {
2283352ff8bdSFrançois Tigeot 	struct intel_ringbuffer *ring;
2284352ff8bdSFrançois Tigeot 	int ret;
2285352ff8bdSFrançois Tigeot 
2286352ff8bdSFrançois Tigeot 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
2287aee94f86SFrançois Tigeot 	if (ring == NULL) {
2288aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
2289aee94f86SFrançois Tigeot 				 engine->name);
2290352ff8bdSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
2291aee94f86SFrançois Tigeot 	}
2292352ff8bdSFrançois Tigeot 
22938621f407SFrançois Tigeot 	ring->engine = engine;
2294aee94f86SFrançois Tigeot 	list_add(&ring->link, &engine->buffers);
2295352ff8bdSFrançois Tigeot 
2296352ff8bdSFrançois Tigeot 	ring->size = size;
2297352ff8bdSFrançois Tigeot 	/* Workaround an erratum on the i830 which causes a hang if
2298352ff8bdSFrançois Tigeot 	 * the TAIL pointer points to within the last 2 cachelines
2299352ff8bdSFrançois Tigeot 	 * of the buffer.
2300352ff8bdSFrançois Tigeot 	 */
2301352ff8bdSFrançois Tigeot 	ring->effective_size = size;
2302*1487f786SFrançois Tigeot 	if (IS_I830(engine->i915) || IS_845G(engine->i915))
2303352ff8bdSFrançois Tigeot 		ring->effective_size -= 2 * CACHELINE_BYTES;
2304352ff8bdSFrançois Tigeot 
2305352ff8bdSFrançois Tigeot 	ring->last_retired_head = -1;
2306352ff8bdSFrançois Tigeot 	intel_ring_update_space(ring);
2307352ff8bdSFrançois Tigeot 
2308*1487f786SFrançois Tigeot 	ret = intel_alloc_ringbuffer_obj(engine->i915->dev, ring);
2309352ff8bdSFrançois Tigeot 	if (ret) {
2310aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
2311352ff8bdSFrançois Tigeot 				 engine->name, ret);
2312aee94f86SFrançois Tigeot 		list_del(&ring->link);
2313352ff8bdSFrançois Tigeot 		kfree(ring);
2314352ff8bdSFrançois Tigeot 		return ERR_PTR(ret);
2315352ff8bdSFrançois Tigeot 	}
2316352ff8bdSFrançois Tigeot 
2317352ff8bdSFrançois Tigeot 	return ring;
2318352ff8bdSFrançois Tigeot }
2319352ff8bdSFrançois Tigeot 
2320352ff8bdSFrançois Tigeot void
2321352ff8bdSFrançois Tigeot intel_ringbuffer_free(struct intel_ringbuffer *ring)
2322352ff8bdSFrançois Tigeot {
2323352ff8bdSFrançois Tigeot 	intel_destroy_ringbuffer_obj(ring);
2324aee94f86SFrançois Tigeot 	list_del(&ring->link);
2325352ff8bdSFrançois Tigeot 	kfree(ring);
2326352ff8bdSFrançois Tigeot }
2327352ff8bdSFrançois Tigeot 
2328*1487f786SFrançois Tigeot static int intel_ring_context_pin(struct i915_gem_context *ctx,
2329*1487f786SFrançois Tigeot 				  struct intel_engine_cs *engine)
2330*1487f786SFrançois Tigeot {
2331*1487f786SFrançois Tigeot 	struct intel_context *ce = &ctx->engine[engine->id];
2332*1487f786SFrançois Tigeot 	int ret;
2333*1487f786SFrançois Tigeot 
2334*1487f786SFrançois Tigeot 	lockdep_assert_held(&ctx->i915->dev->struct_mutex);
2335*1487f786SFrançois Tigeot 
2336*1487f786SFrançois Tigeot 	if (ce->pin_count++)
2337*1487f786SFrançois Tigeot 		return 0;
2338*1487f786SFrançois Tigeot 
2339*1487f786SFrançois Tigeot 	if (ce->state) {
2340*1487f786SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(ce->state, ctx->ggtt_alignment, 0);
2341*1487f786SFrançois Tigeot 		if (ret)
2342*1487f786SFrançois Tigeot 			goto error;
2343*1487f786SFrançois Tigeot 	}
2344*1487f786SFrançois Tigeot 
2345*1487f786SFrançois Tigeot 	/* The kernel context is only used as a placeholder for flushing the
2346*1487f786SFrançois Tigeot 	 * active context. It is never used for submitting user rendering and
2347*1487f786SFrançois Tigeot 	 * as such never requires the golden render context, and so we can skip
2348*1487f786SFrançois Tigeot 	 * emitting it when we switch to the kernel context. This is required
2349*1487f786SFrançois Tigeot 	 * as during eviction we cannot allocate and pin the renderstate in
2350*1487f786SFrançois Tigeot 	 * order to initialise the context.
2351*1487f786SFrançois Tigeot 	 */
2352*1487f786SFrançois Tigeot 	if (ctx == ctx->i915->kernel_context)
2353*1487f786SFrançois Tigeot 		ce->initialised = true;
2354*1487f786SFrançois Tigeot 
2355*1487f786SFrançois Tigeot 	i915_gem_context_reference(ctx);
2356*1487f786SFrançois Tigeot 	return 0;
2357*1487f786SFrançois Tigeot 
2358*1487f786SFrançois Tigeot error:
2359*1487f786SFrançois Tigeot 	ce->pin_count = 0;
2360*1487f786SFrançois Tigeot 	return ret;
2361*1487f786SFrançois Tigeot }
2362*1487f786SFrançois Tigeot 
2363*1487f786SFrançois Tigeot static void intel_ring_context_unpin(struct i915_gem_context *ctx,
2364*1487f786SFrançois Tigeot 				     struct intel_engine_cs *engine)
2365*1487f786SFrançois Tigeot {
2366*1487f786SFrançois Tigeot 	struct intel_context *ce = &ctx->engine[engine->id];
2367*1487f786SFrançois Tigeot 
2368*1487f786SFrançois Tigeot 	lockdep_assert_held(&ctx->i915->dev->struct_mutex);
2369*1487f786SFrançois Tigeot 
2370*1487f786SFrançois Tigeot 	if (--ce->pin_count)
2371*1487f786SFrançois Tigeot 		return;
2372*1487f786SFrançois Tigeot 
2373*1487f786SFrançois Tigeot 	if (ce->state)
2374*1487f786SFrançois Tigeot 		i915_gem_object_ggtt_unpin(ce->state);
2375*1487f786SFrançois Tigeot 
2376*1487f786SFrançois Tigeot 	i915_gem_context_unreference(ctx);
2377*1487f786SFrançois Tigeot }
2378*1487f786SFrançois Tigeot 
2379ba55f2f5SFrançois Tigeot static int intel_init_ring_buffer(struct drm_device *dev,
23808621f407SFrançois Tigeot 				  struct intel_engine_cs *engine)
2381ba55f2f5SFrançois Tigeot {
2382*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
23832c9916cdSFrançois Tigeot 	struct intel_ringbuffer *ringbuf;
2384ba55f2f5SFrançois Tigeot 	int ret;
2385ba55f2f5SFrançois Tigeot 
23868621f407SFrançois Tigeot 	WARN_ON(engine->buffer);
23872c9916cdSFrançois Tigeot 
2388*1487f786SFrançois Tigeot 	engine->i915 = dev_priv;
23898621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->active_list);
23908621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->request_list);
23918621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->execlist_queue);
23928621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->buffers);
23938621f407SFrançois Tigeot 	i915_gem_batch_pool_init(dev, &engine->batch_pool);
23948621f407SFrançois Tigeot 	memset(engine->semaphore.sync_seqno, 0,
23958621f407SFrançois Tigeot 	       sizeof(engine->semaphore.sync_seqno));
2396ba55f2f5SFrançois Tigeot 
23978621f407SFrançois Tigeot 	init_waitqueue_head(&engine->irq_queue);
2398ba55f2f5SFrançois Tigeot 
2399*1487f786SFrançois Tigeot 	/* We may need to do things with the shrinker which
2400*1487f786SFrançois Tigeot 	 * require us to immediately switch back to the default
2401*1487f786SFrançois Tigeot 	 * context. This can cause a problem as pinning the
2402*1487f786SFrançois Tigeot 	 * default context also requires GTT space which may not
2403*1487f786SFrançois Tigeot 	 * be available. To avoid this we always pin the default
2404*1487f786SFrançois Tigeot 	 * context.
2405*1487f786SFrançois Tigeot 	 */
2406*1487f786SFrançois Tigeot 	ret = intel_ring_context_pin(dev_priv->kernel_context, engine);
2407*1487f786SFrançois Tigeot 	if (ret)
2408*1487f786SFrançois Tigeot 		goto error;
2409*1487f786SFrançois Tigeot 
24108621f407SFrançois Tigeot 	ringbuf = intel_engine_create_ringbuffer(engine, 32 * PAGE_SIZE);
2411aee94f86SFrançois Tigeot 	if (IS_ERR(ringbuf)) {
2412aee94f86SFrançois Tigeot 		ret = PTR_ERR(ringbuf);
2413aee94f86SFrançois Tigeot 		goto error;
2414aee94f86SFrançois Tigeot 	}
24158621f407SFrançois Tigeot 	engine->buffer = ringbuf;
2416352ff8bdSFrançois Tigeot 
2417*1487f786SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev_priv)) {
24188621f407SFrançois Tigeot 		ret = init_status_page(engine);
2419e3adcf8fSFrançois Tigeot 		if (ret)
2420ba55f2f5SFrançois Tigeot 			goto error;
2421ba55f2f5SFrançois Tigeot 	} else {
24228621f407SFrançois Tigeot 		WARN_ON(engine->id != RCS);
24238621f407SFrançois Tigeot 		ret = init_phys_status_page(engine);
2424ba55f2f5SFrançois Tigeot 		if (ret)
2425ba55f2f5SFrançois Tigeot 			goto error;
2426ba55f2f5SFrançois Tigeot 	}
2427ba55f2f5SFrançois Tigeot 
2428*1487f786SFrançois Tigeot 	ret = intel_pin_and_map_ringbuffer_obj(dev_priv, ringbuf);
24292c9916cdSFrançois Tigeot 	if (ret) {
24302c9916cdSFrançois Tigeot 		DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
24318621f407SFrançois Tigeot 				engine->name, ret);
24322c9916cdSFrançois Tigeot 		intel_destroy_ringbuffer_obj(ringbuf);
2433ba55f2f5SFrançois Tigeot 		goto error;
2434ba55f2f5SFrançois Tigeot 	}
2435e3adcf8fSFrançois Tigeot 
24368621f407SFrançois Tigeot 	ret = i915_cmd_parser_init_ring(engine);
2437ba55f2f5SFrançois Tigeot 	if (ret)
2438ba55f2f5SFrançois Tigeot 		goto error;
2439ba55f2f5SFrançois Tigeot 
2440e3adcf8fSFrançois Tigeot 	return 0;
2441e3adcf8fSFrançois Tigeot 
2442ba55f2f5SFrançois Tigeot error:
24438621f407SFrançois Tigeot 	intel_cleanup_engine(engine);
2444e3adcf8fSFrançois Tigeot 	return ret;
2445e3adcf8fSFrançois Tigeot }
2446e3adcf8fSFrançois Tigeot 
24478621f407SFrançois Tigeot void intel_cleanup_engine(struct intel_engine_cs *engine)
2448e3adcf8fSFrançois Tigeot {
24492c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv;
2450e3adcf8fSFrançois Tigeot 
24518621f407SFrançois Tigeot 	if (!intel_engine_initialized(engine))
2452e3adcf8fSFrançois Tigeot 		return;
2453e3adcf8fSFrançois Tigeot 
2454*1487f786SFrançois Tigeot 	dev_priv = engine->i915;
24552c9916cdSFrançois Tigeot 
24568621f407SFrançois Tigeot 	if (engine->buffer) {
24578621f407SFrançois Tigeot 		intel_stop_engine(engine);
2458*1487f786SFrançois Tigeot 		WARN_ON(!IS_GEN2(dev_priv) && (I915_READ_MODE(engine) & MODE_IDLE) == 0);
2459b030f26bSFrançois Tigeot 
24608621f407SFrançois Tigeot 		intel_unpin_ringbuffer_obj(engine->buffer);
24618621f407SFrançois Tigeot 		intel_ringbuffer_free(engine->buffer);
24628621f407SFrançois Tigeot 		engine->buffer = NULL;
2463aee94f86SFrançois Tigeot 	}
2464e3adcf8fSFrançois Tigeot 
24658621f407SFrançois Tigeot 	if (engine->cleanup)
24668621f407SFrançois Tigeot 		engine->cleanup(engine);
2467e3adcf8fSFrançois Tigeot 
2468*1487f786SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev_priv)) {
24698621f407SFrançois Tigeot 		cleanup_status_page(engine);
2470c0e85e96SFrançois Tigeot 	} else {
24718621f407SFrançois Tigeot 		WARN_ON(engine->id != RCS);
24728621f407SFrançois Tigeot 		cleanup_phys_status_page(engine);
2473c0e85e96SFrançois Tigeot 	}
2474ba55f2f5SFrançois Tigeot 
24758621f407SFrançois Tigeot 	i915_cmd_parser_fini_ring(engine);
24768621f407SFrançois Tigeot 	i915_gem_batch_pool_fini(&engine->batch_pool);
2477*1487f786SFrançois Tigeot 
2478*1487f786SFrançois Tigeot 	intel_ring_context_unpin(dev_priv->kernel_context, engine);
2479*1487f786SFrançois Tigeot 
2480*1487f786SFrançois Tigeot 	engine->i915 = NULL;
2481e3adcf8fSFrançois Tigeot }
2482e3adcf8fSFrançois Tigeot 
24838621f407SFrançois Tigeot int intel_engine_idle(struct intel_engine_cs *engine)
2484b030f26bSFrançois Tigeot {
24852c9916cdSFrançois Tigeot 	struct drm_i915_gem_request *req;
2486b5c29a34SFrançois Tigeot 
2487b5c29a34SFrançois Tigeot 	/* Wait upon the last request to be completed */
24888621f407SFrançois Tigeot 	if (list_empty(&engine->request_list))
2489b5c29a34SFrançois Tigeot 		return 0;
2490b5c29a34SFrançois Tigeot 
24918621f407SFrançois Tigeot 	req = list_entry(engine->request_list.prev,
2492b5c29a34SFrançois Tigeot 			 struct drm_i915_gem_request,
24932c9916cdSFrançois Tigeot 			 list);
2494b5c29a34SFrançois Tigeot 
249519c468b4SFrançois Tigeot 	/* Make sure we do not trigger any retires */
249619c468b4SFrançois Tigeot 	return __i915_wait_request(req,
24978621f407SFrançois Tigeot 				   req->i915->mm.interruptible,
249819c468b4SFrançois Tigeot 				   NULL, NULL);
2499b5c29a34SFrançois Tigeot }
2500b5c29a34SFrançois Tigeot 
250119c468b4SFrançois Tigeot int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
2502b5c29a34SFrançois Tigeot {
2503*1487f786SFrançois Tigeot 	int ret;
25049edbd4a0SFrançois Tigeot 
2505*1487f786SFrançois Tigeot 	/* Flush enough space to reduce the likelihood of waiting after
2506*1487f786SFrançois Tigeot 	 * we start building the request - in which case we will just
2507*1487f786SFrançois Tigeot 	 * have to repeat work.
2508a05eeebfSFrançois Tigeot 	 */
2509*1487f786SFrançois Tigeot 	request->reserved_space += LEGACY_REQUEST_SIZE;
2510a2fdbec6SFrançois Tigeot 
2511*1487f786SFrançois Tigeot 	request->ringbuf = request->engine->buffer;
2512a2fdbec6SFrançois Tigeot 
2513*1487f786SFrançois Tigeot 	ret = intel_ring_begin(request, 0);
2514*1487f786SFrançois Tigeot 	if (ret)
2515*1487f786SFrançois Tigeot 		return ret;
2516a05eeebfSFrançois Tigeot 
2517*1487f786SFrançois Tigeot 	request->reserved_space -= LEGACY_REQUEST_SIZE;
2518*1487f786SFrançois Tigeot 	return 0;
2519a05eeebfSFrançois Tigeot }
2520a05eeebfSFrançois Tigeot 
25218621f407SFrançois Tigeot static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
2522a05eeebfSFrançois Tigeot {
25238621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = req->ringbuf;
25248621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
25258621f407SFrançois Tigeot 	struct drm_i915_gem_request *target;
25268621f407SFrançois Tigeot 
25278621f407SFrançois Tigeot 	intel_ring_update_space(ringbuf);
25288621f407SFrançois Tigeot 	if (ringbuf->space >= bytes)
25298621f407SFrançois Tigeot 		return 0;
25308621f407SFrançois Tigeot 
25318621f407SFrançois Tigeot 	/*
25328621f407SFrançois Tigeot 	 * Space is reserved in the ringbuffer for finalising the request,
25338621f407SFrançois Tigeot 	 * as that cannot be allowed to fail. During request finalisation,
25348621f407SFrançois Tigeot 	 * reserved_space is set to 0 to stop the overallocation and the
25358621f407SFrançois Tigeot 	 * assumption is that then we never need to wait (which has the
25368621f407SFrançois Tigeot 	 * risk of failing with EINTR).
25378621f407SFrançois Tigeot 	 *
25388621f407SFrançois Tigeot 	 * See also i915_gem_request_alloc() and i915_add_request().
25398621f407SFrançois Tigeot 	 */
2540*1487f786SFrançois Tigeot 	GEM_BUG_ON(!req->reserved_space);
25418621f407SFrançois Tigeot 
25428621f407SFrançois Tigeot 	list_for_each_entry(target, &engine->request_list, list) {
25438621f407SFrançois Tigeot 		unsigned space;
25448621f407SFrançois Tigeot 
25458621f407SFrançois Tigeot 		/*
25468621f407SFrançois Tigeot 		 * The request queue is per-engine, so can contain requests
25478621f407SFrançois Tigeot 		 * from multiple ringbuffers. Here, we must ignore any that
25488621f407SFrançois Tigeot 		 * aren't from the ringbuffer we're considering.
25498621f407SFrançois Tigeot 		 */
25508621f407SFrançois Tigeot 		if (target->ringbuf != ringbuf)
25518621f407SFrançois Tigeot 			continue;
25528621f407SFrançois Tigeot 
25538621f407SFrançois Tigeot 		/* Would completion of this request free enough space? */
25548621f407SFrançois Tigeot 		space = __intel_ring_space(target->postfix, ringbuf->tail,
25558621f407SFrançois Tigeot 					   ringbuf->size);
25568621f407SFrançois Tigeot 		if (space >= bytes)
25578621f407SFrançois Tigeot 			break;
25588621f407SFrançois Tigeot 	}
25598621f407SFrançois Tigeot 
25608621f407SFrançois Tigeot 	if (WARN_ON(&target->list == &engine->request_list))
25618621f407SFrançois Tigeot 		return -ENOSPC;
25628621f407SFrançois Tigeot 
25638621f407SFrançois Tigeot 	return i915_wait_request(target);
25648621f407SFrançois Tigeot }
25658621f407SFrançois Tigeot 
25668621f407SFrançois Tigeot int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords)
25678621f407SFrançois Tigeot {
25688621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = req->ringbuf;
2569a05eeebfSFrançois Tigeot 	int remain_actual = ringbuf->size - ringbuf->tail;
25708621f407SFrançois Tigeot 	int remain_usable = ringbuf->effective_size - ringbuf->tail;
25718621f407SFrançois Tigeot 	int bytes = num_dwords * sizeof(u32);
25728621f407SFrançois Tigeot 	int total_bytes, wait_bytes;
2573a05eeebfSFrançois Tigeot 	bool need_wrap = false;
2574a05eeebfSFrançois Tigeot 
2575*1487f786SFrançois Tigeot 	total_bytes = bytes + req->reserved_space;
2576a05eeebfSFrançois Tigeot 
2577a05eeebfSFrançois Tigeot 	if (unlikely(bytes > remain_usable)) {
2578a05eeebfSFrançois Tigeot 		/*
2579a05eeebfSFrançois Tigeot 		 * Not enough space for the basic request. So need to flush
2580a05eeebfSFrançois Tigeot 		 * out the remainder and then wait for base + reserved.
2581a05eeebfSFrançois Tigeot 		 */
2582a05eeebfSFrançois Tigeot 		wait_bytes = remain_actual + total_bytes;
2583a05eeebfSFrançois Tigeot 		need_wrap = true;
25848621f407SFrançois Tigeot 	} else if (unlikely(total_bytes > remain_usable)) {
2585a05eeebfSFrançois Tigeot 		/*
2586a05eeebfSFrançois Tigeot 		 * The base request will fit but the reserved space
25878621f407SFrançois Tigeot 		 * falls off the end. So we don't need an immediate wrap
2588c0e85e96SFrançois Tigeot 		 * and only need to effectively wait for the reserved
2589c0e85e96SFrançois Tigeot 		 * size space from the start of ringbuffer.
2590a05eeebfSFrançois Tigeot 		 */
2591*1487f786SFrançois Tigeot 		wait_bytes = remain_actual + req->reserved_space;
25928621f407SFrançois Tigeot 	} else {
2593a05eeebfSFrançois Tigeot 		/* No wrapping required, just waiting. */
2594a05eeebfSFrançois Tigeot 		wait_bytes = total_bytes;
2595a05eeebfSFrançois Tigeot 	}
2596a05eeebfSFrançois Tigeot 
25978621f407SFrançois Tigeot 	if (wait_bytes > ringbuf->space) {
25988621f407SFrançois Tigeot 		int ret = wait_for_space(req, wait_bytes);
2599a2fdbec6SFrançois Tigeot 		if (unlikely(ret))
2600a2fdbec6SFrançois Tigeot 			return ret;
2601a05eeebfSFrançois Tigeot 
26028621f407SFrançois Tigeot 		intel_ring_update_space(ringbuf);
26038621f407SFrançois Tigeot 		if (unlikely(ringbuf->space < wait_bytes))
26048621f407SFrançois Tigeot 			return -EAGAIN;
2605a2fdbec6SFrançois Tigeot 	}
2606a2fdbec6SFrançois Tigeot 
26078621f407SFrançois Tigeot 	if (unlikely(need_wrap)) {
26088621f407SFrançois Tigeot 		GEM_BUG_ON(remain_actual > ringbuf->space);
26098621f407SFrançois Tigeot 		GEM_BUG_ON(ringbuf->tail + remain_actual > ringbuf->size);
26108621f407SFrançois Tigeot 
26118621f407SFrançois Tigeot 		/* Fill the tail with MI_NOOP */
26128621f407SFrançois Tigeot 		memset(ringbuf->virtual_start + ringbuf->tail,
26138621f407SFrançois Tigeot 		       0, remain_actual);
26148621f407SFrançois Tigeot 		ringbuf->tail = 0;
26158621f407SFrançois Tigeot 		ringbuf->space -= remain_actual;
2616a2fdbec6SFrançois Tigeot 	}
2617a2fdbec6SFrançois Tigeot 
26188621f407SFrançois Tigeot 	ringbuf->space -= bytes;
26198621f407SFrançois Tigeot 	GEM_BUG_ON(ringbuf->space < 0);
26209edbd4a0SFrançois Tigeot 	return 0;
26219edbd4a0SFrançois Tigeot }
26229edbd4a0SFrançois Tigeot 
26239edbd4a0SFrançois Tigeot /* Align the ring tail to a cacheline boundary */
2624a05eeebfSFrançois Tigeot int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
26259edbd4a0SFrançois Tigeot {
26268621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
26278621f407SFrançois Tigeot 	int num_dwords = (engine->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
26289edbd4a0SFrançois Tigeot 	int ret;
26299edbd4a0SFrançois Tigeot 
26309edbd4a0SFrançois Tigeot 	if (num_dwords == 0)
26319edbd4a0SFrançois Tigeot 		return 0;
26329edbd4a0SFrançois Tigeot 
2633ba55f2f5SFrançois Tigeot 	num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords;
2634a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, num_dwords);
26359edbd4a0SFrançois Tigeot 	if (ret)
26369edbd4a0SFrançois Tigeot 		return ret;
26379edbd4a0SFrançois Tigeot 
26389edbd4a0SFrançois Tigeot 	while (num_dwords--)
26398621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
26409edbd4a0SFrançois Tigeot 
26418621f407SFrançois Tigeot 	intel_ring_advance(engine);
26429edbd4a0SFrançois Tigeot 
26439edbd4a0SFrançois Tigeot 	return 0;
2644e3adcf8fSFrançois Tigeot }
2645e3adcf8fSFrançois Tigeot 
26468621f407SFrançois Tigeot void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno)
2647a2fdbec6SFrançois Tigeot {
2648*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2649a2fdbec6SFrançois Tigeot 
26508621f407SFrançois Tigeot 	/* Our semaphore implementation is strictly monotonic (i.e. we proceed
26518621f407SFrançois Tigeot 	 * so long as the semaphore value in the register/page is greater
26528621f407SFrançois Tigeot 	 * than the sync value), so whenever we reset the seqno,
26538621f407SFrançois Tigeot 	 * so long as we reset the tracking semaphore value to 0, it will
26548621f407SFrançois Tigeot 	 * always be before the next request's seqno. If we don't reset
26558621f407SFrançois Tigeot 	 * the semaphore value, then when the seqno moves backwards all
26568621f407SFrançois Tigeot 	 * future waits will complete instantly (causing rendering corruption).
26578621f407SFrançois Tigeot 	 */
2658*1487f786SFrançois Tigeot 	if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) {
26598621f407SFrançois Tigeot 		I915_WRITE(RING_SYNC_0(engine->mmio_base), 0);
26608621f407SFrançois Tigeot 		I915_WRITE(RING_SYNC_1(engine->mmio_base), 0);
26618621f407SFrançois Tigeot 		if (HAS_VEBOX(dev_priv))
26628621f407SFrançois Tigeot 			I915_WRITE(RING_SYNC_2(engine->mmio_base), 0);
26638621f407SFrançois Tigeot 	}
26648621f407SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
26658621f407SFrançois Tigeot 		struct drm_i915_gem_object *obj = dev_priv->semaphore_obj;
2666f0bba3d1SFrançois Tigeot 		struct page *page = i915_gem_object_get_dirty_page(obj, 0);
2667*1487f786SFrançois Tigeot 		void *semaphores = kmap(page);
26688621f407SFrançois Tigeot 		memset(semaphores + GEN8_SEMAPHORE_OFFSET(engine->id, 0),
26698621f407SFrançois Tigeot 		       0, I915_NUM_ENGINES * gen8_semaphore_seqno_size);
26708621f407SFrançois Tigeot 		kunmap(page);
26718621f407SFrançois Tigeot 	}
26728621f407SFrançois Tigeot 	memset(engine->semaphore.sync_seqno, 0,
26738621f407SFrançois Tigeot 	       sizeof(engine->semaphore.sync_seqno));
26748621f407SFrançois Tigeot 
26758621f407SFrançois Tigeot 	engine->set_seqno(engine, seqno);
26768621f407SFrançois Tigeot 	engine->last_submitted_seqno = seqno;
26778621f407SFrançois Tigeot 
26788621f407SFrançois Tigeot 	engine->hangcheck.seqno = seqno;
2679e3adcf8fSFrançois Tigeot }
2680e3adcf8fSFrançois Tigeot 
26818621f407SFrançois Tigeot static void gen6_bsd_ring_write_tail(struct intel_engine_cs *engine,
2682f4e1c372SFrançois Tigeot 				     u32 value)
2683e3adcf8fSFrançois Tigeot {
2684*1487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2685*1487f786SFrançois Tigeot 
2686*1487f786SFrançois Tigeot 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
2687e3adcf8fSFrançois Tigeot 
2688e3adcf8fSFrançois Tigeot        /* Every tail move must follow the sequence below */
2689f4e1c372SFrançois Tigeot 
2690f4e1c372SFrançois Tigeot 	/* Disable notification that the ring is IDLE. The GT
2691f4e1c372SFrançois Tigeot 	 * will then assume that it is busy and bring it out of rc6.
2692f4e1c372SFrançois Tigeot 	 */
2693*1487f786SFrançois Tigeot 	I915_WRITE_FW(GEN6_BSD_SLEEP_PSMI_CONTROL,
2694f4e1c372SFrançois Tigeot 		      _MASKED_BIT_ENABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2695e3adcf8fSFrançois Tigeot 
2696f4e1c372SFrançois Tigeot 	/* Clear the context id. Here be magic! */
2697*1487f786SFrançois Tigeot 	I915_WRITE64_FW(GEN6_BSD_RNCID, 0x0);
2698e3adcf8fSFrançois Tigeot 
2699f4e1c372SFrançois Tigeot 	/* Wait for the ring not to be idle, i.e. for it to wake up. */
2700*1487f786SFrançois Tigeot 	if (intel_wait_for_register_fw(dev_priv,
2701*1487f786SFrançois Tigeot 				       GEN6_BSD_SLEEP_PSMI_CONTROL,
2702*1487f786SFrançois Tigeot 				       GEN6_BSD_SLEEP_INDICATOR,
2703*1487f786SFrançois Tigeot 				       0,
2704f4e1c372SFrançois Tigeot 				       50))
2705f4e1c372SFrançois Tigeot 		DRM_ERROR("timed out waiting for the BSD ring to wake up\n");
2706f4e1c372SFrançois Tigeot 
2707f4e1c372SFrançois Tigeot 	/* Now that the ring is fully powered up, update the tail */
2708*1487f786SFrançois Tigeot 	I915_WRITE_FW(RING_TAIL(engine->mmio_base), value);
2709*1487f786SFrançois Tigeot 	POSTING_READ_FW(RING_TAIL(engine->mmio_base));
2710f4e1c372SFrançois Tigeot 
2711f4e1c372SFrançois Tigeot 	/* Let the ring send IDLE messages to the GT again,
2712f4e1c372SFrançois Tigeot 	 * and so let it sleep to conserve power when idle.
2713f4e1c372SFrançois Tigeot 	 */
2714*1487f786SFrançois Tigeot 	I915_WRITE_FW(GEN6_BSD_SLEEP_PSMI_CONTROL,
2715f4e1c372SFrançois Tigeot 		      _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2716*1487f786SFrançois Tigeot 
2717*1487f786SFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
2718e3adcf8fSFrançois Tigeot }
2719e3adcf8fSFrançois Tigeot 
2720a05eeebfSFrançois Tigeot static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req,
2721b5c29a34SFrançois Tigeot 			       u32 invalidate, u32 flush)
2722e3adcf8fSFrançois Tigeot {
27238621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2724e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2725e3adcf8fSFrançois Tigeot 	int ret;
2726e3adcf8fSFrançois Tigeot 
2727a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2728e3adcf8fSFrançois Tigeot 	if (ret)
2729e3adcf8fSFrançois Tigeot 		return ret;
2730e3adcf8fSFrançois Tigeot 
2731e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
2732*1487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8)
27339edbd4a0SFrançois Tigeot 		cmd += 1;
27342c9916cdSFrançois Tigeot 
27352c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
27362c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
27372c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
27382c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
27392c9916cdSFrançois Tigeot 	 */
27402c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
27412c9916cdSFrançois Tigeot 
2742b5c29a34SFrançois Tigeot 	/*
2743b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.5 - video engine command streamer:
2744b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2745b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2746b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2747b5c29a34SFrançois Tigeot 	 */
2748e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_GPU_DOMAINS)
27492c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
27502c9916cdSFrançois Tigeot 
27518621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
27528621f407SFrançois Tigeot 	intel_ring_emit(engine,
27538621f407SFrançois Tigeot 			I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
2754*1487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8) {
27558621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* upper addr */
27568621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* value */
27579edbd4a0SFrançois Tigeot 	} else  {
27588621f407SFrançois Tigeot 		intel_ring_emit(engine, 0);
27598621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
27609edbd4a0SFrançois Tigeot 	}
27618621f407SFrançois Tigeot 	intel_ring_advance(engine);
27629edbd4a0SFrançois Tigeot 	return 0;
27639edbd4a0SFrançois Tigeot }
27649edbd4a0SFrançois Tigeot 
27659edbd4a0SFrançois Tigeot static int
2766a05eeebfSFrançois Tigeot gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2767ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2768477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
27699edbd4a0SFrançois Tigeot {
27708621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
27718621f407SFrançois Tigeot 	bool ppgtt = USES_PPGTT(engine->dev) &&
2772477eb7f9SFrançois Tigeot 			!(dispatch_flags & I915_DISPATCH_SECURE);
27739edbd4a0SFrançois Tigeot 	int ret;
27749edbd4a0SFrançois Tigeot 
2775a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
27769edbd4a0SFrançois Tigeot 	if (ret)
27779edbd4a0SFrançois Tigeot 		return ret;
27789edbd4a0SFrançois Tigeot 
27799edbd4a0SFrançois Tigeot 	/* FIXME(BDW): Address space and security selectors. */
27808621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) |
2781a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2782a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
27838621f407SFrançois Tigeot 	intel_ring_emit(engine, lower_32_bits(offset));
27848621f407SFrançois Tigeot 	intel_ring_emit(engine, upper_32_bits(offset));
27858621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
27868621f407SFrançois Tigeot 	intel_ring_advance(engine);
27879edbd4a0SFrançois Tigeot 
2788e3adcf8fSFrançois Tigeot 	return 0;
2789e3adcf8fSFrançois Tigeot }
2790e3adcf8fSFrançois Tigeot 
2791e3adcf8fSFrançois Tigeot static int
2792a05eeebfSFrançois Tigeot hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2793ba55f2f5SFrançois Tigeot 			     u64 offset, u32 len,
2794477eb7f9SFrançois Tigeot 			     unsigned dispatch_flags)
2795e3adcf8fSFrançois Tigeot {
27968621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2797e3adcf8fSFrançois Tigeot 	int ret;
2798e3adcf8fSFrançois Tigeot 
2799a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2800e3adcf8fSFrançois Tigeot 	if (ret)
2801e3adcf8fSFrançois Tigeot 		return ret;
2802e3adcf8fSFrançois Tigeot 
28038621f407SFrançois Tigeot 	intel_ring_emit(engine,
28041b13d190SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2805477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2806a05eeebfSFrançois Tigeot 			 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) |
2807a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2808a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
2809b5c29a34SFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
28108621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
28118621f407SFrançois Tigeot 	intel_ring_advance(engine);
2812b5c29a34SFrançois Tigeot 
2813b5c29a34SFrançois Tigeot 	return 0;
2814b5c29a34SFrançois Tigeot }
2815b5c29a34SFrançois Tigeot 
2816b5c29a34SFrançois Tigeot static int
2817a05eeebfSFrançois Tigeot gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2818ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2819477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
2820b5c29a34SFrançois Tigeot {
28218621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2822b5c29a34SFrançois Tigeot 	int ret;
2823b5c29a34SFrançois Tigeot 
2824a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2825b5c29a34SFrançois Tigeot 	if (ret)
2826b5c29a34SFrançois Tigeot 		return ret;
2827b5c29a34SFrançois Tigeot 
28288621f407SFrançois Tigeot 	intel_ring_emit(engine,
2829b5c29a34SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2830477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2831477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
2832e3adcf8fSFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
28338621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
28348621f407SFrançois Tigeot 	intel_ring_advance(engine);
2835e3adcf8fSFrançois Tigeot 
2836e3adcf8fSFrançois Tigeot 	return 0;
2837e3adcf8fSFrançois Tigeot }
2838e3adcf8fSFrançois Tigeot 
2839e3adcf8fSFrançois Tigeot /* Blitter support (SandyBridge+) */
2840e3adcf8fSFrançois Tigeot 
2841a05eeebfSFrançois Tigeot static int gen6_ring_flush(struct drm_i915_gem_request *req,
2842b5c29a34SFrançois Tigeot 			   u32 invalidate, u32 flush)
2843e3adcf8fSFrançois Tigeot {
28448621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2845e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2846e3adcf8fSFrançois Tigeot 	int ret;
2847e3adcf8fSFrançois Tigeot 
2848a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2849e3adcf8fSFrançois Tigeot 	if (ret)
2850e3adcf8fSFrançois Tigeot 		return ret;
2851e3adcf8fSFrançois Tigeot 
2852e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
2853*1487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8)
28549edbd4a0SFrançois Tigeot 		cmd += 1;
28552c9916cdSFrançois Tigeot 
28562c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
28572c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
28582c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
28592c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
28602c9916cdSFrançois Tigeot 	 */
28612c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
28622c9916cdSFrançois Tigeot 
2863b5c29a34SFrançois Tigeot 	/*
2864b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.3 - blitter engine command streamer:
2865b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2866b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2867b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2868b5c29a34SFrançois Tigeot 	 */
2869e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_DOMAIN_RENDER)
28702c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB;
28718621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
28728621f407SFrançois Tigeot 	intel_ring_emit(engine,
28738621f407SFrançois Tigeot 			I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
2874*1487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8) {
28758621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* upper addr */
28768621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* value */
28779edbd4a0SFrançois Tigeot 	} else  {
28788621f407SFrançois Tigeot 		intel_ring_emit(engine, 0);
28798621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
28809edbd4a0SFrançois Tigeot 	}
28818621f407SFrançois Tigeot 	intel_ring_advance(engine);
28825d0b1887SFrançois Tigeot 
2883e3adcf8fSFrançois Tigeot 	return 0;
2884e3adcf8fSFrançois Tigeot }
2885e3adcf8fSFrançois Tigeot 
2886*1487f786SFrançois Tigeot static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv,
2887*1487f786SFrançois Tigeot 				       struct intel_engine_cs *engine)
2888*1487f786SFrançois Tigeot {
2889*1487f786SFrançois Tigeot 	struct drm_i915_gem_object *obj;
2890*1487f786SFrançois Tigeot 	int ret, i;
2891*1487f786SFrançois Tigeot 
2892*1487f786SFrançois Tigeot 	if (!i915_semaphore_is_enabled(dev_priv))
2893*1487f786SFrançois Tigeot 		return;
2894*1487f786SFrançois Tigeot 
2895*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8 && !dev_priv->semaphore_obj) {
2896*1487f786SFrançois Tigeot 		obj = i915_gem_object_create(dev_priv->dev, 4096);
2897*1487f786SFrançois Tigeot 		if (IS_ERR(obj)) {
2898*1487f786SFrançois Tigeot 			DRM_ERROR("Failed to allocate semaphore bo. Disabling semaphores\n");
2899*1487f786SFrançois Tigeot 			i915.semaphores = 0;
2900*1487f786SFrançois Tigeot 		} else {
2901*1487f786SFrançois Tigeot 			i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
2902*1487f786SFrançois Tigeot 			ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_NONBLOCK);
2903*1487f786SFrançois Tigeot 			if (ret != 0) {
2904*1487f786SFrançois Tigeot 				drm_gem_object_unreference(&obj->base);
2905*1487f786SFrançois Tigeot 				DRM_ERROR("Failed to pin semaphore bo. Disabling semaphores\n");
2906*1487f786SFrançois Tigeot 				i915.semaphores = 0;
2907*1487f786SFrançois Tigeot 			} else {
2908*1487f786SFrançois Tigeot 				dev_priv->semaphore_obj = obj;
2909*1487f786SFrançois Tigeot 			}
2910*1487f786SFrançois Tigeot 		}
2911*1487f786SFrançois Tigeot 	}
2912*1487f786SFrançois Tigeot 
2913*1487f786SFrançois Tigeot 	if (!i915_semaphore_is_enabled(dev_priv))
2914*1487f786SFrançois Tigeot 		return;
2915*1487f786SFrançois Tigeot 
2916*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
2917*1487f786SFrançois Tigeot 		u64 offset = i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj);
2918*1487f786SFrançois Tigeot 
2919*1487f786SFrançois Tigeot 		engine->semaphore.sync_to = gen8_ring_sync;
2920*1487f786SFrançois Tigeot 		engine->semaphore.signal = gen8_xcs_signal;
2921*1487f786SFrançois Tigeot 
2922*1487f786SFrançois Tigeot 		for (i = 0; i < I915_NUM_ENGINES; i++) {
2923*1487f786SFrançois Tigeot 			u64 ring_offset;
2924*1487f786SFrançois Tigeot 
2925*1487f786SFrançois Tigeot 			if (i != engine->id)
2926*1487f786SFrançois Tigeot 				ring_offset = offset + GEN8_SEMAPHORE_OFFSET(engine->id, i);
2927*1487f786SFrançois Tigeot 			else
2928*1487f786SFrançois Tigeot 				ring_offset = MI_SEMAPHORE_SYNC_INVALID;
2929*1487f786SFrançois Tigeot 
2930*1487f786SFrançois Tigeot 			engine->semaphore.signal_ggtt[i] = ring_offset;
2931*1487f786SFrançois Tigeot 		}
2932*1487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 6) {
2933*1487f786SFrançois Tigeot 		engine->semaphore.sync_to = gen6_ring_sync;
2934*1487f786SFrançois Tigeot 		engine->semaphore.signal = gen6_signal;
2935*1487f786SFrançois Tigeot 
2936*1487f786SFrançois Tigeot 		/*
2937*1487f786SFrançois Tigeot 		 * The current semaphore is only applied on pre-gen8
2938*1487f786SFrançois Tigeot 		 * platform.  And there is no VCS2 ring on the pre-gen8
2939*1487f786SFrançois Tigeot 		 * platform. So the semaphore between RCS and VCS2 is
2940*1487f786SFrançois Tigeot 		 * initialized as INVALID.  Gen8 will initialize the
2941*1487f786SFrançois Tigeot 		 * sema between VCS2 and RCS later.
2942*1487f786SFrançois Tigeot 		 */
2943*1487f786SFrançois Tigeot 		for (i = 0; i < I915_NUM_ENGINES; i++) {
2944*1487f786SFrançois Tigeot 			static const struct {
2945*1487f786SFrançois Tigeot 				u32 wait_mbox;
2946*1487f786SFrançois Tigeot 				i915_reg_t mbox_reg;
2947*1487f786SFrançois Tigeot 			} sem_data[I915_NUM_ENGINES][I915_NUM_ENGINES] = {
2948*1487f786SFrançois Tigeot 				[RCS] = {
2949*1487f786SFrançois Tigeot 					[VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RV,  .mbox_reg = GEN6_VRSYNC },
2950*1487f786SFrançois Tigeot 					[BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RB,  .mbox_reg = GEN6_BRSYNC },
2951*1487f786SFrançois Tigeot 					[VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_RVE, .mbox_reg = GEN6_VERSYNC },
2952*1487f786SFrançois Tigeot 				},
2953*1487f786SFrançois Tigeot 				[VCS] = {
2954*1487f786SFrançois Tigeot 					[RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VR,  .mbox_reg = GEN6_RVSYNC },
2955*1487f786SFrançois Tigeot 					[BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VB,  .mbox_reg = GEN6_BVSYNC },
2956*1487f786SFrançois Tigeot 					[VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_VVE, .mbox_reg = GEN6_VEVSYNC },
2957*1487f786SFrançois Tigeot 				},
2958*1487f786SFrançois Tigeot 				[BCS] = {
2959*1487f786SFrançois Tigeot 					[RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BR,  .mbox_reg = GEN6_RBSYNC },
2960*1487f786SFrançois Tigeot 					[VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BV,  .mbox_reg = GEN6_VBSYNC },
2961*1487f786SFrançois Tigeot 					[VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_BVE, .mbox_reg = GEN6_VEBSYNC },
2962*1487f786SFrançois Tigeot 				},
2963*1487f786SFrançois Tigeot 				[VECS] = {
2964*1487f786SFrançois Tigeot 					[RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VER, .mbox_reg = GEN6_RVESYNC },
2965*1487f786SFrançois Tigeot 					[VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEV, .mbox_reg = GEN6_VVESYNC },
2966*1487f786SFrançois Tigeot 					[BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEB, .mbox_reg = GEN6_BVESYNC },
2967*1487f786SFrançois Tigeot 				},
2968*1487f786SFrançois Tigeot 			};
2969*1487f786SFrançois Tigeot 			u32 wait_mbox;
2970*1487f786SFrançois Tigeot 			i915_reg_t mbox_reg;
2971*1487f786SFrançois Tigeot 
2972*1487f786SFrançois Tigeot 			if (i == engine->id || i == VCS2) {
2973*1487f786SFrançois Tigeot 				wait_mbox = MI_SEMAPHORE_SYNC_INVALID;
2974*1487f786SFrançois Tigeot 				mbox_reg = GEN6_NOSYNC;
2975*1487f786SFrançois Tigeot 			} else {
2976*1487f786SFrançois Tigeot 				wait_mbox = sem_data[engine->id][i].wait_mbox;
2977*1487f786SFrançois Tigeot 				mbox_reg = sem_data[engine->id][i].mbox_reg;
2978*1487f786SFrançois Tigeot 			}
2979*1487f786SFrançois Tigeot 
2980*1487f786SFrançois Tigeot 			engine->semaphore.mbox.wait[i] = wait_mbox;
2981*1487f786SFrançois Tigeot 			engine->semaphore.mbox.signal[i] = mbox_reg;
2982*1487f786SFrançois Tigeot 		}
2983*1487f786SFrançois Tigeot 	}
2984*1487f786SFrançois Tigeot }
2985*1487f786SFrançois Tigeot 
2986*1487f786SFrançois Tigeot static void intel_ring_init_irq(struct drm_i915_private *dev_priv,
2987*1487f786SFrançois Tigeot 				struct intel_engine_cs *engine)
2988*1487f786SFrançois Tigeot {
2989*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
2990*1487f786SFrançois Tigeot 		engine->irq_get = gen8_ring_get_irq;
2991*1487f786SFrançois Tigeot 		engine->irq_put = gen8_ring_put_irq;
2992*1487f786SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
2993*1487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 6) {
2994*1487f786SFrançois Tigeot 		engine->irq_get = gen6_ring_get_irq;
2995*1487f786SFrançois Tigeot 		engine->irq_put = gen6_ring_put_irq;
2996*1487f786SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
2997*1487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 5) {
2998*1487f786SFrançois Tigeot 		engine->irq_get = gen5_ring_get_irq;
2999*1487f786SFrançois Tigeot 		engine->irq_put = gen5_ring_put_irq;
3000*1487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 3) {
3001*1487f786SFrançois Tigeot 		engine->irq_get = i9xx_ring_get_irq;
3002*1487f786SFrançois Tigeot 		engine->irq_put = i9xx_ring_put_irq;
3003*1487f786SFrançois Tigeot 	} else {
3004*1487f786SFrançois Tigeot 		engine->irq_get = i8xx_ring_get_irq;
3005*1487f786SFrançois Tigeot 		engine->irq_put = i8xx_ring_put_irq;
3006*1487f786SFrançois Tigeot 	}
3007*1487f786SFrançois Tigeot }
3008*1487f786SFrançois Tigeot 
3009*1487f786SFrançois Tigeot static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
3010*1487f786SFrançois Tigeot 				      struct intel_engine_cs *engine)
3011*1487f786SFrançois Tigeot {
3012*1487f786SFrançois Tigeot 	engine->init_hw = init_ring_common;
3013*1487f786SFrançois Tigeot 	engine->write_tail = ring_write_tail;
3014*1487f786SFrançois Tigeot 	engine->get_seqno = ring_get_seqno;
3015*1487f786SFrançois Tigeot 	engine->set_seqno = ring_set_seqno;
3016*1487f786SFrançois Tigeot 
3017*1487f786SFrançois Tigeot 	engine->add_request = i9xx_add_request;
3018*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6)
3019*1487f786SFrançois Tigeot 		engine->add_request = gen6_add_request;
3020*1487f786SFrançois Tigeot 
3021*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
3022*1487f786SFrançois Tigeot 		engine->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
3023*1487f786SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 6)
3024*1487f786SFrançois Tigeot 		engine->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
3025*1487f786SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 4)
3026*1487f786SFrançois Tigeot 		engine->dispatch_execbuffer = i965_dispatch_execbuffer;
3027*1487f786SFrançois Tigeot 	else if (IS_I830(dev_priv) || IS_845G(dev_priv))
3028*1487f786SFrançois Tigeot 		engine->dispatch_execbuffer = i830_dispatch_execbuffer;
3029*1487f786SFrançois Tigeot 	else
3030*1487f786SFrançois Tigeot 		engine->dispatch_execbuffer = i915_dispatch_execbuffer;
3031*1487f786SFrançois Tigeot 
3032*1487f786SFrançois Tigeot 	intel_ring_init_irq(dev_priv, engine);
3033*1487f786SFrançois Tigeot 	intel_ring_init_semaphores(dev_priv, engine);
3034*1487f786SFrançois Tigeot }
3035*1487f786SFrançois Tigeot 
3036e3adcf8fSFrançois Tigeot int intel_init_render_ring_buffer(struct drm_device *dev)
3037e3adcf8fSFrançois Tigeot {
3038ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
30398621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[RCS];
304024edb884SFrançois Tigeot 	struct drm_i915_gem_object *obj;
304124edb884SFrançois Tigeot 	int ret;
3042e3adcf8fSFrançois Tigeot 
30438621f407SFrançois Tigeot 	engine->name = "render ring";
30448621f407SFrançois Tigeot 	engine->id = RCS;
30458621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_RENDER;
30468621f407SFrançois Tigeot 	engine->hw_id = 0;
30478621f407SFrançois Tigeot 	engine->mmio_base = RENDER_RING_BASE;
3048686a02f1SFrançois Tigeot 
3049*1487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
30502c9916cdSFrançois Tigeot 
3051*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
30528621f407SFrançois Tigeot 		engine->init_context = intel_rcs_ctx_init;
3053*1487f786SFrançois Tigeot 		engine->add_request = gen8_render_add_request;
30548621f407SFrançois Tigeot 		engine->flush = gen8_render_ring_flush;
30558621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
3056*1487f786SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev_priv))
30578621f407SFrançois Tigeot 			engine->semaphore.signal = gen8_rcs_signal;
3058*1487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 6) {
30598621f407SFrançois Tigeot 		engine->init_context = intel_rcs_ctx_init;
30608621f407SFrançois Tigeot 		engine->flush = gen7_render_ring_flush;
3061*1487f786SFrançois Tigeot 		if (IS_GEN6(dev_priv))
30628621f407SFrançois Tigeot 			engine->flush = gen6_render_ring_flush;
30638621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
3064*1487f786SFrançois Tigeot 	} else if (IS_GEN5(dev_priv)) {
30658621f407SFrançois Tigeot 		engine->add_request = pc_render_add_request;
30668621f407SFrançois Tigeot 		engine->flush = gen4_render_ring_flush;
30678621f407SFrançois Tigeot 		engine->get_seqno = pc_render_get_seqno;
30688621f407SFrançois Tigeot 		engine->set_seqno = pc_render_set_seqno;
30698621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT |
30705d0b1887SFrançois Tigeot 					GT_RENDER_PIPECTL_NOTIFY_INTERRUPT;
3071686a02f1SFrançois Tigeot 	} else {
3072*1487f786SFrançois Tigeot 		if (INTEL_GEN(dev_priv) < 4)
30738621f407SFrançois Tigeot 			engine->flush = gen2_render_ring_flush;
3074686a02f1SFrançois Tigeot 		else
30758621f407SFrançois Tigeot 			engine->flush = gen4_render_ring_flush;
30768621f407SFrançois Tigeot 		engine->irq_enable_mask = I915_USER_INTERRUPT;
3077686a02f1SFrançois Tigeot 	}
307824edb884SFrançois Tigeot 
3079*1487f786SFrançois Tigeot 	if (IS_HASWELL(dev_priv))
30808621f407SFrançois Tigeot 		engine->dispatch_execbuffer = hsw_ring_dispatch_execbuffer;
3081*1487f786SFrançois Tigeot 
30828621f407SFrançois Tigeot 	engine->init_hw = init_render_ring;
30838621f407SFrançois Tigeot 	engine->cleanup = render_ring_cleanup;
3084e3adcf8fSFrançois Tigeot 
3085b5c29a34SFrançois Tigeot 	/* Workaround batchbuffer to combat CS tlb bug. */
3086*1487f786SFrançois Tigeot 	if (HAS_BROKEN_CS_TLB(dev_priv)) {
3087*1487f786SFrançois Tigeot 		obj = i915_gem_object_create(dev, I830_WA_SIZE);
3088*1487f786SFrançois Tigeot 		if (IS_ERR(obj)) {
3089b5c29a34SFrançois Tigeot 			DRM_ERROR("Failed to allocate batch bo\n");
3090*1487f786SFrançois Tigeot 			return PTR_ERR(obj);
3091b5c29a34SFrançois Tigeot 		}
3092b5c29a34SFrançois Tigeot 
3093ba55f2f5SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 0, 0);
3094b5c29a34SFrançois Tigeot 		if (ret != 0) {
3095b5c29a34SFrançois Tigeot 			drm_gem_object_unreference(&obj->base);
3096b5c29a34SFrançois Tigeot 			DRM_ERROR("Failed to ping batch bo\n");
3097b5c29a34SFrançois Tigeot 			return ret;
3098b5c29a34SFrançois Tigeot 		}
3099b5c29a34SFrançois Tigeot 
31008621f407SFrançois Tigeot 		engine->scratch.obj = obj;
31018621f407SFrançois Tigeot 		engine->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
3102e3adcf8fSFrançois Tigeot 	}
3103e3adcf8fSFrançois Tigeot 
31048621f407SFrançois Tigeot 	ret = intel_init_ring_buffer(dev, engine);
3105b5c29a34SFrançois Tigeot 	if (ret)
31062c9916cdSFrançois Tigeot 		return ret;
31072c9916cdSFrançois Tigeot 
3108*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 5) {
31098621f407SFrançois Tigeot 		ret = intel_init_pipe_control(engine);
31102c9916cdSFrançois Tigeot 		if (ret)
31112c9916cdSFrançois Tigeot 			return ret;
3112b5c29a34SFrançois Tigeot 	}
3113b5c29a34SFrançois Tigeot 
3114e3adcf8fSFrançois Tigeot 	return 0;
3115e3adcf8fSFrançois Tigeot }
3116e3adcf8fSFrançois Tigeot 
3117e3adcf8fSFrançois Tigeot int intel_init_bsd_ring_buffer(struct drm_device *dev)
3118e3adcf8fSFrançois Tigeot {
3119ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
31208621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[VCS];
3121e3adcf8fSFrançois Tigeot 
31228621f407SFrançois Tigeot 	engine->name = "bsd ring";
31238621f407SFrançois Tigeot 	engine->id = VCS;
31248621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_BSD;
31258621f407SFrançois Tigeot 	engine->hw_id = 1;
3126686a02f1SFrançois Tigeot 
3127*1487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
3128*1487f786SFrançois Tigeot 
3129*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6) {
31308621f407SFrançois Tigeot 		engine->mmio_base = GEN6_BSD_RING_BASE;
3131686a02f1SFrançois Tigeot 		/* gen6 bsd needs a special wa for tail updates */
3132*1487f786SFrançois Tigeot 		if (IS_GEN6(dev_priv))
31338621f407SFrançois Tigeot 			engine->write_tail = gen6_bsd_ring_write_tail;
31348621f407SFrançois Tigeot 		engine->flush = gen6_bsd_ring_flush;
3135*1487f786SFrançois Tigeot 		if (INTEL_GEN(dev_priv) >= 8)
31368621f407SFrançois Tigeot 			engine->irq_enable_mask =
31379edbd4a0SFrançois Tigeot 				GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
3138*1487f786SFrançois Tigeot 		else
31398621f407SFrançois Tigeot 			engine->irq_enable_mask = GT_BSD_USER_INTERRUPT;
3140686a02f1SFrançois Tigeot 	} else {
31418621f407SFrançois Tigeot 		engine->mmio_base = BSD_RING_BASE;
31428621f407SFrançois Tigeot 		engine->flush = bsd_ring_flush;
3143*1487f786SFrançois Tigeot 		if (IS_GEN5(dev_priv))
31448621f407SFrançois Tigeot 			engine->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
3145*1487f786SFrançois Tigeot 		else
31468621f407SFrançois Tigeot 			engine->irq_enable_mask = I915_BSD_USER_INTERRUPT;
3147686a02f1SFrançois Tigeot 	}
3148e3adcf8fSFrançois Tigeot 
31498621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
3150e3adcf8fSFrançois Tigeot }
3151e3adcf8fSFrançois Tigeot 
3152ba55f2f5SFrançois Tigeot /**
3153477eb7f9SFrançois Tigeot  * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
3154ba55f2f5SFrançois Tigeot  */
3155ba55f2f5SFrançois Tigeot int intel_init_bsd2_ring_buffer(struct drm_device *dev)
3156ba55f2f5SFrançois Tigeot {
3157ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
31588621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[VCS2];
3159ba55f2f5SFrançois Tigeot 
31608621f407SFrançois Tigeot 	engine->name = "bsd2 ring";
31618621f407SFrançois Tigeot 	engine->id = VCS2;
31628621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_BSD;
31638621f407SFrançois Tigeot 	engine->hw_id = 4;
31648621f407SFrançois Tigeot 	engine->mmio_base = GEN8_BSD2_RING_BASE;
3165*1487f786SFrançois Tigeot 
3166*1487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
3167*1487f786SFrançois Tigeot 
31688621f407SFrançois Tigeot 	engine->flush = gen6_bsd_ring_flush;
31698621f407SFrançois Tigeot 	engine->irq_enable_mask =
3170ba55f2f5SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
3171ba55f2f5SFrançois Tigeot 
31728621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
3173ba55f2f5SFrançois Tigeot }
3174ba55f2f5SFrançois Tigeot 
3175e3adcf8fSFrançois Tigeot int intel_init_blt_ring_buffer(struct drm_device *dev)
3176e3adcf8fSFrançois Tigeot {
3177ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
31788621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[BCS];
3179e3adcf8fSFrançois Tigeot 
31808621f407SFrançois Tigeot 	engine->name = "blitter ring";
31818621f407SFrançois Tigeot 	engine->id = BCS;
31828621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_BLT;
31838621f407SFrançois Tigeot 	engine->hw_id = 2;
31848621f407SFrançois Tigeot 	engine->mmio_base = BLT_RING_BASE;
3185*1487f786SFrançois Tigeot 
3186*1487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
3187*1487f786SFrançois Tigeot 
31888621f407SFrançois Tigeot 	engine->flush = gen6_ring_flush;
3189*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
31908621f407SFrançois Tigeot 		engine->irq_enable_mask =
31919edbd4a0SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
3192*1487f786SFrançois Tigeot 	else
31938621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_BLT_USER_INTERRUPT;
31945d0b1887SFrançois Tigeot 
31958621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
31965d0b1887SFrançois Tigeot }
31975d0b1887SFrançois Tigeot 
31985d0b1887SFrançois Tigeot int intel_init_vebox_ring_buffer(struct drm_device *dev)
31995d0b1887SFrançois Tigeot {
3200ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
32018621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[VECS];
32025d0b1887SFrançois Tigeot 
32038621f407SFrançois Tigeot 	engine->name = "video enhancement ring";
32048621f407SFrançois Tigeot 	engine->id = VECS;
32058621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_VEBOX;
32068621f407SFrançois Tigeot 	engine->hw_id = 3;
32078621f407SFrançois Tigeot 	engine->mmio_base = VEBOX_RING_BASE;
32089edbd4a0SFrançois Tigeot 
3209*1487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
3210*1487f786SFrançois Tigeot 
3211*1487f786SFrançois Tigeot 	engine->flush = gen6_ring_flush;
3212*1487f786SFrançois Tigeot 
3213*1487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
32148621f407SFrançois Tigeot 		engine->irq_enable_mask =
32159edbd4a0SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
32169edbd4a0SFrançois Tigeot 	} else {
32178621f407SFrançois Tigeot 		engine->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
32188621f407SFrançois Tigeot 		engine->irq_get = hsw_vebox_get_irq;
32198621f407SFrançois Tigeot 		engine->irq_put = hsw_vebox_put_irq;
322024edb884SFrançois Tigeot 	}
3221e3adcf8fSFrançois Tigeot 
32228621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
3223e3adcf8fSFrançois Tigeot }
3224b030f26bSFrançois Tigeot 
3225b030f26bSFrançois Tigeot int
3226a05eeebfSFrançois Tigeot intel_ring_flush_all_caches(struct drm_i915_gem_request *req)
3227b030f26bSFrançois Tigeot {
32288621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
3229b030f26bSFrançois Tigeot 	int ret;
3230b030f26bSFrançois Tigeot 
32318621f407SFrançois Tigeot 	if (!engine->gpu_caches_dirty)
3232b030f26bSFrançois Tigeot 		return 0;
3233b030f26bSFrançois Tigeot 
32348621f407SFrançois Tigeot 	ret = engine->flush(req, 0, I915_GEM_GPU_DOMAINS);
3235b030f26bSFrançois Tigeot 	if (ret)
3236b030f26bSFrançois Tigeot 		return ret;
3237b030f26bSFrançois Tigeot 
3238a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS);
3239a2fdbec6SFrançois Tigeot 
32408621f407SFrançois Tigeot 	engine->gpu_caches_dirty = false;
3241b030f26bSFrançois Tigeot 	return 0;
3242b030f26bSFrançois Tigeot }
3243b030f26bSFrançois Tigeot 
3244b030f26bSFrançois Tigeot int
3245a05eeebfSFrançois Tigeot intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
3246b030f26bSFrançois Tigeot {
32478621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
3248b030f26bSFrançois Tigeot 	uint32_t flush_domains;
3249b030f26bSFrançois Tigeot 	int ret;
3250b030f26bSFrançois Tigeot 
3251b030f26bSFrançois Tigeot 	flush_domains = 0;
32528621f407SFrançois Tigeot 	if (engine->gpu_caches_dirty)
3253b030f26bSFrançois Tigeot 		flush_domains = I915_GEM_GPU_DOMAINS;
3254b030f26bSFrançois Tigeot 
32558621f407SFrançois Tigeot 	ret = engine->flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
3256b030f26bSFrançois Tigeot 	if (ret)
3257b030f26bSFrançois Tigeot 		return ret;
3258b030f26bSFrançois Tigeot 
3259a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
3260a2fdbec6SFrançois Tigeot 
32618621f407SFrançois Tigeot 	engine->gpu_caches_dirty = false;
3262b030f26bSFrançois Tigeot 	return 0;
3263b030f26bSFrançois Tigeot }
3264ba55f2f5SFrançois Tigeot 
3265ba55f2f5SFrançois Tigeot void
32668621f407SFrançois Tigeot intel_stop_engine(struct intel_engine_cs *engine)
3267ba55f2f5SFrançois Tigeot {
3268ba55f2f5SFrançois Tigeot 	int ret;
3269ba55f2f5SFrançois Tigeot 
32708621f407SFrançois Tigeot 	if (!intel_engine_initialized(engine))
3271ba55f2f5SFrançois Tigeot 		return;
3272ba55f2f5SFrançois Tigeot 
32738621f407SFrançois Tigeot 	ret = intel_engine_idle(engine);
32748621f407SFrançois Tigeot 	if (ret)
3275ba55f2f5SFrançois Tigeot 		DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
32768621f407SFrançois Tigeot 			  engine->name, ret);
3277ba55f2f5SFrançois Tigeot 
32788621f407SFrançois Tigeot 	stop_ring(engine);
3279ba55f2f5SFrançois Tigeot }
3280