xref: /dflybsd-src/sys/dev/drm/i915/intel_ringbuffer.c (revision 87df8fc682f500d842f0b6cfa4b17a3d0fc13b35)
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 
371487f786SFrançois Tigeot /* Rough estimate of the typical request size, performing a flush,
381487f786SFrançois Tigeot  * set-context and then emitting the batch.
391487f786SFrançois Tigeot  */
401487f786SFrançois Tigeot #define LEGACY_REQUEST_SIZE 200
411487f786SFranç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 static void __intel_ring_advance(struct intel_engine_cs *engine)
629edbd4a0SFrançois Tigeot {
638621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = engine->buffer;
64ba55f2f5SFrançois Tigeot 	ringbuf->tail &= ringbuf->size - 1;
658621f407SFrançois Tigeot 	engine->write_tail(engine, ringbuf->tail);
669edbd4a0SFrançois Tigeot }
679edbd4a0SFrançois Tigeot 
68e3adcf8fSFrançois Tigeot static int
69a05eeebfSFrançois Tigeot gen2_render_ring_flush(struct drm_i915_gem_request *req,
70686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
71686a02f1SFrançois Tigeot 		       u32	flush_domains)
72686a02f1SFrançois Tigeot {
738621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
74686a02f1SFrançois Tigeot 	u32 cmd;
75686a02f1SFrançois Tigeot 	int ret;
76686a02f1SFrançois Tigeot 
77686a02f1SFrançois Tigeot 	cmd = MI_FLUSH;
78686a02f1SFrançois Tigeot 	if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0)
79686a02f1SFrançois Tigeot 		cmd |= MI_NO_WRITE_FLUSH;
80686a02f1SFrançois Tigeot 
81686a02f1SFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
82686a02f1SFrançois Tigeot 		cmd |= MI_READ_FLUSH;
83686a02f1SFrançois Tigeot 
84a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
85686a02f1SFrançois Tigeot 	if (ret)
86686a02f1SFrançois Tigeot 		return ret;
87686a02f1SFrançois Tigeot 
888621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
898621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
908621f407SFrançois Tigeot 	intel_ring_advance(engine);
91686a02f1SFrançois Tigeot 
92686a02f1SFrançois Tigeot 	return 0;
93686a02f1SFrançois Tigeot }
94686a02f1SFrançois Tigeot 
95686a02f1SFrançois Tigeot static int
96a05eeebfSFrançois Tigeot gen4_render_ring_flush(struct drm_i915_gem_request *req,
97686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
98686a02f1SFrançois Tigeot 		       u32	flush_domains)
99e3adcf8fSFrançois Tigeot {
1008621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
101686a02f1SFrançois Tigeot 	u32 cmd;
102e3adcf8fSFrançois Tigeot 	int ret;
103e3adcf8fSFrançois Tigeot 
104e3adcf8fSFrançois Tigeot 	/*
105e3adcf8fSFrançois Tigeot 	 * read/write caches:
106e3adcf8fSFrançois Tigeot 	 *
107e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER is always invalidated, but is
108e3adcf8fSFrançois Tigeot 	 * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
109e3adcf8fSFrançois Tigeot 	 * also flushed at 2d versus 3d pipeline switches.
110e3adcf8fSFrançois Tigeot 	 *
111e3adcf8fSFrançois Tigeot 	 * read-only caches:
112e3adcf8fSFrançois Tigeot 	 *
113e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
114e3adcf8fSFrançois Tigeot 	 * MI_READ_FLUSH is set, and is always flushed on 965.
115e3adcf8fSFrançois Tigeot 	 *
116e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_COMMAND may not exist?
117e3adcf8fSFrançois Tigeot 	 *
118e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
119e3adcf8fSFrançois Tigeot 	 * invalidated when MI_EXE_FLUSH is set.
120e3adcf8fSFrançois Tigeot 	 *
121e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
122e3adcf8fSFrançois Tigeot 	 * invalidated with every MI_FLUSH.
123e3adcf8fSFrançois Tigeot 	 *
124e3adcf8fSFrançois Tigeot 	 * TLBs:
125e3adcf8fSFrançois Tigeot 	 *
126e3adcf8fSFrançois Tigeot 	 * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
127e3adcf8fSFrançois Tigeot 	 * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
128e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
129e3adcf8fSFrançois Tigeot 	 * are flushed at any MI_FLUSH.
130e3adcf8fSFrançois Tigeot 	 */
131e3adcf8fSFrançois Tigeot 
132e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
133686a02f1SFrançois Tigeot 	if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER)
134e3adcf8fSFrançois Tigeot 		cmd &= ~MI_NO_WRITE_FLUSH;
135e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
136e3adcf8fSFrançois Tigeot 		cmd |= MI_EXE_FLUSH;
137e3adcf8fSFrançois Tigeot 
138e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
1391487f786SFrançois Tigeot 	    (IS_G4X(req->i915) || IS_GEN5(req->i915)))
140e3adcf8fSFrançois Tigeot 		cmd |= MI_INVALIDATE_ISP;
141e3adcf8fSFrançois Tigeot 
142a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
143e3adcf8fSFrançois Tigeot 	if (ret)
144e3adcf8fSFrançois Tigeot 		return ret;
145e3adcf8fSFrançois Tigeot 
1468621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
1478621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
1488621f407SFrançois Tigeot 	intel_ring_advance(engine);
149e3adcf8fSFrançois Tigeot 
150e3adcf8fSFrançois Tigeot 	return 0;
151e3adcf8fSFrançois Tigeot }
152e3adcf8fSFrançois Tigeot 
153e3adcf8fSFrançois Tigeot /**
154e3adcf8fSFrançois Tigeot  * Emits a PIPE_CONTROL with a non-zero post-sync operation, for
155e3adcf8fSFrançois Tigeot  * implementing two workarounds on gen6.  From section 1.4.7.1
156e3adcf8fSFrançois Tigeot  * "PIPE_CONTROL" of the Sandy Bridge PRM volume 2 part 1:
157e3adcf8fSFrançois Tigeot  *
158e3adcf8fSFrançois Tigeot  * [DevSNB-C+{W/A}] Before any depth stall flush (including those
159e3adcf8fSFrançois Tigeot  * produced by non-pipelined state commands), software needs to first
160e3adcf8fSFrançois Tigeot  * send a PIPE_CONTROL with no bits set except Post-Sync Operation !=
161e3adcf8fSFrançois Tigeot  * 0.
162e3adcf8fSFrançois Tigeot  *
163e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Before a PIPE_CONTROL with Write Cache Flush Enable
164e3adcf8fSFrançois Tigeot  * =1, a PIPE_CONTROL with any non-zero post-sync-op is required.
165e3adcf8fSFrançois Tigeot  *
166e3adcf8fSFrançois Tigeot  * And the workaround for these two requires this workaround first:
167e3adcf8fSFrançois Tigeot  *
168e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
169e3adcf8fSFrançois Tigeot  * BEFORE the pipe-control with a post-sync op and no write-cache
170e3adcf8fSFrançois Tigeot  * flushes.
171e3adcf8fSFrançois Tigeot  *
172e3adcf8fSFrançois Tigeot  * And this last workaround is tricky because of the requirements on
173e3adcf8fSFrançois Tigeot  * that bit.  From section 1.4.7.2.3 "Stall" of the Sandy Bridge PRM
174e3adcf8fSFrançois Tigeot  * volume 2 part 1:
175e3adcf8fSFrançois Tigeot  *
176e3adcf8fSFrançois Tigeot  *     "1 of the following must also be set:
177e3adcf8fSFrançois Tigeot  *      - Render Target Cache Flush Enable ([12] of DW1)
178e3adcf8fSFrançois Tigeot  *      - Depth Cache Flush Enable ([0] of DW1)
179e3adcf8fSFrançois Tigeot  *      - Stall at Pixel Scoreboard ([1] of DW1)
180e3adcf8fSFrançois Tigeot  *      - Depth Stall ([13] of DW1)
181e3adcf8fSFrançois Tigeot  *      - Post-Sync Operation ([13] of DW1)
182e3adcf8fSFrançois Tigeot  *      - Notify Enable ([8] of DW1)"
183e3adcf8fSFrançois Tigeot  *
184e3adcf8fSFrançois Tigeot  * The cache flushes require the workaround flush that triggered this
185e3adcf8fSFrançois Tigeot  * one, so we can't use it.  Depth stall would trigger the same.
186e3adcf8fSFrançois Tigeot  * Post-sync nonzero is what triggered this second workaround, so we
187e3adcf8fSFrançois Tigeot  * can't use that one either.  Notify enable is IRQs, which aren't
188e3adcf8fSFrançois Tigeot  * really our business.  That leaves only stall at scoreboard.
189e3adcf8fSFrançois Tigeot  */
190e3adcf8fSFrançois Tigeot static int
191a05eeebfSFrançois Tigeot intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
192e3adcf8fSFrançois Tigeot {
1938621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1948621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
195e3adcf8fSFrançois Tigeot 	int ret;
196e3adcf8fSFrançois Tigeot 
197a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
198e3adcf8fSFrançois Tigeot 	if (ret)
199e3adcf8fSFrançois Tigeot 		return ret;
200e3adcf8fSFrançois Tigeot 
2018621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
2028621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
203e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_STALL_AT_SCOREBOARD);
2048621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
2058621f407SFrançois Tigeot 	intel_ring_emit(engine, 0); /* low dword */
2068621f407SFrançois Tigeot 	intel_ring_emit(engine, 0); /* high dword */
2078621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
2088621f407SFrançois Tigeot 	intel_ring_advance(engine);
209e3adcf8fSFrançois Tigeot 
210a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
211e3adcf8fSFrançois Tigeot 	if (ret)
212e3adcf8fSFrançois Tigeot 		return ret;
213e3adcf8fSFrançois Tigeot 
2148621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
2158621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_QW_WRITE);
2168621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
2178621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2188621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2198621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
2208621f407SFrançois Tigeot 	intel_ring_advance(engine);
221e3adcf8fSFrançois Tigeot 
222e3adcf8fSFrançois Tigeot 	return 0;
223e3adcf8fSFrançois Tigeot }
224e3adcf8fSFrançois Tigeot 
225e3adcf8fSFrançois Tigeot static int
226a05eeebfSFrançois Tigeot gen6_render_ring_flush(struct drm_i915_gem_request *req,
227e3adcf8fSFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
228e3adcf8fSFrançois Tigeot {
2298621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
230e3adcf8fSFrançois Tigeot 	u32 flags = 0;
2318621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
232e3adcf8fSFrançois Tigeot 	int ret;
233e3adcf8fSFrançois Tigeot 
234e3adcf8fSFrançois Tigeot 	/* Force SNB workarounds for PIPE_CONTROL flushes */
235a05eeebfSFrançois Tigeot 	ret = intel_emit_post_sync_nonzero_flush(req);
236686a02f1SFrançois Tigeot 	if (ret)
237686a02f1SFrançois Tigeot 		return ret;
238e3adcf8fSFrançois Tigeot 
239e3adcf8fSFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
240e3adcf8fSFrançois Tigeot 	 * number of bits based on the write domains has little performance
241e3adcf8fSFrançois Tigeot 	 * impact.
242e3adcf8fSFrançois Tigeot 	 */
243b5c29a34SFrançois Tigeot 	if (flush_domains) {
244e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
245b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
246b5c29a34SFrançois Tigeot 		/*
247b5c29a34SFrançois Tigeot 		 * Ensure that any following seqno writes only happen
248b5c29a34SFrançois Tigeot 		 * when the render cache is indeed flushed.
249b5c29a34SFrançois Tigeot 		 */
250b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CS_STALL;
251b5c29a34SFrançois Tigeot 	}
252b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
253686a02f1SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
254e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
255e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
256e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
257e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
258e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
259686a02f1SFrançois Tigeot 		/*
260b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
261686a02f1SFrançois Tigeot 		 */
262b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL;
263b5c29a34SFrançois Tigeot 	}
264e3adcf8fSFrançois Tigeot 
265a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
266e3adcf8fSFrançois Tigeot 	if (ret)
267e3adcf8fSFrançois Tigeot 		return ret;
268e3adcf8fSFrançois Tigeot 
2698621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
2708621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
2718621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
2728621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2738621f407SFrançois Tigeot 	intel_ring_advance(engine);
274b5c29a34SFrançois Tigeot 
275b5c29a34SFrançois Tigeot 	return 0;
276b5c29a34SFrançois Tigeot }
277b5c29a34SFrançois Tigeot 
278b5c29a34SFrançois Tigeot static int
279a05eeebfSFrançois Tigeot gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
280b5c29a34SFrançois Tigeot {
2818621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
282b5c29a34SFrançois Tigeot 	int ret;
283b5c29a34SFrançois Tigeot 
284a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
285b5c29a34SFrançois Tigeot 	if (ret)
286b5c29a34SFrançois Tigeot 		return ret;
287b5c29a34SFrançois Tigeot 
2888621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
2898621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
290b5c29a34SFrançois Tigeot 			      PIPE_CONTROL_STALL_AT_SCOREBOARD);
2918621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2928621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2938621f407SFrançois Tigeot 	intel_ring_advance(engine);
294b5c29a34SFrançois Tigeot 
295b5c29a34SFrançois Tigeot 	return 0;
296b5c29a34SFrançois Tigeot }
297b5c29a34SFrançois Tigeot 
298b5c29a34SFrançois Tigeot static int
299a05eeebfSFrançois Tigeot gen7_render_ring_flush(struct drm_i915_gem_request *req,
300b5c29a34SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
301b5c29a34SFrançois Tigeot {
3028621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
303b5c29a34SFrançois Tigeot 	u32 flags = 0;
3048621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
305b5c29a34SFrançois Tigeot 	int ret;
306b5c29a34SFrançois Tigeot 
307b5c29a34SFrançois Tigeot 	/*
308b5c29a34SFrançois Tigeot 	 * Ensure that any following seqno writes only happen when the render
309b5c29a34SFrançois Tigeot 	 * cache is indeed flushed.
310b5c29a34SFrançois Tigeot 	 *
311b5c29a34SFrançois Tigeot 	 * Workaround: 4th PIPE_CONTROL command (except the ones with only
312b5c29a34SFrançois Tigeot 	 * read-cache invalidate bits set) must have the CS_STALL bit set. We
313b5c29a34SFrançois Tigeot 	 * don't try to be clever and just set it unconditionally.
314b5c29a34SFrançois Tigeot 	 */
315b5c29a34SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
316b5c29a34SFrançois Tigeot 
317b5c29a34SFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
318b5c29a34SFrançois Tigeot 	 * number of bits based on the write domains has little performance
319b5c29a34SFrançois Tigeot 	 * impact.
320b5c29a34SFrançois Tigeot 	 */
321b5c29a34SFrançois Tigeot 	if (flush_domains) {
322b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
323b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
324aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
325b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
326b5c29a34SFrançois Tigeot 	}
327b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
328b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
329b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
330b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
331b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
332b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
333b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
3342c9916cdSFrançois Tigeot 		flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR;
335b5c29a34SFrançois Tigeot 		/*
336b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
337b5c29a34SFrançois Tigeot 		 */
338b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
339a2fdbec6SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
340b5c29a34SFrançois Tigeot 
3410dbf0ea8SMatthew Dillon 		flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD;
3420dbf0ea8SMatthew Dillon 
343b5c29a34SFrançois Tigeot 		/* Workaround: we must issue a pipe_control with CS-stall bit
344b5c29a34SFrançois Tigeot 		 * set before a pipe_control command that has the state cache
345b5c29a34SFrançois Tigeot 		 * invalidate bit set. */
346a05eeebfSFrançois Tigeot 		gen7_render_ring_cs_stall_wa(req);
347b5c29a34SFrançois Tigeot 	}
348b5c29a34SFrançois Tigeot 
349a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
350b5c29a34SFrançois Tigeot 	if (ret)
351b5c29a34SFrançois Tigeot 		return ret;
352b5c29a34SFrançois Tigeot 
3538621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
3548621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
3558621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr);
3568621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3578621f407SFrançois Tigeot 	intel_ring_advance(engine);
358e3adcf8fSFrançois Tigeot 
359e3adcf8fSFrançois Tigeot 	return 0;
360e3adcf8fSFrançois Tigeot }
361e3adcf8fSFrançois Tigeot 
3629edbd4a0SFrançois Tigeot static int
363a05eeebfSFrançois Tigeot gen8_emit_pipe_control(struct drm_i915_gem_request *req,
36424edb884SFrançois Tigeot 		       u32 flags, u32 scratch_addr)
36524edb884SFrançois Tigeot {
3668621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
36724edb884SFrançois Tigeot 	int ret;
36824edb884SFrançois Tigeot 
369a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
37024edb884SFrançois Tigeot 	if (ret)
37124edb884SFrançois Tigeot 		return ret;
37224edb884SFrançois Tigeot 
3738621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
3748621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
3758621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr);
3768621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3778621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3788621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3798621f407SFrançois Tigeot 	intel_ring_advance(engine);
38024edb884SFrançois Tigeot 
38124edb884SFrançois Tigeot 	return 0;
38224edb884SFrançois Tigeot }
38324edb884SFrançois Tigeot 
38424edb884SFrançois Tigeot static int
385a05eeebfSFrançois Tigeot gen8_render_ring_flush(struct drm_i915_gem_request *req,
3869edbd4a0SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
3879edbd4a0SFrançois Tigeot {
3889edbd4a0SFrançois Tigeot 	u32 flags = 0;
3898621f407SFrançois Tigeot 	u32 scratch_addr = req->engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
3909edbd4a0SFrançois Tigeot 	int ret;
3919edbd4a0SFrançois Tigeot 
3929edbd4a0SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
3939edbd4a0SFrançois Tigeot 
3949edbd4a0SFrançois Tigeot 	if (flush_domains) {
3959edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
3969edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
397aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
398b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
3999edbd4a0SFrançois Tigeot 	}
4009edbd4a0SFrançois Tigeot 	if (invalidate_domains) {
4019edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
4029edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
4039edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
4049edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
4059edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
4069edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
4079edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
4089edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
4099edbd4a0SFrançois Tigeot 
41024edb884SFrançois Tigeot 		/* WaCsStallBeforeStateCacheInvalidate:bdw,chv */
411a05eeebfSFrançois Tigeot 		ret = gen8_emit_pipe_control(req,
41224edb884SFrançois Tigeot 					     PIPE_CONTROL_CS_STALL |
41324edb884SFrançois Tigeot 					     PIPE_CONTROL_STALL_AT_SCOREBOARD,
41424edb884SFrançois Tigeot 					     0);
4159edbd4a0SFrançois Tigeot 		if (ret)
4169edbd4a0SFrançois Tigeot 			return ret;
41724edb884SFrançois Tigeot 	}
4189edbd4a0SFrançois Tigeot 
419a05eeebfSFrançois Tigeot 	return gen8_emit_pipe_control(req, flags, scratch_addr);
4209edbd4a0SFrançois Tigeot }
4219edbd4a0SFrançois Tigeot 
4228621f407SFrançois Tigeot static void ring_write_tail(struct intel_engine_cs *engine,
423b5c29a34SFrançois Tigeot 			    u32 value)
424e3adcf8fSFrançois Tigeot {
4251487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
4268621f407SFrançois Tigeot 	I915_WRITE_TAIL(engine, value);
427e3adcf8fSFrançois Tigeot }
428e3adcf8fSFrançois Tigeot 
4298621f407SFrançois Tigeot u64 intel_ring_get_active_head(struct intel_engine_cs *engine)
430e3adcf8fSFrançois Tigeot {
4311487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
432ba55f2f5SFrançois Tigeot 	u64 acthd;
433e3adcf8fSFrançois Tigeot 
4341487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
4358621f407SFrançois Tigeot 		acthd = I915_READ64_2x32(RING_ACTHD(engine->mmio_base),
4368621f407SFrançois Tigeot 					 RING_ACTHD_UDW(engine->mmio_base));
4371487f786SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 4)
4388621f407SFrançois Tigeot 		acthd = I915_READ(RING_ACTHD(engine->mmio_base));
439ba55f2f5SFrançois Tigeot 	else
440ba55f2f5SFrançois Tigeot 		acthd = I915_READ(ACTHD);
441ba55f2f5SFrançois Tigeot 
442ba55f2f5SFrançois Tigeot 	return acthd;
443e3adcf8fSFrançois Tigeot }
444e3adcf8fSFrançois Tigeot 
4458621f407SFrançois Tigeot static void ring_setup_phys_status_page(struct intel_engine_cs *engine)
4465d0b1887SFrançois Tigeot {
4471487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
4485d0b1887SFrançois Tigeot 	u32 addr;
4495d0b1887SFrançois Tigeot 
4505d0b1887SFrançois Tigeot 	addr = dev_priv->status_page_dmah->busaddr;
4511487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 4)
4525d0b1887SFrançois Tigeot 		addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0;
4535d0b1887SFrançois Tigeot 	I915_WRITE(HWS_PGA, addr);
4545d0b1887SFrançois Tigeot }
4555d0b1887SFrançois Tigeot 
4568621f407SFrançois Tigeot static void intel_ring_setup_status_page(struct intel_engine_cs *engine)
457477eb7f9SFrançois Tigeot {
4581487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
459aee94f86SFrançois Tigeot 	i915_reg_t mmio;
460477eb7f9SFrançois Tigeot 
461477eb7f9SFrançois Tigeot 	/* The ring status page addresses are no longer next to the rest of
462477eb7f9SFrançois Tigeot 	 * the ring registers as of gen7.
463477eb7f9SFrançois Tigeot 	 */
4641487f786SFrançois Tigeot 	if (IS_GEN7(dev_priv)) {
4658621f407SFrançois Tigeot 		switch (engine->id) {
466477eb7f9SFrançois Tigeot 		case RCS:
467477eb7f9SFrançois Tigeot 			mmio = RENDER_HWS_PGA_GEN7;
468477eb7f9SFrançois Tigeot 			break;
469477eb7f9SFrançois Tigeot 		case BCS:
470477eb7f9SFrançois Tigeot 			mmio = BLT_HWS_PGA_GEN7;
471477eb7f9SFrançois Tigeot 			break;
472477eb7f9SFrançois Tigeot 		/*
473477eb7f9SFrançois Tigeot 		 * VCS2 actually doesn't exist on Gen7. Only shut up
474477eb7f9SFrançois Tigeot 		 * gcc switch check warning
475477eb7f9SFrançois Tigeot 		 */
476477eb7f9SFrançois Tigeot 		case VCS2:
477477eb7f9SFrançois Tigeot 		case VCS:
478477eb7f9SFrançois Tigeot 			mmio = BSD_HWS_PGA_GEN7;
479477eb7f9SFrançois Tigeot 			break;
480477eb7f9SFrançois Tigeot 		case VECS:
481477eb7f9SFrançois Tigeot 			mmio = VEBOX_HWS_PGA_GEN7;
482477eb7f9SFrançois Tigeot 			break;
483477eb7f9SFrançois Tigeot 		}
4841487f786SFrançois Tigeot 	} else if (IS_GEN6(dev_priv)) {
4858621f407SFrançois Tigeot 		mmio = RING_HWS_PGA_GEN6(engine->mmio_base);
486477eb7f9SFrançois Tigeot 	} else {
487477eb7f9SFrançois Tigeot 		/* XXX: gen8 returns to sanity */
4888621f407SFrançois Tigeot 		mmio = RING_HWS_PGA(engine->mmio_base);
489477eb7f9SFrançois Tigeot 	}
490477eb7f9SFrançois Tigeot 
4918621f407SFrançois Tigeot 	I915_WRITE(mmio, (u32)engine->status_page.gfx_addr);
492477eb7f9SFrançois Tigeot 	POSTING_READ(mmio);
493477eb7f9SFrançois Tigeot 
494477eb7f9SFrançois Tigeot 	/*
495477eb7f9SFrançois Tigeot 	 * Flush the TLB for this page
496477eb7f9SFrançois Tigeot 	 *
497477eb7f9SFrançois Tigeot 	 * FIXME: These two bits have disappeared on gen8, so a question
498477eb7f9SFrançois Tigeot 	 * arises: do we still need this and if so how should we go about
499477eb7f9SFrançois Tigeot 	 * invalidating the TLB?
500477eb7f9SFrançois Tigeot 	 */
5011487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 6, 7)) {
5028621f407SFrançois Tigeot 		i915_reg_t reg = RING_INSTPM(engine->mmio_base);
503477eb7f9SFrançois Tigeot 
504477eb7f9SFrançois Tigeot 		/* ring should be idle before issuing a sync flush*/
5058621f407SFrançois Tigeot 		WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0);
506477eb7f9SFrançois Tigeot 
507477eb7f9SFrançois Tigeot 		I915_WRITE(reg,
508477eb7f9SFrançois Tigeot 			   _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
509477eb7f9SFrançois Tigeot 					      INSTPM_SYNC_FLUSH));
5101487f786SFrançois Tigeot 		if (intel_wait_for_register(dev_priv,
5111487f786SFrançois Tigeot 					    reg, INSTPM_SYNC_FLUSH, 0,
512477eb7f9SFrançois Tigeot 					    1000))
513477eb7f9SFrançois Tigeot 			DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
5148621f407SFrançois Tigeot 				  engine->name);
515477eb7f9SFrançois Tigeot 	}
516477eb7f9SFrançois Tigeot }
517477eb7f9SFrançois Tigeot 
5188621f407SFrançois Tigeot static bool stop_ring(struct intel_engine_cs *engine)
519e3adcf8fSFrançois Tigeot {
5201487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
521e3adcf8fSFrançois Tigeot 
5221487f786SFrançois Tigeot 	if (!IS_GEN2(dev_priv)) {
5238621f407SFrançois Tigeot 		I915_WRITE_MODE(engine, _MASKED_BIT_ENABLE(STOP_RING));
5241487f786SFrançois Tigeot 		if (intel_wait_for_register(dev_priv,
5251487f786SFrançois Tigeot 					    RING_MI_MODE(engine->mmio_base),
5261487f786SFrançois Tigeot 					    MODE_IDLE,
5271487f786SFrançois Tigeot 					    MODE_IDLE,
5281487f786SFrançois Tigeot 					    1000)) {
5298621f407SFrançois Tigeot 			DRM_ERROR("%s : timed out trying to stop ring\n",
5308621f407SFrançois Tigeot 				  engine->name);
5311b13d190SFrançois Tigeot 			/* Sometimes we observe that the idle flag is not
5321b13d190SFrançois Tigeot 			 * set even though the ring is empty. So double
5331b13d190SFrançois Tigeot 			 * check before giving up.
5341b13d190SFrançois Tigeot 			 */
5358621f407SFrançois Tigeot 			if (I915_READ_HEAD(engine) != I915_READ_TAIL(engine))
536ba55f2f5SFrançois Tigeot 				return false;
537ba55f2f5SFrançois Tigeot 		}
538ba55f2f5SFrançois Tigeot 	}
539686a02f1SFrançois Tigeot 
5408621f407SFrançois Tigeot 	I915_WRITE_CTL(engine, 0);
5418621f407SFrançois Tigeot 	I915_WRITE_HEAD(engine, 0);
5428621f407SFrançois Tigeot 	engine->write_tail(engine, 0);
543e3adcf8fSFrançois Tigeot 
5441487f786SFrançois Tigeot 	if (!IS_GEN2(dev_priv)) {
5458621f407SFrançois Tigeot 		(void)I915_READ_CTL(engine);
5468621f407SFrançois Tigeot 		I915_WRITE_MODE(engine, _MASKED_BIT_DISABLE(STOP_RING));
547ba55f2f5SFrançois Tigeot 	}
548e3adcf8fSFrançois Tigeot 
5498621f407SFrançois Tigeot 	return (I915_READ_HEAD(engine) & HEAD_ADDR) == 0;
550ba55f2f5SFrançois Tigeot }
551ba55f2f5SFrançois Tigeot 
5528621f407SFrançois Tigeot static int init_ring_common(struct intel_engine_cs *engine)
5538621f407SFrançois Tigeot {
5541487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
5558621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = engine->buffer;
556ba55f2f5SFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
557ba55f2f5SFrançois Tigeot 	int ret = 0;
558ba55f2f5SFrançois Tigeot 
5592c9916cdSFrançois Tigeot 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
560ba55f2f5SFrançois Tigeot 
5618621f407SFrançois Tigeot 	if (!stop_ring(engine)) {
562ba55f2f5SFrançois Tigeot 		/* G45 ring initialization often fails to reset head to zero */
563b5c29a34SFrançois Tigeot 		DRM_DEBUG_KMS("%s head not reset to zero "
564e3adcf8fSFrançois Tigeot 			      "ctl %08x head %08x tail %08x start %08x\n",
5658621f407SFrançois Tigeot 			      engine->name,
5668621f407SFrançois Tigeot 			      I915_READ_CTL(engine),
5678621f407SFrançois Tigeot 			      I915_READ_HEAD(engine),
5688621f407SFrançois Tigeot 			      I915_READ_TAIL(engine),
5698621f407SFrançois Tigeot 			      I915_READ_START(engine));
570e3adcf8fSFrançois Tigeot 
5718621f407SFrançois Tigeot 		if (!stop_ring(engine)) {
572e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to set %s head to zero "
573e3adcf8fSFrançois Tigeot 				  "ctl %08x head %08x tail %08x start %08x\n",
5748621f407SFrançois Tigeot 				  engine->name,
5758621f407SFrançois Tigeot 				  I915_READ_CTL(engine),
5768621f407SFrançois Tigeot 				  I915_READ_HEAD(engine),
5778621f407SFrançois Tigeot 				  I915_READ_TAIL(engine),
5788621f407SFrançois Tigeot 				  I915_READ_START(engine));
579686a02f1SFrançois Tigeot 			ret = -EIO;
580686a02f1SFrançois Tigeot 			goto out;
581e3adcf8fSFrançois Tigeot 		}
582ba55f2f5SFrançois Tigeot 	}
583ba55f2f5SFrançois Tigeot 
5841487f786SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev_priv))
5858621f407SFrançois Tigeot 		intel_ring_setup_status_page(engine);
586ba55f2f5SFrançois Tigeot 	else
5878621f407SFrançois Tigeot 		ring_setup_phys_status_page(engine);
588ba55f2f5SFrançois Tigeot 
5890f370975SMatthew Dillon 	/* Enforce ordering by reading HEAD register back */
5908621f407SFrançois Tigeot 	I915_READ_HEAD(engine);
5910f370975SMatthew Dillon 
592ba55f2f5SFrançois Tigeot 	/* Initialize the ring. This must happen _after_ we've cleared the ring
593ba55f2f5SFrançois Tigeot 	 * registers with the above sequence (the readback of the HEAD registers
594ba55f2f5SFrançois Tigeot 	 * also enforces ordering), otherwise the hw might lose the new ring
595ba55f2f5SFrançois Tigeot 	 * register values. */
5968621f407SFrançois Tigeot 	I915_WRITE_START(engine, i915_gem_obj_ggtt_offset(obj));
5971b13d190SFrançois Tigeot 
5981b13d190SFrançois Tigeot 	/* WaClearRingBufHeadRegAtInit:ctg,elk */
5998621f407SFrançois Tigeot 	if (I915_READ_HEAD(engine))
6001b13d190SFrançois Tigeot 		DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
6018621f407SFrançois Tigeot 			  engine->name, I915_READ_HEAD(engine));
6028621f407SFrançois Tigeot 	I915_WRITE_HEAD(engine, 0);
6038621f407SFrançois Tigeot 	(void)I915_READ_HEAD(engine);
6041b13d190SFrançois Tigeot 
6058621f407SFrançois Tigeot 	I915_WRITE_CTL(engine,
606ba55f2f5SFrançois Tigeot 			((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES)
607ba55f2f5SFrançois Tigeot 			| RING_VALID);
608ba55f2f5SFrançois Tigeot 
609ba55f2f5SFrançois Tigeot 	/* If the head is still not zero, the ring is dead */
6108621f407SFrançois Tigeot 	if (wait_for((I915_READ_CTL(engine) & RING_VALID) != 0 &&
6118621f407SFrançois Tigeot 		     I915_READ_START(engine) == i915_gem_obj_ggtt_offset(obj) &&
6128621f407SFrançois Tigeot 		     (I915_READ_HEAD(engine) & HEAD_ADDR) == 0, 50)) {
613ba55f2f5SFrançois Tigeot 		DRM_ERROR("%s initialization failed "
614ba55f2f5SFrançois Tigeot 			  "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08lx]\n",
6158621f407SFrançois Tigeot 			  engine->name,
6168621f407SFrançois Tigeot 			  I915_READ_CTL(engine),
6178621f407SFrançois Tigeot 			  I915_READ_CTL(engine) & RING_VALID,
6188621f407SFrançois Tigeot 			  I915_READ_HEAD(engine), I915_READ_TAIL(engine),
6198621f407SFrançois Tigeot 			  I915_READ_START(engine),
6208621f407SFrançois Tigeot 			  (unsigned long)i915_gem_obj_ggtt_offset(obj));
621ba55f2f5SFrançois Tigeot 		ret = -EIO;
622ba55f2f5SFrançois Tigeot 		goto out;
623ba55f2f5SFrançois Tigeot 	}
624e3adcf8fSFrançois Tigeot 
6252c9916cdSFrançois Tigeot 	ringbuf->last_retired_head = -1;
6268621f407SFrançois Tigeot 	ringbuf->head = I915_READ_HEAD(engine);
6278621f407SFrançois Tigeot 	ringbuf->tail = I915_READ_TAIL(engine) & TAIL_ADDR;
6282c9916cdSFrançois Tigeot 	intel_ring_update_space(ringbuf);
629e3adcf8fSFrançois Tigeot 
6308621f407SFrançois Tigeot 	intel_engine_init_hangcheck(engine);
6315d0b1887SFrançois Tigeot 
632686a02f1SFrançois Tigeot out:
6332c9916cdSFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
634686a02f1SFrançois Tigeot 
635686a02f1SFrançois Tigeot 	return ret;
636e3adcf8fSFrançois Tigeot }
637e3adcf8fSFrançois Tigeot 
638303bf270SFrançois Tigeot void intel_fini_pipe_control(struct intel_engine_cs *engine)
6391b13d190SFrançois Tigeot {
6408621f407SFrançois Tigeot 	if (engine->scratch.obj == NULL)
6411b13d190SFrançois Tigeot 		return;
6421b13d190SFrançois Tigeot 
6438621f407SFrançois Tigeot 	i915_gem_object_ggtt_unpin(engine->scratch.obj);
644*87df8fc6SFrançois Tigeot 	i915_gem_object_put(engine->scratch.obj);
6458621f407SFrançois Tigeot 	engine->scratch.obj = NULL;
6461b13d190SFrançois Tigeot }
6471b13d190SFrançois Tigeot 
648303bf270SFrançois Tigeot int intel_init_pipe_control(struct intel_engine_cs *engine, int size)
649e3adcf8fSFrançois Tigeot {
650303bf270SFrançois Tigeot 	struct drm_i915_gem_object *obj;
651e3adcf8fSFrançois Tigeot 	int ret;
652e3adcf8fSFrançois Tigeot 
6538621f407SFrançois Tigeot 	WARN_ON(engine->scratch.obj);
654e3adcf8fSFrançois Tigeot 
655303bf270SFrançois Tigeot 	obj = i915_gem_object_create_stolen(&engine->i915->drm, size);
656303bf270SFrançois Tigeot 	if (!obj)
657303bf270SFrançois Tigeot 		obj = i915_gem_object_create(&engine->i915->drm, size);
658303bf270SFrançois Tigeot 	if (IS_ERR(obj)) {
659303bf270SFrançois Tigeot 		DRM_ERROR("Failed to allocate scratch page\n");
660303bf270SFrançois Tigeot 		ret = PTR_ERR(obj);
661e3adcf8fSFrançois Tigeot 		goto err;
662e3adcf8fSFrançois Tigeot 	}
663e3adcf8fSFrançois Tigeot 
664303bf270SFrançois Tigeot 	ret = i915_gem_obj_ggtt_pin(obj, 4096, PIN_HIGH);
665ba55f2f5SFrançois Tigeot 	if (ret)
666ba55f2f5SFrançois Tigeot 		goto err_unref;
667e3adcf8fSFrançois Tigeot 
668303bf270SFrançois Tigeot 	engine->scratch.obj = obj;
669303bf270SFrançois Tigeot 	engine->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
670a2fdbec6SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
6718621f407SFrançois Tigeot 			 engine->name, engine->scratch.gtt_offset);
672e3adcf8fSFrançois Tigeot 	return 0;
673e3adcf8fSFrançois Tigeot 
674e3adcf8fSFrançois Tigeot err_unref:
675*87df8fc6SFrançois Tigeot 	i915_gem_object_put(engine->scratch.obj);
676e3adcf8fSFrançois Tigeot err:
677e3adcf8fSFrançois Tigeot 	return ret;
678e3adcf8fSFrançois Tigeot }
679e3adcf8fSFrançois Tigeot 
680a05eeebfSFrançois Tigeot static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
6811b13d190SFrançois Tigeot {
6828621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
6831487f786SFrançois Tigeot 	struct i915_workarounds *w = &req->i915->workarounds;
6841487f786SFrançois Tigeot 	int ret, i;
6851b13d190SFrançois Tigeot 
686352ff8bdSFrançois Tigeot 	if (w->count == 0)
6872c9916cdSFrançois Tigeot 		return 0;
6881b13d190SFrançois Tigeot 
6898621f407SFrançois Tigeot 	engine->gpu_caches_dirty = true;
690a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
6911b13d190SFrançois Tigeot 	if (ret)
6921b13d190SFrançois Tigeot 		return ret;
6931b13d190SFrançois Tigeot 
694a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, (w->count * 2 + 2));
6952c9916cdSFrançois Tigeot 	if (ret)
6962c9916cdSFrançois Tigeot 		return ret;
6972c9916cdSFrançois Tigeot 
6988621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(w->count));
6992c9916cdSFrançois Tigeot 	for (i = 0; i < w->count; i++) {
7008621f407SFrançois Tigeot 		intel_ring_emit_reg(engine, w->reg[i].addr);
7018621f407SFrançois Tigeot 		intel_ring_emit(engine, w->reg[i].value);
7022c9916cdSFrançois Tigeot 	}
7038621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
7042c9916cdSFrançois Tigeot 
7058621f407SFrançois Tigeot 	intel_ring_advance(engine);
7062c9916cdSFrançois Tigeot 
7078621f407SFrançois Tigeot 	engine->gpu_caches_dirty = true;
708a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7092c9916cdSFrançois Tigeot 	if (ret)
7102c9916cdSFrançois Tigeot 		return ret;
7112c9916cdSFrançois Tigeot 
7122c9916cdSFrançois Tigeot 	DRM_DEBUG_DRIVER("Number of Workarounds emitted: %d\n", w->count);
7132c9916cdSFrançois Tigeot 
7142c9916cdSFrançois Tigeot 	return 0;
7152c9916cdSFrançois Tigeot }
7162c9916cdSFrançois Tigeot 
717a05eeebfSFrançois Tigeot static int intel_rcs_ctx_init(struct drm_i915_gem_request *req)
7182c9916cdSFrançois Tigeot {
7192c9916cdSFrançois Tigeot 	int ret;
7202c9916cdSFrançois Tigeot 
721a05eeebfSFrançois Tigeot 	ret = intel_ring_workarounds_emit(req);
7222c9916cdSFrançois Tigeot 	if (ret != 0)
7232c9916cdSFrançois Tigeot 		return ret;
7242c9916cdSFrançois Tigeot 
725a05eeebfSFrançois Tigeot 	ret = i915_gem_render_state_init(req);
7262c9916cdSFrançois Tigeot 	if (ret)
7272c9916cdSFrançois Tigeot 		return ret;
728c0e85e96SFrançois Tigeot 
729c0e85e96SFrançois Tigeot 	return 0;
7302c9916cdSFrançois Tigeot }
7312c9916cdSFrançois Tigeot 
7322c9916cdSFrançois Tigeot static int wa_add(struct drm_i915_private *dev_priv,
733aee94f86SFrançois Tigeot 		  i915_reg_t addr,
734aee94f86SFrançois Tigeot 		  const u32 mask, const u32 val)
7352c9916cdSFrançois Tigeot {
7362c9916cdSFrançois Tigeot 	const u32 idx = dev_priv->workarounds.count;
7372c9916cdSFrançois Tigeot 
7382c9916cdSFrançois Tigeot 	if (WARN_ON(idx >= I915_MAX_WA_REGS))
7392c9916cdSFrançois Tigeot 		return -ENOSPC;
7402c9916cdSFrançois Tigeot 
7412c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].addr = addr;
7422c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].value = val;
7432c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].mask = mask;
7442c9916cdSFrançois Tigeot 
7452c9916cdSFrançois Tigeot 	dev_priv->workarounds.count++;
7462c9916cdSFrançois Tigeot 
7472c9916cdSFrançois Tigeot 	return 0;
7482c9916cdSFrançois Tigeot }
7492c9916cdSFrançois Tigeot 
750a05eeebfSFrançois Tigeot #define WA_REG(addr, mask, val) do { \
7512c9916cdSFrançois Tigeot 		const int r = wa_add(dev_priv, (addr), (mask), (val)); \
7522c9916cdSFrançois Tigeot 		if (r) \
7532c9916cdSFrançois Tigeot 			return r; \
754a05eeebfSFrançois Tigeot 	} while (0)
7552c9916cdSFrançois Tigeot 
7562c9916cdSFrançois Tigeot #define WA_SET_BIT_MASKED(addr, mask) \
7572c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask))
7582c9916cdSFrançois Tigeot 
7592c9916cdSFrançois Tigeot #define WA_CLR_BIT_MASKED(addr, mask) \
7602c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_DISABLE(mask))
7612c9916cdSFrançois Tigeot 
7622c9916cdSFrançois Tigeot #define WA_SET_FIELD_MASKED(addr, mask, value) \
7632c9916cdSFrançois Tigeot 	WA_REG(addr, mask, _MASKED_FIELD(mask, value))
7642c9916cdSFrançois Tigeot 
7652c9916cdSFrançois Tigeot #define WA_SET_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) | (mask))
7662c9916cdSFrançois Tigeot #define WA_CLR_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) & ~(mask))
7672c9916cdSFrançois Tigeot 
7682c9916cdSFrançois Tigeot #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
7692c9916cdSFrançois Tigeot 
7708621f407SFrançois Tigeot static int wa_ring_whitelist_reg(struct intel_engine_cs *engine,
7718621f407SFrançois Tigeot 				 i915_reg_t reg)
772c0e85e96SFrançois Tigeot {
7731487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
774c0e85e96SFrançois Tigeot 	struct i915_workarounds *wa = &dev_priv->workarounds;
7758621f407SFrançois Tigeot 	const uint32_t index = wa->hw_whitelist_count[engine->id];
776c0e85e96SFrançois Tigeot 
777c0e85e96SFrançois Tigeot 	if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS))
778c0e85e96SFrançois Tigeot 		return -EINVAL;
779c0e85e96SFrançois Tigeot 
7808621f407SFrançois Tigeot 	WA_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index),
781c0e85e96SFrançois Tigeot 		 i915_mmio_reg_offset(reg));
7828621f407SFrançois Tigeot 	wa->hw_whitelist_count[engine->id]++;
783c0e85e96SFrançois Tigeot 
784c0e85e96SFrançois Tigeot 	return 0;
785c0e85e96SFrançois Tigeot }
786c0e85e96SFrançois Tigeot 
7878621f407SFrançois Tigeot static int gen8_init_workarounds(struct intel_engine_cs *engine)
7882c9916cdSFrançois Tigeot {
7891487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
7902c9916cdSFrançois Tigeot 
791a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
792a05eeebfSFrançois Tigeot 
793352ff8bdSFrançois Tigeot 	/* WaDisableAsyncFlipPerfMode:bdw,chv */
794a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE);
795a05eeebfSFrançois Tigeot 
796352ff8bdSFrançois Tigeot 	/* WaDisablePartialInstShootdown:bdw,chv */
7972c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
798352ff8bdSFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
7991b13d190SFrançois Tigeot 
8001b13d190SFrançois Tigeot 	/* Use Force Non-Coherent whenever executing a 3D context. This is a
8011b13d190SFrançois Tigeot 	 * workaround for for a possible hang in the unlikely event a TLB
8021b13d190SFrançois Tigeot 	 * invalidation occurs during a PSD flush.
8031b13d190SFrançois Tigeot 	 */
804352ff8bdSFrançois Tigeot 	/* WaForceEnableNonCoherent:bdw,chv */
805352ff8bdSFrançois Tigeot 	/* WaHdcDisableFetchWhenMasked:bdw,chv */
8062c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
8072c9916cdSFrançois Tigeot 			  HDC_DONOT_FETCH_MEM_WHEN_MASKED |
808352ff8bdSFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
8092c9916cdSFrançois Tigeot 
8102c9916cdSFrançois Tigeot 	/* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
8112c9916cdSFrançois Tigeot 	 * "The Hierarchical Z RAW Stall Optimization allows non-overlapping
8122c9916cdSFrançois Tigeot 	 *  polygons in the same 8x4 pixel/sample area to be processed without
8132c9916cdSFrançois Tigeot 	 *  stalling waiting for the earlier ones to write to Hierarchical Z
8142c9916cdSFrançois Tigeot 	 *  buffer."
8152c9916cdSFrançois Tigeot 	 *
816352ff8bdSFrançois Tigeot 	 * This optimization is off by default for BDW and CHV; turn it on.
8172c9916cdSFrançois Tigeot 	 */
8182c9916cdSFrançois Tigeot 	WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
8191b13d190SFrançois Tigeot 
820352ff8bdSFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:bdw,chv */
821352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
8221b13d190SFrançois Tigeot 
8231b13d190SFrançois Tigeot 	/*
8241b13d190SFrançois Tigeot 	 * BSpec recommends 8x4 when MSAA is used,
8251b13d190SFrançois Tigeot 	 * however in practice 16x4 seems fastest.
8261b13d190SFrançois Tigeot 	 *
8271b13d190SFrançois Tigeot 	 * Note that PS/WM thread counts depend on the WIZ hashing
8281b13d190SFrançois Tigeot 	 * disable bit, which we don't touch here, but it's good
8291b13d190SFrançois Tigeot 	 * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
8301b13d190SFrançois Tigeot 	 */
8312c9916cdSFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
8322c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_MASK,
8332c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_16x4);
8341b13d190SFrançois Tigeot 
8351b13d190SFrançois Tigeot 	return 0;
8361b13d190SFrançois Tigeot }
8371b13d190SFrançois Tigeot 
8388621f407SFrançois Tigeot static int bdw_init_workarounds(struct intel_engine_cs *engine)
8391b13d190SFrançois Tigeot {
8401487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
841352ff8bdSFrançois Tigeot 	int ret;
8421b13d190SFrançois Tigeot 
8438621f407SFrançois Tigeot 	ret = gen8_init_workarounds(engine);
844352ff8bdSFrançois Tigeot 	if (ret)
845352ff8bdSFrançois Tigeot 		return ret;
846a05eeebfSFrançois Tigeot 
847352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bdw (pre-production) */
848352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
849a05eeebfSFrançois Tigeot 
850352ff8bdSFrançois Tigeot 	/* WaDisableDopClockGating:bdw */
851352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
852352ff8bdSFrançois Tigeot 			  DOP_CLOCK_GATING_DISABLE);
8531b13d190SFrançois Tigeot 
854352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
855352ff8bdSFrançois Tigeot 			  GEN8_SAMPLER_POWER_BYPASS_DIS);
856352ff8bdSFrançois Tigeot 
8572c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
858352ff8bdSFrançois Tigeot 			  /* WaForceContextSaveRestoreNonCoherent:bdw */
859352ff8bdSFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
860352ff8bdSFrançois Tigeot 			  /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
8611487f786SFrançois Tigeot 			  (IS_BDW_GT3(dev_priv) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
8621b13d190SFrançois Tigeot 
863352ff8bdSFrançois Tigeot 	return 0;
864352ff8bdSFrançois Tigeot }
8651b13d190SFrançois Tigeot 
8668621f407SFrançois Tigeot static int chv_init_workarounds(struct intel_engine_cs *engine)
867352ff8bdSFrançois Tigeot {
8681487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
869352ff8bdSFrançois Tigeot 	int ret;
870352ff8bdSFrançois Tigeot 
8718621f407SFrançois Tigeot 	ret = gen8_init_workarounds(engine);
872352ff8bdSFrançois Tigeot 	if (ret)
873352ff8bdSFrançois Tigeot 		return ret;
874352ff8bdSFrançois Tigeot 
875352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:chv */
876352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
8772c9916cdSFrançois Tigeot 
8782c9916cdSFrançois Tigeot 	/* Improve HiZ throughput on CHV. */
8792c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
8802c9916cdSFrançois Tigeot 
8812c9916cdSFrançois Tigeot 	return 0;
8822c9916cdSFrançois Tigeot }
8832c9916cdSFrançois Tigeot 
8848621f407SFrançois Tigeot static int gen9_init_workarounds(struct intel_engine_cs *engine)
885477eb7f9SFrançois Tigeot {
8861487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
887c0e85e96SFrançois Tigeot 	int ret;
888477eb7f9SFrançois Tigeot 
8898621f407SFrançois Tigeot 	/* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl */
8908621f407SFrançois Tigeot 	I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE));
8918621f407SFrançois Tigeot 
8928621f407SFrançois Tigeot 	/* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl */
893352ff8bdSFrançois Tigeot 	I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
894352ff8bdSFrançois Tigeot 		   GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
895352ff8bdSFrançois Tigeot 
8968621f407SFrançois Tigeot 	/* WaDisableKillLogic:bxt,skl,kbl */
897352ff8bdSFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
898352ff8bdSFrançois Tigeot 		   ECOCHK_DIS_TLB);
899352ff8bdSFrançois Tigeot 
9008621f407SFrançois Tigeot 	/* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl */
9018621f407SFrançois Tigeot 	/* WaDisablePartialInstShootdown:skl,bxt,kbl */
902477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
9038621f407SFrançois Tigeot 			  FLOW_CONTROL_ENABLE |
904477eb7f9SFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
905477eb7f9SFrançois Tigeot 
9068621f407SFrançois Tigeot 	/* Syncing dependencies between camera and graphics:skl,bxt,kbl */
907477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
908477eb7f9SFrançois Tigeot 			  GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
909477eb7f9SFrançois Tigeot 
91019c468b4SFrançois Tigeot 	/* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
9111487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
9121487f786SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
913477eb7f9SFrançois Tigeot 		WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
914477eb7f9SFrançois Tigeot 				  GEN9_DG_MIRROR_FIX_ENABLE);
915477eb7f9SFrançois Tigeot 
91619c468b4SFrançois Tigeot 	/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
9171487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_B0) ||
9181487f786SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
919477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
920477eb7f9SFrançois Tigeot 				  GEN9_RHWO_OPTIMIZATION_DISABLE);
921a05eeebfSFrançois Tigeot 		/*
922a05eeebfSFrançois Tigeot 		 * WA also requires GEN9_SLICE_COMMON_ECO_CHICKEN0[14:14] to be set
923a05eeebfSFrançois Tigeot 		 * but we do that in per ctx batchbuffer as there is an issue
924a05eeebfSFrançois Tigeot 		 * with this register not getting restored on ctx restore
925a05eeebfSFrançois Tigeot 		 */
926477eb7f9SFrançois Tigeot 	}
927477eb7f9SFrançois Tigeot 
9288621f407SFrançois Tigeot 	/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl */
9298621f407SFrançois Tigeot 	/* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl */
930477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
9318621f407SFrançois Tigeot 			  GEN9_ENABLE_YV12_BUGFIX |
9328621f407SFrançois Tigeot 			  GEN9_ENABLE_GPGPU_PREEMPTION);
933477eb7f9SFrançois Tigeot 
9348621f407SFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:skl,bxt,kbl */
9358621f407SFrançois Tigeot 	/* WaDisablePartialResolveInVc:skl,bxt,kbl */
936352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE |
937352ff8bdSFrançois Tigeot 					 GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE));
938477eb7f9SFrançois Tigeot 
9398621f407SFrançois Tigeot 	/* WaCcsTlbPrefetchDisable:skl,bxt,kbl */
940477eb7f9SFrançois Tigeot 	WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
941477eb7f9SFrançois Tigeot 			  GEN9_CCS_TLB_PREFETCH_ENABLE);
942477eb7f9SFrançois Tigeot 
94319c468b4SFrançois Tigeot 	/* WaDisableMaskBasedCammingInRCC:skl,bxt */
9441487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_C0) ||
9451487f786SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
94619c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
94719c468b4SFrançois Tigeot 				  PIXEL_MASK_CAMMING_DISABLE);
94819c468b4SFrançois Tigeot 
9498621f407SFrançois Tigeot 	/* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl */
9508621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
9518621f407SFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
9528621f407SFrançois Tigeot 			  HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE);
95319c468b4SFrançois Tigeot 
9548621f407SFrançois Tigeot 	/* WaForceEnableNonCoherent and WaDisableHDCInvalidation are
9558621f407SFrançois Tigeot 	 * both tied to WaForceContextSaveRestoreNonCoherent
9568621f407SFrançois Tigeot 	 * in some hsds for skl. We keep the tie for all gen9. The
9578621f407SFrançois Tigeot 	 * documentation is a bit hazy and so we want to get common behaviour,
9588621f407SFrançois Tigeot 	 * even though there is no clear evidence we would need both on kbl/bxt.
9598621f407SFrançois Tigeot 	 * This area has been source of system hangs so we play it safe
9608621f407SFrançois Tigeot 	 * and mimic the skl regardless of what bspec says.
9618621f407SFrançois Tigeot 	 *
9628621f407SFrançois Tigeot 	 * Use Force Non-Coherent whenever executing a 3D context. This
9638621f407SFrançois Tigeot 	 * is a workaround for a possible hang in the unlikely event
9648621f407SFrançois Tigeot 	 * a TLB invalidation occurs during a PSD flush.
9658621f407SFrançois Tigeot 	 */
9668621f407SFrançois Tigeot 
9678621f407SFrançois Tigeot 	/* WaForceEnableNonCoherent:skl,bxt,kbl */
9688621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
9698621f407SFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
9708621f407SFrançois Tigeot 
9718621f407SFrançois Tigeot 	/* WaDisableHDCInvalidation:skl,bxt,kbl */
9728621f407SFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
9738621f407SFrançois Tigeot 		   BDW_DISABLE_HDC_INVALIDATION);
9748621f407SFrançois Tigeot 
9758621f407SFrançois Tigeot 	/* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl */
9768621f407SFrançois Tigeot 	if (IS_SKYLAKE(dev_priv) ||
9778621f407SFrançois Tigeot 	    IS_KABYLAKE(dev_priv) ||
9788621f407SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
979352ff8bdSFrançois Tigeot 		WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
980352ff8bdSFrançois Tigeot 				  GEN8_SAMPLER_POWER_BYPASS_DIS);
981352ff8bdSFrançois Tigeot 
9828621f407SFrançois Tigeot 	/* WaDisableSTUnitPowerOptimization:skl,bxt,kbl */
983352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
984352ff8bdSFrançois Tigeot 
9858621f407SFrançois Tigeot 	/* WaOCLCoherentLineFlush:skl,bxt,kbl */
986c0e85e96SFrançois Tigeot 	I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) |
987c0e85e96SFrançois Tigeot 				    GEN8_LQSC_FLUSH_COHERENT_LINES));
988c0e85e96SFrançois Tigeot 
9898621f407SFrançois Tigeot 	/* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt */
9908621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG);
991c0e85e96SFrançois Tigeot 	if (ret)
992c0e85e96SFrançois Tigeot 		return ret;
993c0e85e96SFrançois Tigeot 
9948621f407SFrançois Tigeot 	/* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl */
9958621f407SFrançois Tigeot 	ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1);
9968621f407SFrançois Tigeot 	if (ret)
9978621f407SFrançois Tigeot 		return ret;
9988621f407SFrançois Tigeot 
9998621f407SFrançois Tigeot 	/* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl */
10008621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1);
1001c0e85e96SFrançois Tigeot 	if (ret)
1002c0e85e96SFrançois Tigeot 		return ret;
1003c0e85e96SFrançois Tigeot 
1004477eb7f9SFrançois Tigeot 	return 0;
1005477eb7f9SFrançois Tigeot }
1006477eb7f9SFrançois Tigeot 
10078621f407SFrançois Tigeot static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
1008477eb7f9SFrançois Tigeot {
10091487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1010477eb7f9SFrançois Tigeot 	u8 vals[3] = { 0, 0, 0 };
1011477eb7f9SFrançois Tigeot 	unsigned int i;
1012477eb7f9SFrançois Tigeot 
1013477eb7f9SFrançois Tigeot 	for (i = 0; i < 3; i++) {
1014477eb7f9SFrançois Tigeot 		u8 ss;
1015477eb7f9SFrançois Tigeot 
1016477eb7f9SFrançois Tigeot 		/*
1017477eb7f9SFrançois Tigeot 		 * Only consider slices where one, and only one, subslice has 7
1018477eb7f9SFrançois Tigeot 		 * EUs
1019477eb7f9SFrançois Tigeot 		 */
1020aee94f86SFrançois Tigeot 		if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
1021477eb7f9SFrançois Tigeot 			continue;
1022477eb7f9SFrançois Tigeot 
1023477eb7f9SFrançois Tigeot 		/*
1024477eb7f9SFrançois Tigeot 		 * subslice_7eu[i] != 0 (because of the check above) and
1025477eb7f9SFrançois Tigeot 		 * ss_max == 4 (maximum number of subslices possible per slice)
1026477eb7f9SFrançois Tigeot 		 *
1027477eb7f9SFrançois Tigeot 		 * ->    0 <= ss <= 3;
1028477eb7f9SFrançois Tigeot 		 */
1029477eb7f9SFrançois Tigeot 		ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
1030477eb7f9SFrançois Tigeot 		vals[i] = 3 - ss;
1031477eb7f9SFrançois Tigeot 	}
1032477eb7f9SFrançois Tigeot 
1033477eb7f9SFrançois Tigeot 	if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0)
1034477eb7f9SFrançois Tigeot 		return 0;
1035477eb7f9SFrançois Tigeot 
1036477eb7f9SFrançois Tigeot 	/* Tune IZ hashing. See intel_device_info_runtime_init() */
1037477eb7f9SFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
1038477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(2) |
1039477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(1) |
1040477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(0),
1041477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(2, vals[2]) |
1042477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(1, vals[1]) |
1043477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(0, vals[0]));
1044477eb7f9SFrançois Tigeot 
1045477eb7f9SFrançois Tigeot 	return 0;
1046477eb7f9SFrançois Tigeot }
1047477eb7f9SFrançois Tigeot 
10488621f407SFrançois Tigeot static int skl_init_workarounds(struct intel_engine_cs *engine)
1049477eb7f9SFrançois Tigeot {
10501487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1051352ff8bdSFrançois Tigeot 	int ret;
1052477eb7f9SFrançois Tigeot 
10538621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
1054352ff8bdSFrançois Tigeot 	if (ret)
1055352ff8bdSFrançois Tigeot 		return ret;
1056352ff8bdSFrançois Tigeot 
1057c0e85e96SFrançois Tigeot 	/*
1058c0e85e96SFrançois Tigeot 	 * Actual WA is to disable percontext preemption granularity control
1059c0e85e96SFrançois Tigeot 	 * until D0 which is the default case so this is equivalent to
1060c0e85e96SFrançois Tigeot 	 * !WaDisablePerCtxtPreemptionGranularityControl:skl
1061c0e85e96SFrançois Tigeot 	 */
10621487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_E0, REVID_FOREVER)) {
1063c0e85e96SFrançois Tigeot 		I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
1064c0e85e96SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
1065c0e85e96SFrançois Tigeot 	}
1066c0e85e96SFrançois Tigeot 
10671487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0)) {
1068352ff8bdSFrançois Tigeot 		/* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
1069352ff8bdSFrançois Tigeot 		I915_WRITE(FF_SLICE_CS_CHICKEN2,
1070352ff8bdSFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
1071352ff8bdSFrançois Tigeot 	}
1072352ff8bdSFrançois Tigeot 
1073352ff8bdSFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
1074352ff8bdSFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
1075352ff8bdSFrançois Tigeot 	 */
10761487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_E0))
1077352ff8bdSFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:skl */
1078352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
1079352ff8bdSFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
1080352ff8bdSFrançois Tigeot 
1081352ff8bdSFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:skl */
10821487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, REVID_FOREVER)) {
1083352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
1084352ff8bdSFrançois Tigeot 					   GEN9_GAPS_TSV_CREDIT_DISABLE));
1085352ff8bdSFrançois Tigeot 	}
1086477eb7f9SFrançois Tigeot 
1087477eb7f9SFrançois Tigeot 	/* WaDisablePowerCompilerClockGating:skl */
10881487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_B0, SKL_REVID_B0))
1089477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(HIZ_CHICKEN,
1090477eb7f9SFrançois Tigeot 				  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
1091477eb7f9SFrançois Tigeot 
1092a05eeebfSFrançois Tigeot 	/* WaBarrierPerformanceFixDisable:skl */
10931487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_C0, SKL_REVID_D0))
1094a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
1095a05eeebfSFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE |
1096a05eeebfSFrançois Tigeot 				  HDC_BARRIER_PERFORMANCE_DISABLE);
1097a05eeebfSFrançois Tigeot 
1098a05eeebfSFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:skl */
10991487f786SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, 0, SKL_REVID_F0))
1100a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(
1101a05eeebfSFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
1102a05eeebfSFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
1103a05eeebfSFrançois Tigeot 
11048621f407SFrançois Tigeot 	/* WaDisableGafsUnitClkGating:skl */
11058621f407SFrançois Tigeot 	WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
11068621f407SFrançois Tigeot 
1107bf017597SFrançois Tigeot 	/* WaInPlaceDecompressionHang:skl */
1108bf017597SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER))
1109bf017597SFrançois Tigeot 		WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
1110bf017597SFrançois Tigeot 			   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
1111bf017597SFrançois Tigeot 
1112c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:skl */
11138621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
1114c0e85e96SFrançois Tigeot 	if (ret)
1115c0e85e96SFrançois Tigeot 		return ret;
1116c0e85e96SFrançois Tigeot 
11178621f407SFrançois Tigeot 	return skl_tune_iz_hashing(engine);
1118477eb7f9SFrançois Tigeot }
1119477eb7f9SFrançois Tigeot 
11208621f407SFrançois Tigeot static int bxt_init_workarounds(struct intel_engine_cs *engine)
112119c468b4SFrançois Tigeot {
11221487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1123352ff8bdSFrançois Tigeot 	int ret;
112419c468b4SFrançois Tigeot 
11258621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
1126352ff8bdSFrançois Tigeot 	if (ret)
1127352ff8bdSFrançois Tigeot 		return ret;
1128352ff8bdSFrançois Tigeot 
1129352ff8bdSFrançois Tigeot 	/* WaStoreMultiplePTEenable:bxt */
1130352ff8bdSFrançois Tigeot 	/* This is a requirement according to Hardware specification */
11311487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1))
1132352ff8bdSFrançois Tigeot 		I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
1133352ff8bdSFrançois Tigeot 
1134352ff8bdSFrançois Tigeot 	/* WaSetClckGatingDisableMedia:bxt */
11351487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
1136352ff8bdSFrançois Tigeot 		I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
1137352ff8bdSFrançois Tigeot 					    ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
1138352ff8bdSFrançois Tigeot 	}
113919c468b4SFrançois Tigeot 
114019c468b4SFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bxt */
114119c468b4SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
114219c468b4SFrançois Tigeot 			  STALL_DOP_GATING_DISABLE);
114319c468b4SFrançois Tigeot 
11441487f786SFrançois Tigeot 	/* WaDisablePooledEuLoadBalancingFix:bxt */
11451487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER)) {
11461487f786SFrançois Tigeot 		WA_SET_BIT_MASKED(FF_SLICE_CS_CHICKEN2,
11471487f786SFrançois Tigeot 				  GEN9_POOLED_EU_LOAD_BALANCING_FIX_DISABLE);
11481487f786SFrançois Tigeot 	}
11491487f786SFrançois Tigeot 
115019c468b4SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:bxt */
11511487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0)) {
115219c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(
115319c468b4SFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
115419c468b4SFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
115519c468b4SFrançois Tigeot 	}
115619c468b4SFrançois Tigeot 
1157c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt */
1158c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForInstancedDraw:bxt */
1159c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemtionForInstanceId:bxt */
1160c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:bxt */
11611487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) {
11628621f407SFrançois Tigeot 		ret = wa_ring_whitelist_reg(engine, GEN9_CS_DEBUG_MODE1);
1163c0e85e96SFrançois Tigeot 		if (ret)
1164c0e85e96SFrançois Tigeot 			return ret;
1165c0e85e96SFrançois Tigeot 
11668621f407SFrançois Tigeot 		ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
1167c0e85e96SFrançois Tigeot 		if (ret)
1168c0e85e96SFrançois Tigeot 			return ret;
1169c0e85e96SFrançois Tigeot 	}
1170c0e85e96SFrançois Tigeot 
11711487f786SFrançois Tigeot 	/* WaProgramL3SqcReg1DefaultForPerf:bxt */
11721487f786SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER))
11731487f786SFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG1, L3_GENERAL_PRIO_CREDITS(62) |
11741487f786SFrançois Tigeot 					   L3_HIGH_PRIO_CREDITS(2));
11751487f786SFrançois Tigeot 
1176bf017597SFrançois Tigeot 	/* WaToEnableHwFixForPushConstHWBug:bxt */
1177bf017597SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_C0, REVID_FOREVER))
11788621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
11798621f407SFrançois Tigeot 				  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
11808621f407SFrançois Tigeot 
1181bf017597SFrançois Tigeot 	/* WaInPlaceDecompressionHang:bxt */
1182bf017597SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_C0, REVID_FOREVER))
1183bf017597SFrançois Tigeot 		WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
1184bf017597SFrançois Tigeot 			   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
1185bf017597SFrançois Tigeot 
118619c468b4SFrançois Tigeot 	return 0;
118719c468b4SFrançois Tigeot }
118819c468b4SFrançois Tigeot 
11898621f407SFrançois Tigeot static int kbl_init_workarounds(struct intel_engine_cs *engine)
11902c9916cdSFrançois Tigeot {
11911487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
11928621f407SFrançois Tigeot 	int ret;
11938621f407SFrançois Tigeot 
11948621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
11958621f407SFrançois Tigeot 	if (ret)
11968621f407SFrançois Tigeot 		return ret;
11978621f407SFrançois Tigeot 
11988621f407SFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:kbl */
11998621f407SFrançois Tigeot 	I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
12008621f407SFrançois Tigeot 				   GEN9_GAPS_TSV_CREDIT_DISABLE));
12018621f407SFrançois Tigeot 
12028621f407SFrançois Tigeot 	/* WaDisableDynamicCreditSharing:kbl */
12038621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
12048621f407SFrançois Tigeot 		WA_SET_BIT(GAMT_CHKN_BIT_REG,
12058621f407SFrançois Tigeot 			   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING);
12068621f407SFrançois Tigeot 
12078621f407SFrançois Tigeot 	/* WaDisableFenceDestinationToSLM:kbl (pre-prod) */
12088621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0))
12098621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
12108621f407SFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE);
12118621f407SFrançois Tigeot 
12128621f407SFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
12138621f407SFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
12148621f407SFrançois Tigeot 	 */
12158621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
12168621f407SFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:kbl */
12178621f407SFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
12188621f407SFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
12198621f407SFrançois Tigeot 
1220bf017597SFrançois Tigeot 	/* WaToEnableHwFixForPushConstHWBug:kbl */
1221bf017597SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER))
12228621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
12238621f407SFrançois Tigeot 				  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
12248621f407SFrançois Tigeot 
12258621f407SFrançois Tigeot 	/* WaDisableGafsUnitClkGating:kbl */
12268621f407SFrançois Tigeot 	WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
12278621f407SFrançois Tigeot 
12288621f407SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:kbl */
12298621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(
12308621f407SFrançois Tigeot 		GEN7_HALF_SLICE_CHICKEN1,
12318621f407SFrançois Tigeot 		GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
12328621f407SFrançois Tigeot 
1233bf017597SFrançois Tigeot 	/* WaInPlaceDecompressionHang:kbl */
1234bf017597SFrançois Tigeot 	WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
1235bf017597SFrançois Tigeot 		   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
1236bf017597SFrançois Tigeot 
12378621f407SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:kbl */
12388621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
12398621f407SFrançois Tigeot 	if (ret)
12408621f407SFrançois Tigeot 		return ret;
12418621f407SFrançois Tigeot 
12428621f407SFrançois Tigeot 	return 0;
12438621f407SFrançois Tigeot }
12448621f407SFrançois Tigeot 
12458621f407SFrançois Tigeot int init_workarounds_ring(struct intel_engine_cs *engine)
12468621f407SFrançois Tigeot {
12471487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
12482c9916cdSFrançois Tigeot 
12498621f407SFrançois Tigeot 	WARN_ON(engine->id != RCS);
12502c9916cdSFrançois Tigeot 
12512c9916cdSFrançois Tigeot 	dev_priv->workarounds.count = 0;
1252c0e85e96SFrançois Tigeot 	dev_priv->workarounds.hw_whitelist_count[RCS] = 0;
12532c9916cdSFrançois Tigeot 
12541487f786SFrançois Tigeot 	if (IS_BROADWELL(dev_priv))
12558621f407SFrançois Tigeot 		return bdw_init_workarounds(engine);
12562c9916cdSFrançois Tigeot 
12571487f786SFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv))
12588621f407SFrançois Tigeot 		return chv_init_workarounds(engine);
12591b13d190SFrançois Tigeot 
12601487f786SFrançois Tigeot 	if (IS_SKYLAKE(dev_priv))
12618621f407SFrançois Tigeot 		return skl_init_workarounds(engine);
126219c468b4SFrançois Tigeot 
12631487f786SFrançois Tigeot 	if (IS_BROXTON(dev_priv))
12648621f407SFrançois Tigeot 		return bxt_init_workarounds(engine);
12658621f407SFrançois Tigeot 
12668621f407SFrançois Tigeot 	if (IS_KABYLAKE(dev_priv))
12678621f407SFrançois Tigeot 		return kbl_init_workarounds(engine);
1268477eb7f9SFrançois Tigeot 
12691b13d190SFrançois Tigeot 	return 0;
12701b13d190SFrançois Tigeot }
12711b13d190SFrançois Tigeot 
12728621f407SFrançois Tigeot static int init_render_ring(struct intel_engine_cs *engine)
1273e3adcf8fSFrançois Tigeot {
12741487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
12758621f407SFrançois Tigeot 	int ret = init_ring_common(engine);
127624edb884SFrançois Tigeot 	if (ret)
127724edb884SFrançois Tigeot 		return ret;
1278e3adcf8fSFrançois Tigeot 
1279ba55f2f5SFrançois Tigeot 	/* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */
12801487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 4, 6))
1281f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
1282f4e1c372SFrançois Tigeot 
1283f4e1c372SFrançois Tigeot 	/* We need to disable the AsyncFlip performance optimisations in order
1284f4e1c372SFrançois Tigeot 	 * to use MI_WAIT_FOR_EVENT within the CS. It should already be
1285f4e1c372SFrançois Tigeot 	 * programmed to '1' on all products.
12865d0b1887SFrançois Tigeot 	 *
1287a05eeebfSFrançois Tigeot 	 * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
1288f4e1c372SFrançois Tigeot 	 */
12891487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 6, 7))
1290f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
1291f4e1c372SFrançois Tigeot 
1292f4e1c372SFrançois Tigeot 	/* Required for the hardware to program scanline values for waiting */
1293ba55f2f5SFrançois Tigeot 	/* WaEnableFlushTlbInvalidationMode:snb */
12941487f786SFrançois Tigeot 	if (IS_GEN6(dev_priv))
1295f4e1c372SFrançois Tigeot 		I915_WRITE(GFX_MODE,
1296ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT));
1297f4e1c372SFrançois Tigeot 
1298ba55f2f5SFrançois Tigeot 	/* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */
12991487f786SFrançois Tigeot 	if (IS_GEN7(dev_priv))
1300e3adcf8fSFrançois Tigeot 		I915_WRITE(GFX_MODE_GEN7,
1301ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
1302f4e1c372SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
1303e3adcf8fSFrançois Tigeot 
13041487f786SFrançois Tigeot 	if (IS_GEN6(dev_priv)) {
1305e3adcf8fSFrançois Tigeot 		/* From the Sandybridge PRM, volume 1 part 3, page 24:
1306e3adcf8fSFrançois Tigeot 		 * "If this bit is set, STCunit will have LRA as replacement
1307e3adcf8fSFrançois Tigeot 		 *  policy. [...] This bit must be reset.  LRA replacement
1308e3adcf8fSFrançois Tigeot 		 *  policy is not supported."
1309e3adcf8fSFrançois Tigeot 		 */
1310e3adcf8fSFrançois Tigeot 		I915_WRITE(CACHE_MODE_0,
1311f4e1c372SFrançois Tigeot 			   _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
1312e3adcf8fSFrançois Tigeot 	}
1313e3adcf8fSFrançois Tigeot 
13141487f786SFrançois Tigeot 	if (IS_GEN(dev_priv, 6, 7))
1315f4e1c372SFrançois Tigeot 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
1316f4e1c372SFrançois Tigeot 
1317303bf270SFrançois Tigeot 	if (INTEL_INFO(dev_priv)->gen >= 6)
1318303bf270SFrançois Tigeot 		I915_WRITE_IMR(engine, ~engine->irq_keep_mask);
1319e3adcf8fSFrançois Tigeot 
13208621f407SFrançois Tigeot 	return init_workarounds_ring(engine);
1321e3adcf8fSFrançois Tigeot }
1322e3adcf8fSFrançois Tigeot 
13238621f407SFrançois Tigeot static void render_ring_cleanup(struct intel_engine_cs *engine)
1324e3adcf8fSFrançois Tigeot {
13251487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
132624edb884SFrançois Tigeot 
132724edb884SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
132824edb884SFrançois Tigeot 		i915_gem_object_ggtt_unpin(dev_priv->semaphore_obj);
1329*87df8fc6SFrançois Tigeot 		i915_gem_object_put(dev_priv->semaphore_obj);
133024edb884SFrançois Tigeot 		dev_priv->semaphore_obj = NULL;
133124edb884SFrançois Tigeot 	}
1332b5c29a34SFrançois Tigeot 
13338621f407SFrançois Tigeot 	intel_fini_pipe_control(engine);
1334e3adcf8fSFrançois Tigeot }
1335e3adcf8fSFrançois Tigeot 
1336a05eeebfSFrançois Tigeot static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req,
133724edb884SFrançois Tigeot 			   unsigned int num_dwords)
133824edb884SFrançois Tigeot {
133924edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 8
13408621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
13411487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = signaller_req->i915;
134224edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
13438621f407SFrançois Tigeot 	enum intel_engine_id id;
13448621f407SFrançois Tigeot 	int ret, num_rings;
134524edb884SFrançois Tigeot 
13461487f786SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
134724edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
134824edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
134924edb884SFrançois Tigeot 
1350a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
135124edb884SFrançois Tigeot 	if (ret)
135224edb884SFrançois Tigeot 		return ret;
135324edb884SFrançois Tigeot 
13548621f407SFrançois Tigeot 	for_each_engine_id(waiter, dev_priv, id) {
13558621f407SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
135624edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
135724edb884SFrançois Tigeot 			continue;
135824edb884SFrançois Tigeot 
135924edb884SFrançois Tigeot 		intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
136024edb884SFrançois Tigeot 		intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
136124edb884SFrançois Tigeot 					   PIPE_CONTROL_QW_WRITE |
13621487f786SFrançois Tigeot 					   PIPE_CONTROL_CS_STALL);
136324edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset));
136424edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
1365*87df8fc6SFrançois Tigeot 		intel_ring_emit(signaller, signaller_req->fence.seqno);
136624edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
136724edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
13688621f407SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->hw_id));
136924edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
137024edb884SFrançois Tigeot 	}
137124edb884SFrançois Tigeot 
137224edb884SFrançois Tigeot 	return 0;
137324edb884SFrançois Tigeot }
137424edb884SFrançois Tigeot 
1375a05eeebfSFrançois Tigeot static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req,
137624edb884SFrançois Tigeot 			   unsigned int num_dwords)
137724edb884SFrançois Tigeot {
137824edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 6
13798621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
13801487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = signaller_req->i915;
138124edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
13828621f407SFrançois Tigeot 	enum intel_engine_id id;
13838621f407SFrançois Tigeot 	int ret, num_rings;
138424edb884SFrançois Tigeot 
13851487f786SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
138624edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
138724edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
138824edb884SFrançois Tigeot 
1389a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
139024edb884SFrançois Tigeot 	if (ret)
139124edb884SFrançois Tigeot 		return ret;
139224edb884SFrançois Tigeot 
13938621f407SFrançois Tigeot 	for_each_engine_id(waiter, dev_priv, id) {
13948621f407SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
139524edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
139624edb884SFrançois Tigeot 			continue;
139724edb884SFrançois Tigeot 
139824edb884SFrançois Tigeot 		intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
139924edb884SFrançois Tigeot 					   MI_FLUSH_DW_OP_STOREDW);
140024edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
140124edb884SFrançois Tigeot 					   MI_FLUSH_DW_USE_GTT);
140224edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
1403*87df8fc6SFrançois Tigeot 		intel_ring_emit(signaller, signaller_req->fence.seqno);
140424edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
14058621f407SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->hw_id));
140624edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
140724edb884SFrançois Tigeot 	}
140824edb884SFrançois Tigeot 
140924edb884SFrançois Tigeot 	return 0;
141024edb884SFrançois Tigeot }
141124edb884SFrançois Tigeot 
1412a05eeebfSFrançois Tigeot static int gen6_signal(struct drm_i915_gem_request *signaller_req,
1413ba55f2f5SFrançois Tigeot 		       unsigned int num_dwords)
1414e3adcf8fSFrançois Tigeot {
14158621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
14161487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = signaller_req->i915;
1417ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *useless;
14188621f407SFrançois Tigeot 	enum intel_engine_id id;
14198621f407SFrançois Tigeot 	int ret, num_rings;
1420ba55f2f5SFrançois Tigeot 
142124edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 3
14221487f786SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev_priv)->ring_mask);
142324edb884SFrançois Tigeot 	num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2);
142424edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
1425ba55f2f5SFrançois Tigeot 
1426a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
1427ba55f2f5SFrançois Tigeot 	if (ret)
1428ba55f2f5SFrançois Tigeot 		return ret;
1429ba55f2f5SFrançois Tigeot 
14308621f407SFrançois Tigeot 	for_each_engine_id(useless, dev_priv, id) {
14318621f407SFrançois Tigeot 		i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[id];
1432aee94f86SFrançois Tigeot 
1433aee94f86SFrançois Tigeot 		if (i915_mmio_reg_valid(mbox_reg)) {
1434ba55f2f5SFrançois Tigeot 			intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
1435aee94f86SFrançois Tigeot 			intel_ring_emit_reg(signaller, mbox_reg);
1436*87df8fc6SFrançois Tigeot 			intel_ring_emit(signaller, signaller_req->fence.seqno);
1437ba55f2f5SFrançois Tigeot 		}
1438ba55f2f5SFrançois Tigeot 	}
1439ba55f2f5SFrançois Tigeot 
144024edb884SFrançois Tigeot 	/* If num_dwords was rounded, make sure the tail pointer is correct */
144124edb884SFrançois Tigeot 	if (num_rings % 2 == 0)
144224edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_NOOP);
144324edb884SFrançois Tigeot 
1444ba55f2f5SFrançois Tigeot 	return 0;
1445e3adcf8fSFrançois Tigeot }
1446e3adcf8fSFrançois Tigeot 
1447e3adcf8fSFrançois Tigeot /**
1448e3adcf8fSFrançois Tigeot  * gen6_add_request - Update the semaphore mailbox registers
1449e3adcf8fSFrançois Tigeot  *
1450a05eeebfSFrançois Tigeot  * @request - request to write to the ring
1451e3adcf8fSFrançois Tigeot  *
1452e3adcf8fSFrançois Tigeot  * Update the mailbox registers in the *other* rings with the current seqno.
1453e3adcf8fSFrançois Tigeot  * This acts like a signal in the canonical semaphore.
1454e3adcf8fSFrançois Tigeot  */
1455e3adcf8fSFrançois Tigeot static int
1456a05eeebfSFrançois Tigeot gen6_add_request(struct drm_i915_gem_request *req)
1457e3adcf8fSFrançois Tigeot {
14588621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1459ba55f2f5SFrançois Tigeot 	int ret;
1460e3adcf8fSFrançois Tigeot 
14618621f407SFrançois Tigeot 	if (engine->semaphore.signal)
14628621f407SFrançois Tigeot 		ret = engine->semaphore.signal(req, 4);
146324edb884SFrançois Tigeot 	else
1464a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 4);
146524edb884SFrançois Tigeot 
14669edbd4a0SFrançois Tigeot 	if (ret)
14679edbd4a0SFrançois Tigeot 		return ret;
14689edbd4a0SFrançois Tigeot 
14698621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
14708621f407SFrançois Tigeot 	intel_ring_emit(engine,
14718621f407SFrançois Tigeot 			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
1472*87df8fc6SFrançois Tigeot 	intel_ring_emit(engine, req->fence.seqno);
14738621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
14748621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1475e3adcf8fSFrançois Tigeot 
1476e3adcf8fSFrançois Tigeot 	return 0;
1477e3adcf8fSFrançois Tigeot }
1478e3adcf8fSFrançois Tigeot 
14791487f786SFrançois Tigeot static int
14801487f786SFrançois Tigeot gen8_render_add_request(struct drm_i915_gem_request *req)
14811487f786SFrançois Tigeot {
14821487f786SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
14831487f786SFrançois Tigeot 	int ret;
14841487f786SFrançois Tigeot 
14851487f786SFrançois Tigeot 	if (engine->semaphore.signal)
14861487f786SFrançois Tigeot 		ret = engine->semaphore.signal(req, 8);
14871487f786SFrançois Tigeot 	else
14881487f786SFrançois Tigeot 		ret = intel_ring_begin(req, 8);
14891487f786SFrançois Tigeot 	if (ret)
14901487f786SFrançois Tigeot 		return ret;
14911487f786SFrançois Tigeot 
14921487f786SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
14931487f786SFrançois Tigeot 	intel_ring_emit(engine, (PIPE_CONTROL_GLOBAL_GTT_IVB |
14941487f786SFrançois Tigeot 				 PIPE_CONTROL_CS_STALL |
14951487f786SFrançois Tigeot 				 PIPE_CONTROL_QW_WRITE));
14961487f786SFrançois Tigeot 	intel_ring_emit(engine, intel_hws_seqno_address(req->engine));
14971487f786SFrançois Tigeot 	intel_ring_emit(engine, 0);
14981487f786SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
14991487f786SFrançois Tigeot 	/* We're thrashing one dword of HWS. */
15001487f786SFrançois Tigeot 	intel_ring_emit(engine, 0);
15011487f786SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
15021487f786SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
15031487f786SFrançois Tigeot 	__intel_ring_advance(engine);
15041487f786SFrançois Tigeot 
15051487f786SFrançois Tigeot 	return 0;
15061487f786SFrançois Tigeot }
15071487f786SFrançois Tigeot 
15081487f786SFrançois Tigeot static inline bool i915_gem_has_seqno_wrapped(struct drm_i915_private *dev_priv,
1509a2fdbec6SFrançois Tigeot 					      u32 seqno)
1510a2fdbec6SFrançois Tigeot {
1511a2fdbec6SFrançois Tigeot 	return dev_priv->last_seqno < seqno;
1512a2fdbec6SFrançois Tigeot }
1513a2fdbec6SFrançois Tigeot 
1514e3adcf8fSFrançois Tigeot /**
1515e3adcf8fSFrançois Tigeot  * intel_ring_sync - sync the waiter to the signaller on seqno
1516e3adcf8fSFrançois Tigeot  *
1517e3adcf8fSFrançois Tigeot  * @waiter - ring that is waiting
1518e3adcf8fSFrançois Tigeot  * @signaller - ring which has, or will signal
1519e3adcf8fSFrançois Tigeot  * @seqno - seqno which the waiter will block on
1520e3adcf8fSFrançois Tigeot  */
152124edb884SFrançois Tigeot 
152224edb884SFrançois Tigeot static int
1523a05eeebfSFrançois Tigeot gen8_ring_sync(struct drm_i915_gem_request *waiter_req,
152424edb884SFrançois Tigeot 	       struct intel_engine_cs *signaller,
152524edb884SFrançois Tigeot 	       u32 seqno)
152624edb884SFrançois Tigeot {
15278621f407SFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->engine;
15281487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = waiter_req->i915;
15291487f786SFrançois Tigeot 	u64 offset = GEN8_WAIT_OFFSET(waiter, signaller->id);
15301487f786SFrançois Tigeot 	struct i915_hw_ppgtt *ppgtt;
153124edb884SFrançois Tigeot 	int ret;
153224edb884SFrançois Tigeot 
1533a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
153424edb884SFrançois Tigeot 	if (ret)
153524edb884SFrançois Tigeot 		return ret;
153624edb884SFrançois Tigeot 
153724edb884SFrançois Tigeot 	intel_ring_emit(waiter, MI_SEMAPHORE_WAIT |
153824edb884SFrançois Tigeot 				MI_SEMAPHORE_GLOBAL_GTT |
153924edb884SFrançois Tigeot 				MI_SEMAPHORE_SAD_GTE_SDD);
154024edb884SFrançois Tigeot 	intel_ring_emit(waiter, seqno);
15411487f786SFrançois Tigeot 	intel_ring_emit(waiter, lower_32_bits(offset));
15421487f786SFrançois Tigeot 	intel_ring_emit(waiter, upper_32_bits(offset));
154324edb884SFrançois Tigeot 	intel_ring_advance(waiter);
15441487f786SFrançois Tigeot 
15451487f786SFrançois Tigeot 	/* When the !RCS engines idle waiting upon a semaphore, they lose their
15461487f786SFrançois Tigeot 	 * pagetables and we must reload them before executing the batch.
15471487f786SFrançois Tigeot 	 * We do this on the i915_switch_context() following the wait and
15481487f786SFrançois Tigeot 	 * before the dispatch.
15491487f786SFrançois Tigeot 	 */
15501487f786SFrançois Tigeot 	ppgtt = waiter_req->ctx->ppgtt;
15511487f786SFrançois Tigeot 	if (ppgtt && waiter_req->engine->id != RCS)
15521487f786SFrançois Tigeot 		ppgtt->pd_dirty_rings |= intel_engine_flag(waiter_req->engine);
155324edb884SFrançois Tigeot 	return 0;
155424edb884SFrançois Tigeot }
155524edb884SFrançois Tigeot 
1556e3adcf8fSFrançois Tigeot static int
1557a05eeebfSFrançois Tigeot gen6_ring_sync(struct drm_i915_gem_request *waiter_req,
1558ba55f2f5SFrançois Tigeot 	       struct intel_engine_cs *signaller,
1559e3adcf8fSFrançois Tigeot 	       u32 seqno)
1560e3adcf8fSFrançois Tigeot {
15618621f407SFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->engine;
1562e3adcf8fSFrançois Tigeot 	u32 dw1 = MI_SEMAPHORE_MBOX |
1563e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_COMPARE |
1564e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_REGISTER;
1565ba55f2f5SFrançois Tigeot 	u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id];
1566ba55f2f5SFrançois Tigeot 	int ret;
1567e3adcf8fSFrançois Tigeot 
1568686a02f1SFrançois Tigeot 	/* Throughout all of the GEM code, seqno passed implies our current
1569686a02f1SFrançois Tigeot 	 * seqno is >= the last seqno executed. However for hardware the
1570686a02f1SFrançois Tigeot 	 * comparison is strictly greater than.
1571686a02f1SFrançois Tigeot 	 */
1572686a02f1SFrançois Tigeot 	seqno -= 1;
1573686a02f1SFrançois Tigeot 
1574ba55f2f5SFrançois Tigeot 	WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
1575686a02f1SFrançois Tigeot 
1576a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
1577e3adcf8fSFrançois Tigeot 	if (ret)
1578e3adcf8fSFrançois Tigeot 		return ret;
1579e3adcf8fSFrançois Tigeot 
1580a2fdbec6SFrançois Tigeot 	/* If seqno wrap happened, omit the wait with no-ops */
15811487f786SFrançois Tigeot 	if (likely(!i915_gem_has_seqno_wrapped(waiter_req->i915, seqno))) {
1582ba55f2f5SFrançois Tigeot 		intel_ring_emit(waiter, dw1 | wait_mbox);
1583e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, seqno);
1584e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, 0);
1585e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1586a2fdbec6SFrançois Tigeot 	} else {
1587a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1588a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1589a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1590a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1591a2fdbec6SFrançois Tigeot 	}
1592e3adcf8fSFrançois Tigeot 	intel_ring_advance(waiter);
1593e3adcf8fSFrançois Tigeot 
1594e3adcf8fSFrançois Tigeot 	return 0;
1595e3adcf8fSFrançois Tigeot }
1596e3adcf8fSFrançois Tigeot 
1597303bf270SFrançois Tigeot static void
1598*87df8fc6SFrançois Tigeot gen5_seqno_barrier(struct intel_engine_cs *engine)
1599e3adcf8fSFrançois Tigeot {
1600303bf270SFrançois Tigeot 	/* MI_STORE are internally buffered by the GPU and not flushed
1601303bf270SFrançois Tigeot 	 * either by MI_FLUSH or SyncFlush or any other combination of
1602303bf270SFrançois Tigeot 	 * MI commands.
1603e3adcf8fSFrançois Tigeot 	 *
1604303bf270SFrançois Tigeot 	 * "Only the submission of the store operation is guaranteed.
1605303bf270SFrançois Tigeot 	 * The write result will be complete (coherent) some time later
1606303bf270SFrançois Tigeot 	 * (this is practically a finite period but there is no guaranteed
1607303bf270SFrançois Tigeot 	 * latency)."
1608303bf270SFrançois Tigeot 	 *
1609303bf270SFrançois Tigeot 	 * Empirically, we observe that we need a delay of at least 75us to
1610303bf270SFrançois Tigeot 	 * be sure that the seqno write is visible by the CPU.
1611e3adcf8fSFrançois Tigeot 	 */
1612303bf270SFrançois Tigeot 	usleep_range(125, 250);
1613e3adcf8fSFrançois Tigeot }
1614e3adcf8fSFrançois Tigeot 
16158621f407SFrançois Tigeot static void
16168621f407SFrançois Tigeot gen6_seqno_barrier(struct intel_engine_cs *engine)
1617e3adcf8fSFrançois Tigeot {
16181487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
16198621f407SFrançois Tigeot 
1620e3adcf8fSFrançois Tigeot 	/* Workaround to force correct ordering between irq and seqno writes on
1621e3adcf8fSFrançois Tigeot 	 * ivb (and maybe also on snb) by reading from a CS register (like
16228621f407SFrançois Tigeot 	 * ACTHD) before reading the status page.
16238621f407SFrançois Tigeot 	 *
16248621f407SFrançois Tigeot 	 * Note that this effectively stalls the read by the time it takes to
16258621f407SFrançois Tigeot 	 * do a memory transaction, which more or less ensures that the write
16268621f407SFrançois Tigeot 	 * from the GPU has sufficient time to invalidate the CPU cacheline.
16278621f407SFrançois Tigeot 	 * Alternatively we could delay the interrupt from the CS ring to give
16288621f407SFrançois Tigeot 	 * the write time to land, but that would incur a delay after every
16298621f407SFrançois Tigeot 	 * batch i.e. much more frequent than a delay when waiting for the
16308621f407SFrançois Tigeot 	 * interrupt (with the same net latency).
16318621f407SFrançois Tigeot 	 *
16328621f407SFrançois Tigeot 	 * Also note that to prevent whole machine hangs on gen7, we have to
16338621f407SFrançois Tigeot 	 * take the spinlock to guard against concurrent cacheline access.
16348621f407SFrançois Tigeot 	 */
16358621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->uncore.lock);
16368621f407SFrançois Tigeot 	POSTING_READ_FW(RING_ACTHD(engine->mmio_base));
16378621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->uncore.lock);
1638e3adcf8fSFrançois Tigeot }
1639e3adcf8fSFrançois Tigeot 
1640303bf270SFrançois Tigeot static void
1641303bf270SFrançois Tigeot gen5_irq_enable(struct intel_engine_cs *engine)
1642e3adcf8fSFrançois Tigeot {
1643303bf270SFrançois Tigeot 	gen5_enable_gt_irq(engine->i915, engine->irq_enable_mask);
1644e3adcf8fSFrançois Tigeot }
1645e3adcf8fSFrançois Tigeot 
1646a2fdbec6SFrançois Tigeot static void
1647303bf270SFrançois Tigeot gen5_irq_disable(struct intel_engine_cs *engine)
1648a2fdbec6SFrançois Tigeot {
1649303bf270SFrançois Tigeot 	gen5_disable_gt_irq(engine->i915, engine->irq_enable_mask);
1650e3adcf8fSFrançois Tigeot }
1651e3adcf8fSFrançois Tigeot 
1652a2fdbec6SFrançois Tigeot static void
1653303bf270SFrançois Tigeot i9xx_irq_enable(struct intel_engine_cs *engine)
1654e3adcf8fSFrançois Tigeot {
16551487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1656e3adcf8fSFrançois Tigeot 
16578621f407SFrançois Tigeot 	dev_priv->irq_mask &= ~engine->irq_enable_mask;
1658686a02f1SFrançois Tigeot 	I915_WRITE(IMR, dev_priv->irq_mask);
1659303bf270SFrançois Tigeot 	POSTING_READ_FW(RING_IMR(engine->mmio_base));
1660686a02f1SFrançois Tigeot }
1661686a02f1SFrançois Tigeot 
1662686a02f1SFrançois Tigeot static void
1663303bf270SFrançois Tigeot i9xx_irq_disable(struct intel_engine_cs *engine)
1664686a02f1SFrançois Tigeot {
16651487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1666686a02f1SFrançois Tigeot 
16678621f407SFrançois Tigeot 	dev_priv->irq_mask |= engine->irq_enable_mask;
1668686a02f1SFrançois Tigeot 	I915_WRITE(IMR, dev_priv->irq_mask);
1669686a02f1SFrançois Tigeot }
1670686a02f1SFrançois Tigeot 
1671686a02f1SFrançois Tigeot static void
1672303bf270SFrançois Tigeot i8xx_irq_enable(struct intel_engine_cs *engine)
1673686a02f1SFrançois Tigeot {
16741487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1675686a02f1SFrançois Tigeot 
1676303bf270SFrançois Tigeot 	dev_priv->irq_mask &= ~engine->irq_enable_mask;
1677303bf270SFrançois Tigeot 	I915_WRITE16(IMR, dev_priv->irq_mask);
1678303bf270SFrançois Tigeot 	POSTING_READ16(RING_IMR(engine->mmio_base));
1679303bf270SFrançois Tigeot }
1680303bf270SFrançois Tigeot 
1681303bf270SFrançois Tigeot static void
1682303bf270SFrançois Tigeot i8xx_irq_disable(struct intel_engine_cs *engine)
1683303bf270SFrançois Tigeot {
1684303bf270SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1685303bf270SFrançois Tigeot 
16868621f407SFrançois Tigeot 	dev_priv->irq_mask |= engine->irq_enable_mask;
1687686a02f1SFrançois Tigeot 	I915_WRITE16(IMR, dev_priv->irq_mask);
1688e3adcf8fSFrançois Tigeot }
1689e3adcf8fSFrançois Tigeot 
1690e3adcf8fSFrançois Tigeot static int
1691a05eeebfSFrançois Tigeot bsd_ring_flush(struct drm_i915_gem_request *req,
1692b5c29a34SFrançois Tigeot 	       u32     invalidate_domains,
1693b5c29a34SFrançois Tigeot 	       u32     flush_domains)
1694e3adcf8fSFrançois Tigeot {
16958621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1696e3adcf8fSFrançois Tigeot 	int ret;
1697e3adcf8fSFrançois Tigeot 
1698a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1699e3adcf8fSFrançois Tigeot 	if (ret)
1700e3adcf8fSFrançois Tigeot 		return ret;
1701e3adcf8fSFrançois Tigeot 
17028621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_FLUSH);
17038621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
17048621f407SFrançois Tigeot 	intel_ring_advance(engine);
1705e3adcf8fSFrançois Tigeot 	return 0;
1706e3adcf8fSFrançois Tigeot }
1707e3adcf8fSFrançois Tigeot 
1708e3adcf8fSFrançois Tigeot static int
1709a05eeebfSFrançois Tigeot i9xx_add_request(struct drm_i915_gem_request *req)
1710e3adcf8fSFrançois Tigeot {
17118621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1712e3adcf8fSFrançois Tigeot 	int ret;
1713e3adcf8fSFrançois Tigeot 
1714a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
1715e3adcf8fSFrançois Tigeot 	if (ret)
1716e3adcf8fSFrançois Tigeot 		return ret;
1717e3adcf8fSFrançois Tigeot 
17188621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
17198621f407SFrançois Tigeot 	intel_ring_emit(engine,
17208621f407SFrançois Tigeot 			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
1721*87df8fc6SFrançois Tigeot 	intel_ring_emit(engine, req->fence.seqno);
17228621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
17238621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1724e3adcf8fSFrançois Tigeot 
1725e3adcf8fSFrançois Tigeot 	return 0;
1726e3adcf8fSFrançois Tigeot }
1727e3adcf8fSFrançois Tigeot 
1728303bf270SFrançois Tigeot static void
1729303bf270SFrançois Tigeot gen6_irq_enable(struct intel_engine_cs *engine)
1730e3adcf8fSFrançois Tigeot {
17311487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1732e3adcf8fSFrançois Tigeot 
17338621f407SFrançois Tigeot 	I915_WRITE_IMR(engine,
17348621f407SFrançois Tigeot 		       ~(engine->irq_enable_mask |
1735303bf270SFrançois Tigeot 			 engine->irq_keep_mask));
17368621f407SFrançois Tigeot 	gen5_enable_gt_irq(dev_priv, engine->irq_enable_mask);
1737e3adcf8fSFrançois Tigeot }
1738e3adcf8fSFrançois Tigeot 
1739e3adcf8fSFrançois Tigeot static void
1740303bf270SFrançois Tigeot gen6_irq_disable(struct intel_engine_cs *engine)
1741e3adcf8fSFrançois Tigeot {
17421487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1743e3adcf8fSFrançois Tigeot 
1744303bf270SFrançois Tigeot 	I915_WRITE_IMR(engine, ~engine->irq_keep_mask);
17458621f407SFrançois Tigeot 	gen5_disable_gt_irq(dev_priv, engine->irq_enable_mask);
1746e3adcf8fSFrançois Tigeot }
1747e3adcf8fSFrançois Tigeot 
1748303bf270SFrançois Tigeot static void
1749303bf270SFrançois Tigeot hsw_vebox_irq_enable(struct intel_engine_cs *engine)
17505d0b1887SFrançois Tigeot {
17511487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17525d0b1887SFrançois Tigeot 
17538621f407SFrançois Tigeot 	I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
17548621f407SFrançois Tigeot 	gen6_enable_pm_irq(dev_priv, engine->irq_enable_mask);
17555d0b1887SFrançois Tigeot }
17565d0b1887SFrançois Tigeot 
17575d0b1887SFrançois Tigeot static void
1758303bf270SFrançois Tigeot hsw_vebox_irq_disable(struct intel_engine_cs *engine)
17595d0b1887SFrançois Tigeot {
17601487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17615d0b1887SFrançois Tigeot 
17628621f407SFrançois Tigeot 	I915_WRITE_IMR(engine, ~0);
17638621f407SFrançois Tigeot 	gen6_disable_pm_irq(dev_priv, engine->irq_enable_mask);
17645d0b1887SFrançois Tigeot }
17659edbd4a0SFrançois Tigeot 
1766303bf270SFrançois Tigeot static void
1767303bf270SFrançois Tigeot gen8_irq_enable(struct intel_engine_cs *engine)
17689edbd4a0SFrançois Tigeot {
17691487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17709edbd4a0SFrançois Tigeot 
17718621f407SFrançois Tigeot 	I915_WRITE_IMR(engine,
17728621f407SFrançois Tigeot 		       ~(engine->irq_enable_mask |
1773303bf270SFrançois Tigeot 			 engine->irq_keep_mask));
1774303bf270SFrançois Tigeot 	POSTING_READ_FW(RING_IMR(engine->mmio_base));
17759edbd4a0SFrançois Tigeot }
17769edbd4a0SFrançois Tigeot 
17779edbd4a0SFrançois Tigeot static void
1778303bf270SFrançois Tigeot gen8_irq_disable(struct intel_engine_cs *engine)
17799edbd4a0SFrançois Tigeot {
17801487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
17819edbd4a0SFrançois Tigeot 
1782303bf270SFrançois Tigeot 	I915_WRITE_IMR(engine, ~engine->irq_keep_mask);
17835d0b1887SFrançois Tigeot }
17845d0b1887SFrançois Tigeot 
1785e3adcf8fSFrançois Tigeot static int
1786a05eeebfSFrançois Tigeot i965_dispatch_execbuffer(struct drm_i915_gem_request *req,
1787ba55f2f5SFrançois Tigeot 			 u64 offset, u32 length,
1788477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1789e3adcf8fSFrançois Tigeot {
17908621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1791e3adcf8fSFrançois Tigeot 	int ret;
1792e3adcf8fSFrançois Tigeot 
1793a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1794e3adcf8fSFrançois Tigeot 	if (ret)
1795e3adcf8fSFrançois Tigeot 		return ret;
1796e3adcf8fSFrançois Tigeot 
17978621f407SFrançois Tigeot 	intel_ring_emit(engine,
1798686a02f1SFrançois Tigeot 			MI_BATCH_BUFFER_START |
1799b5c29a34SFrançois Tigeot 			MI_BATCH_GTT |
1800477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
1801477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
18028621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
18038621f407SFrançois Tigeot 	intel_ring_advance(engine);
1804e3adcf8fSFrançois Tigeot 
1805e3adcf8fSFrançois Tigeot 	return 0;
1806e3adcf8fSFrançois Tigeot }
1807e3adcf8fSFrançois Tigeot 
1808b5c29a34SFrançois Tigeot /* Just userspace ABI convention to limit the wa batch bo to a resonable size */
1809b5c29a34SFrançois Tigeot #define I830_BATCH_LIMIT (256*1024)
181024edb884SFrançois Tigeot #define I830_TLB_ENTRIES (2)
181124edb884SFrançois Tigeot #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
1812e3adcf8fSFrançois Tigeot static int
1813a05eeebfSFrançois Tigeot i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
1814ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
1815477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1816e3adcf8fSFrançois Tigeot {
18178621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
18188621f407SFrançois Tigeot 	u32 cs_offset = engine->scratch.gtt_offset;
1819e3adcf8fSFrançois Tigeot 	int ret;
1820e3adcf8fSFrançois Tigeot 
1821a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
182224edb884SFrançois Tigeot 	if (ret)
182324edb884SFrançois Tigeot 		return ret;
182424edb884SFrançois Tigeot 
182524edb884SFrançois Tigeot 	/* Evict the invalid PTE TLBs */
18268621f407SFrançois Tigeot 	intel_ring_emit(engine, COLOR_BLT_CMD | BLT_WRITE_RGBA);
18278621f407SFrançois Tigeot 	intel_ring_emit(engine, BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | 4096);
18288621f407SFrançois Tigeot 	intel_ring_emit(engine, I830_TLB_ENTRIES << 16 | 4); /* load each page */
18298621f407SFrançois Tigeot 	intel_ring_emit(engine, cs_offset);
18308621f407SFrançois Tigeot 	intel_ring_emit(engine, 0xdeadbeef);
18318621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
18328621f407SFrançois Tigeot 	intel_ring_advance(engine);
183324edb884SFrançois Tigeot 
1834477eb7f9SFrançois Tigeot 	if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
183524edb884SFrançois Tigeot 		if (len > I830_BATCH_LIMIT)
183624edb884SFrançois Tigeot 			return -ENOSPC;
183724edb884SFrançois Tigeot 
1838a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 6 + 2);
183924edb884SFrançois Tigeot 		if (ret)
184024edb884SFrançois Tigeot 			return ret;
184124edb884SFrançois Tigeot 
184224edb884SFrançois Tigeot 		/* Blit the batch (which has now all relocs applied) to the
184324edb884SFrançois Tigeot 		 * stable batch scratch bo area (so that the CS never
184424edb884SFrançois Tigeot 		 * stumbles over its tlb invalidation bug) ...
184524edb884SFrançois Tigeot 		 */
18468621f407SFrançois Tigeot 		intel_ring_emit(engine, SRC_COPY_BLT_CMD | BLT_WRITE_RGBA);
18478621f407SFrançois Tigeot 		intel_ring_emit(engine,
18488621f407SFrançois Tigeot 				BLT_DEPTH_32 | BLT_ROP_SRC_COPY | 4096);
18498621f407SFrançois Tigeot 		intel_ring_emit(engine, DIV_ROUND_UP(len, 4096) << 16 | 4096);
18508621f407SFrançois Tigeot 		intel_ring_emit(engine, cs_offset);
18518621f407SFrançois Tigeot 		intel_ring_emit(engine, 4096);
18528621f407SFrançois Tigeot 		intel_ring_emit(engine, offset);
185324edb884SFrançois Tigeot 
18548621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_FLUSH);
18558621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
18568621f407SFrançois Tigeot 		intel_ring_advance(engine);
185724edb884SFrançois Tigeot 
185824edb884SFrançois Tigeot 		/* ... and execute it. */
185924edb884SFrançois Tigeot 		offset = cs_offset;
186024edb884SFrançois Tigeot 	}
186124edb884SFrançois Tigeot 
1862c0e85e96SFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1863e3adcf8fSFrançois Tigeot 	if (ret)
1864e3adcf8fSFrançois Tigeot 		return ret;
1865e3adcf8fSFrançois Tigeot 
18668621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
18678621f407SFrançois Tigeot 	intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
1868477eb7f9SFrançois Tigeot 					  0 : MI_BATCH_NON_SECURE));
18698621f407SFrançois Tigeot 	intel_ring_advance(engine);
1870686a02f1SFrançois Tigeot 
1871686a02f1SFrançois Tigeot 	return 0;
1872686a02f1SFrançois Tigeot }
1873686a02f1SFrançois Tigeot 
1874686a02f1SFrançois Tigeot static int
1875a05eeebfSFrançois Tigeot i915_dispatch_execbuffer(struct drm_i915_gem_request *req,
1876ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
1877477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1878686a02f1SFrançois Tigeot {
18798621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1880686a02f1SFrançois Tigeot 	int ret;
1881686a02f1SFrançois Tigeot 
1882a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1883e3adcf8fSFrançois Tigeot 	if (ret)
1884e3adcf8fSFrançois Tigeot 		return ret;
1885e3adcf8fSFrançois Tigeot 
18868621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
18878621f407SFrançois Tigeot 	intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
1888477eb7f9SFrançois Tigeot 					  0 : MI_BATCH_NON_SECURE));
18898621f407SFrançois Tigeot 	intel_ring_advance(engine);
1890e3adcf8fSFrançois Tigeot 
1891e3adcf8fSFrançois Tigeot 	return 0;
1892e3adcf8fSFrançois Tigeot }
1893e3adcf8fSFrançois Tigeot 
18948621f407SFrançois Tigeot static void cleanup_phys_status_page(struct intel_engine_cs *engine)
1895c0e85e96SFrançois Tigeot {
18961487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1897c0e85e96SFrançois Tigeot 
1898c0e85e96SFrançois Tigeot 	if (!dev_priv->status_page_dmah)
1899c0e85e96SFrançois Tigeot 		return;
1900c0e85e96SFrançois Tigeot 
1901303bf270SFrançois Tigeot 	drm_pci_free(&dev_priv->drm, dev_priv->status_page_dmah);
19028621f407SFrançois Tigeot 	engine->status_page.page_addr = NULL;
1903c0e85e96SFrançois Tigeot }
1904c0e85e96SFrançois Tigeot 
19058621f407SFrançois Tigeot static void cleanup_status_page(struct intel_engine_cs *engine)
1906e3adcf8fSFrançois Tigeot {
1907e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
1908e3adcf8fSFrançois Tigeot 
19098621f407SFrançois Tigeot 	obj = engine->status_page.obj;
1910e3adcf8fSFrançois Tigeot 	if (obj == NULL)
1911e3adcf8fSFrançois Tigeot 		return;
1912e3adcf8fSFrançois Tigeot 
19137ec9f8e5SFrançois Tigeot 	kunmap(sg_page(obj->pages->sgl));
1914ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
1915*87df8fc6SFrançois Tigeot 	i915_gem_object_put(obj);
19168621f407SFrançois Tigeot 	engine->status_page.obj = NULL;
1917e3adcf8fSFrançois Tigeot }
1918e3adcf8fSFrançois Tigeot 
19198621f407SFrançois Tigeot static int init_status_page(struct intel_engine_cs *engine)
1920e3adcf8fSFrançois Tigeot {
19218621f407SFrançois Tigeot 	struct drm_i915_gem_object *obj = engine->status_page.obj;
1922ba55f2f5SFrançois Tigeot 
1923c0e85e96SFrançois Tigeot 	if (obj == NULL) {
192424edb884SFrançois Tigeot 		unsigned flags;
1925e3adcf8fSFrançois Tigeot 		int ret;
1926e3adcf8fSFrançois Tigeot 
1927303bf270SFrançois Tigeot 		obj = i915_gem_object_create(&engine->i915->drm, 4096);
19281487f786SFrançois Tigeot 		if (IS_ERR(obj)) {
1929e3adcf8fSFrançois Tigeot 			DRM_ERROR("Failed to allocate status page\n");
19301487f786SFrançois Tigeot 			return PTR_ERR(obj);
1931e3adcf8fSFrançois Tigeot 		}
1932e3adcf8fSFrançois Tigeot 
1933ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
1934ba55f2f5SFrançois Tigeot 		if (ret)
1935e3adcf8fSFrançois Tigeot 			goto err_unref;
1936ba55f2f5SFrançois Tigeot 
193724edb884SFrançois Tigeot 		flags = 0;
19381487f786SFrançois Tigeot 		if (!HAS_LLC(engine->i915))
193924edb884SFrançois Tigeot 			/* On g33, we cannot place HWS above 256MiB, so
194024edb884SFrançois Tigeot 			 * restrict its pinning to the low mappable arena.
194124edb884SFrançois Tigeot 			 * Though this restriction is not documented for
194224edb884SFrançois Tigeot 			 * gen4, gen5, or byt, they also behave similarly
194324edb884SFrançois Tigeot 			 * and hang if the HWS is placed at the top of the
194424edb884SFrançois Tigeot 			 * GTT. To generalise, it appears that all !llc
194524edb884SFrançois Tigeot 			 * platforms have issues with us placing the HWS
194624edb884SFrançois Tigeot 			 * above the mappable region (even though we never
194724edb884SFrançois Tigeot 			 * actualy map it).
194824edb884SFrançois Tigeot 			 */
194924edb884SFrançois Tigeot 			flags |= PIN_MAPPABLE;
195024edb884SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 4096, flags);
1951ba55f2f5SFrançois Tigeot 		if (ret) {
1952ba55f2f5SFrançois Tigeot err_unref:
1953*87df8fc6SFrançois Tigeot 			i915_gem_object_put(obj);
1954ba55f2f5SFrançois Tigeot 			return ret;
1955ba55f2f5SFrançois Tigeot 		}
1956ba55f2f5SFrançois Tigeot 
19578621f407SFrançois Tigeot 		engine->status_page.obj = obj;
1958e3adcf8fSFrançois Tigeot 	}
1959e3adcf8fSFrançois Tigeot 
19608621f407SFrançois Tigeot 	engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
19618621f407SFrançois Tigeot 	engine->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
19628621f407SFrançois Tigeot 	memset(engine->status_page.page_addr, 0, PAGE_SIZE);
1963e3adcf8fSFrançois Tigeot 
1964b5c29a34SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
19658621f407SFrançois Tigeot 			engine->name, engine->status_page.gfx_addr);
1966e3adcf8fSFrançois Tigeot 
1967e3adcf8fSFrançois Tigeot 	return 0;
1968e3adcf8fSFrançois Tigeot }
1969e3adcf8fSFrançois Tigeot 
19708621f407SFrançois Tigeot static int init_phys_status_page(struct intel_engine_cs *engine)
1971686a02f1SFrançois Tigeot {
19721487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
1973686a02f1SFrançois Tigeot 
1974686a02f1SFrançois Tigeot 	if (!dev_priv->status_page_dmah) {
1975686a02f1SFrançois Tigeot 		dev_priv->status_page_dmah =
1976303bf270SFrançois Tigeot 			drm_pci_alloc(&dev_priv->drm, PAGE_SIZE, PAGE_SIZE);
1977686a02f1SFrançois Tigeot 		if (!dev_priv->status_page_dmah)
1978686a02f1SFrançois Tigeot 			return -ENOMEM;
1979686a02f1SFrançois Tigeot 	}
1980686a02f1SFrançois Tigeot 
19818621f407SFrançois Tigeot 	engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
19828621f407SFrançois Tigeot 	memset(engine->status_page.page_addr, 0, PAGE_SIZE);
1983686a02f1SFrançois Tigeot 
1984686a02f1SFrançois Tigeot 	return 0;
1985686a02f1SFrançois Tigeot }
1986686a02f1SFrançois Tigeot 
19872c9916cdSFrançois Tigeot void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
19882c9916cdSFrançois Tigeot {
1989*87df8fc6SFrançois Tigeot 	GEM_BUG_ON(!ringbuf->vma);
1990*87df8fc6SFrançois Tigeot 	GEM_BUG_ON(!ringbuf->vaddr);
19911487f786SFrançois Tigeot 
1992aee94f86SFrançois Tigeot 	if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
19938621f407SFrançois Tigeot 		i915_gem_object_unpin_map(ringbuf->obj);
1994aee94f86SFrançois Tigeot 	else
19951487f786SFrançois Tigeot 		i915_vma_unpin_iomap(ringbuf->vma);
1996*87df8fc6SFrançois Tigeot 	ringbuf->vaddr = NULL;
19971487f786SFrançois Tigeot 
19982c9916cdSFrançois Tigeot 	i915_gem_object_ggtt_unpin(ringbuf->obj);
19991487f786SFrançois Tigeot 	ringbuf->vma = NULL;
20002c9916cdSFrançois Tigeot }
20012c9916cdSFrançois Tigeot 
20021487f786SFrançois Tigeot int intel_pin_and_map_ringbuffer_obj(struct drm_i915_private *dev_priv,
20032c9916cdSFrançois Tigeot 				     struct intel_ringbuffer *ringbuf)
20042c9916cdSFrançois Tigeot {
20052c9916cdSFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
2006c0e85e96SFrançois Tigeot 	/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
2007c0e85e96SFrançois Tigeot 	unsigned flags = PIN_OFFSET_BIAS | 4096;
20088621f407SFrançois Tigeot 	void *addr;
20092c9916cdSFrançois Tigeot 	int ret;
20102c9916cdSFrançois Tigeot 
2011aee94f86SFrançois Tigeot 	if (HAS_LLC(dev_priv) && !obj->stolen) {
2012c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, flags);
2013aee94f86SFrançois Tigeot 		if (ret)
2014aee94f86SFrançois Tigeot 			return ret;
2015aee94f86SFrançois Tigeot 
2016aee94f86SFrançois Tigeot 		ret = i915_gem_object_set_to_cpu_domain(obj, true);
20178621f407SFrançois Tigeot 		if (ret)
20188621f407SFrançois Tigeot 			goto err_unpin;
2019aee94f86SFrançois Tigeot 
20208621f407SFrançois Tigeot 		addr = i915_gem_object_pin_map(obj);
20218621f407SFrançois Tigeot 		if (IS_ERR(addr)) {
20228621f407SFrançois Tigeot 			ret = PTR_ERR(addr);
20238621f407SFrançois Tigeot 			goto err_unpin;
2024aee94f86SFrançois Tigeot 		}
2025aee94f86SFrançois Tigeot 	} else {
2026c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
2027c0e85e96SFrançois Tigeot 					    flags | PIN_MAPPABLE);
20282c9916cdSFrançois Tigeot 		if (ret)
20292c9916cdSFrançois Tigeot 			return ret;
20302c9916cdSFrançois Tigeot 
20312c9916cdSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(obj, true);
20328621f407SFrançois Tigeot 		if (ret)
20338621f407SFrançois Tigeot 			goto err_unpin;
20342c9916cdSFrançois Tigeot 
2035c0e85e96SFrançois Tigeot 		/* Access through the GTT requires the device to be awake. */
2036c0e85e96SFrançois Tigeot 		assert_rpm_wakelock_held(dev_priv);
2037c0e85e96SFrançois Tigeot 
2038*87df8fc6SFrançois Tigeot 		addr = (void __force *)
2039*87df8fc6SFrançois Tigeot 			i915_vma_pin_iomap(i915_gem_obj_to_ggtt(obj));
20401487f786SFrançois Tigeot 		if (IS_ERR(addr)) {
20411487f786SFrançois Tigeot 			ret = PTR_ERR(addr);
20428621f407SFrançois Tigeot 			goto err_unpin;
20432c9916cdSFrançois Tigeot 		}
2044aee94f86SFrançois Tigeot 	}
20452c9916cdSFrançois Tigeot 
2046*87df8fc6SFrançois Tigeot 	ringbuf->vaddr = addr;
2047c0e85e96SFrançois Tigeot 	ringbuf->vma = i915_gem_obj_to_ggtt(obj);
20482c9916cdSFrançois Tigeot 	return 0;
20498621f407SFrançois Tigeot 
20508621f407SFrançois Tigeot err_unpin:
20518621f407SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
20528621f407SFrançois Tigeot 	return ret;
20532c9916cdSFrançois Tigeot }
20542c9916cdSFrançois Tigeot 
2055352ff8bdSFrançois Tigeot static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
2056e3adcf8fSFrançois Tigeot {
2057*87df8fc6SFrançois Tigeot 	i915_gem_object_put(ringbuf->obj);
205824edb884SFrançois Tigeot 	ringbuf->obj = NULL;
205924edb884SFrançois Tigeot }
206024edb884SFrançois Tigeot 
2061352ff8bdSFrançois Tigeot static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
206224edb884SFrançois Tigeot 				      struct intel_ringbuffer *ringbuf)
206324edb884SFrançois Tigeot {
2064e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
2065e3adcf8fSFrançois Tigeot 
2066a2fdbec6SFrançois Tigeot 	obj = NULL;
2067a2fdbec6SFrançois Tigeot 	if (!HAS_LLC(dev))
2068ba55f2f5SFrançois Tigeot 		obj = i915_gem_object_create_stolen(dev, ringbuf->size);
2069a2fdbec6SFrançois Tigeot 	if (obj == NULL)
20701487f786SFrançois Tigeot 		obj = i915_gem_object_create(dev, ringbuf->size);
20711487f786SFrançois Tigeot 	if (IS_ERR(obj))
20721487f786SFrançois Tigeot 		return PTR_ERR(obj);
2073e3adcf8fSFrançois Tigeot 
207424edb884SFrançois Tigeot 	/* mark ring buffers as read-only from GPU side by default */
207524edb884SFrançois Tigeot 	obj->gt_ro = 1;
207624edb884SFrançois Tigeot 
2077ba55f2f5SFrançois Tigeot 	ringbuf->obj = obj;
2078ba55f2f5SFrançois Tigeot 
20792c9916cdSFrançois Tigeot 	return 0;
2080ba55f2f5SFrançois Tigeot }
2081ba55f2f5SFrançois Tigeot 
2082352ff8bdSFrançois Tigeot struct intel_ringbuffer *
2083352ff8bdSFrançois Tigeot intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
2084352ff8bdSFrançois Tigeot {
2085352ff8bdSFrançois Tigeot 	struct intel_ringbuffer *ring;
2086352ff8bdSFrançois Tigeot 	int ret;
2087352ff8bdSFrançois Tigeot 
2088352ff8bdSFrançois Tigeot 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
2089aee94f86SFrançois Tigeot 	if (ring == NULL) {
2090aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
2091aee94f86SFrançois Tigeot 				 engine->name);
2092352ff8bdSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
2093aee94f86SFrançois Tigeot 	}
2094352ff8bdSFrançois Tigeot 
20958621f407SFrançois Tigeot 	ring->engine = engine;
2096aee94f86SFrançois Tigeot 	list_add(&ring->link, &engine->buffers);
2097352ff8bdSFrançois Tigeot 
2098352ff8bdSFrançois Tigeot 	ring->size = size;
2099352ff8bdSFrançois Tigeot 	/* Workaround an erratum on the i830 which causes a hang if
2100352ff8bdSFrançois Tigeot 	 * the TAIL pointer points to within the last 2 cachelines
2101352ff8bdSFrançois Tigeot 	 * of the buffer.
2102352ff8bdSFrançois Tigeot 	 */
2103352ff8bdSFrançois Tigeot 	ring->effective_size = size;
21041487f786SFrançois Tigeot 	if (IS_I830(engine->i915) || IS_845G(engine->i915))
2105352ff8bdSFrançois Tigeot 		ring->effective_size -= 2 * CACHELINE_BYTES;
2106352ff8bdSFrançois Tigeot 
2107352ff8bdSFrançois Tigeot 	ring->last_retired_head = -1;
2108352ff8bdSFrançois Tigeot 	intel_ring_update_space(ring);
2109352ff8bdSFrançois Tigeot 
2110303bf270SFrançois Tigeot 	ret = intel_alloc_ringbuffer_obj(&engine->i915->drm, ring);
2111352ff8bdSFrançois Tigeot 	if (ret) {
2112aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
2113352ff8bdSFrançois Tigeot 				 engine->name, ret);
2114aee94f86SFrançois Tigeot 		list_del(&ring->link);
2115352ff8bdSFrançois Tigeot 		kfree(ring);
2116352ff8bdSFrançois Tigeot 		return ERR_PTR(ret);
2117352ff8bdSFrançois Tigeot 	}
2118352ff8bdSFrançois Tigeot 
2119352ff8bdSFrançois Tigeot 	return ring;
2120352ff8bdSFrançois Tigeot }
2121352ff8bdSFrançois Tigeot 
2122352ff8bdSFrançois Tigeot void
2123352ff8bdSFrançois Tigeot intel_ringbuffer_free(struct intel_ringbuffer *ring)
2124352ff8bdSFrançois Tigeot {
2125352ff8bdSFrançois Tigeot 	intel_destroy_ringbuffer_obj(ring);
2126aee94f86SFrançois Tigeot 	list_del(&ring->link);
2127352ff8bdSFrançois Tigeot 	kfree(ring);
2128352ff8bdSFrançois Tigeot }
2129352ff8bdSFrançois Tigeot 
21301487f786SFrançois Tigeot static int intel_ring_context_pin(struct i915_gem_context *ctx,
21311487f786SFrançois Tigeot 				  struct intel_engine_cs *engine)
21321487f786SFrançois Tigeot {
21331487f786SFrançois Tigeot 	struct intel_context *ce = &ctx->engine[engine->id];
21341487f786SFrançois Tigeot 	int ret;
21351487f786SFrançois Tigeot 
2136303bf270SFrançois Tigeot 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
21371487f786SFrançois Tigeot 
21381487f786SFrançois Tigeot 	if (ce->pin_count++)
21391487f786SFrançois Tigeot 		return 0;
21401487f786SFrançois Tigeot 
21411487f786SFrançois Tigeot 	if (ce->state) {
21421487f786SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(ce->state, ctx->ggtt_alignment, 0);
21431487f786SFrançois Tigeot 		if (ret)
21441487f786SFrançois Tigeot 			goto error;
21451487f786SFrançois Tigeot 	}
21461487f786SFrançois Tigeot 
21471487f786SFrançois Tigeot 	/* The kernel context is only used as a placeholder for flushing the
21481487f786SFrançois Tigeot 	 * active context. It is never used for submitting user rendering and
21491487f786SFrançois Tigeot 	 * as such never requires the golden render context, and so we can skip
21501487f786SFrançois Tigeot 	 * emitting it when we switch to the kernel context. This is required
21511487f786SFrançois Tigeot 	 * as during eviction we cannot allocate and pin the renderstate in
21521487f786SFrançois Tigeot 	 * order to initialise the context.
21531487f786SFrançois Tigeot 	 */
21541487f786SFrançois Tigeot 	if (ctx == ctx->i915->kernel_context)
21551487f786SFrançois Tigeot 		ce->initialised = true;
21561487f786SFrançois Tigeot 
2157*87df8fc6SFrançois Tigeot 	i915_gem_context_get(ctx);
21581487f786SFrançois Tigeot 	return 0;
21591487f786SFrançois Tigeot 
21601487f786SFrançois Tigeot error:
21611487f786SFrançois Tigeot 	ce->pin_count = 0;
21621487f786SFrançois Tigeot 	return ret;
21631487f786SFrançois Tigeot }
21641487f786SFrançois Tigeot 
21651487f786SFrançois Tigeot static void intel_ring_context_unpin(struct i915_gem_context *ctx,
21661487f786SFrançois Tigeot 				     struct intel_engine_cs *engine)
21671487f786SFrançois Tigeot {
21681487f786SFrançois Tigeot 	struct intel_context *ce = &ctx->engine[engine->id];
21691487f786SFrançois Tigeot 
2170303bf270SFrançois Tigeot 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
21711487f786SFrançois Tigeot 
21721487f786SFrançois Tigeot 	if (--ce->pin_count)
21731487f786SFrançois Tigeot 		return;
21741487f786SFrançois Tigeot 
21751487f786SFrançois Tigeot 	if (ce->state)
21761487f786SFrançois Tigeot 		i915_gem_object_ggtt_unpin(ce->state);
21771487f786SFrançois Tigeot 
2178*87df8fc6SFrançois Tigeot 	i915_gem_context_put(ctx);
21791487f786SFrançois Tigeot }
21801487f786SFrançois Tigeot 
2181*87df8fc6SFrançois Tigeot static int intel_init_ring_buffer(struct intel_engine_cs *engine)
2182ba55f2f5SFrançois Tigeot {
2183*87df8fc6SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
21842c9916cdSFrançois Tigeot 	struct intel_ringbuffer *ringbuf;
2185ba55f2f5SFrançois Tigeot 	int ret;
2186ba55f2f5SFrançois Tigeot 
21878621f407SFrançois Tigeot 	WARN_ON(engine->buffer);
21882c9916cdSFrançois Tigeot 
2189*87df8fc6SFrançois Tigeot 	intel_engine_setup_common(engine);
2190*87df8fc6SFrançois Tigeot 
21918621f407SFrançois Tigeot 	memset(engine->semaphore.sync_seqno, 0,
21928621f407SFrançois Tigeot 	       sizeof(engine->semaphore.sync_seqno));
2193ba55f2f5SFrançois Tigeot 
2194*87df8fc6SFrançois Tigeot 	ret = intel_engine_init_common(engine);
2195303bf270SFrançois Tigeot 	if (ret)
2196303bf270SFrançois Tigeot 		goto error;
2197ba55f2f5SFrançois Tigeot 
21981487f786SFrançois Tigeot 	/* We may need to do things with the shrinker which
21991487f786SFrançois Tigeot 	 * require us to immediately switch back to the default
22001487f786SFrançois Tigeot 	 * context. This can cause a problem as pinning the
22011487f786SFrançois Tigeot 	 * default context also requires GTT space which may not
22021487f786SFrançois Tigeot 	 * be available. To avoid this we always pin the default
22031487f786SFrançois Tigeot 	 * context.
22041487f786SFrançois Tigeot 	 */
22051487f786SFrançois Tigeot 	ret = intel_ring_context_pin(dev_priv->kernel_context, engine);
22061487f786SFrançois Tigeot 	if (ret)
22071487f786SFrançois Tigeot 		goto error;
22081487f786SFrançois Tigeot 
22098621f407SFrançois Tigeot 	ringbuf = intel_engine_create_ringbuffer(engine, 32 * PAGE_SIZE);
2210aee94f86SFrançois Tigeot 	if (IS_ERR(ringbuf)) {
2211aee94f86SFrançois Tigeot 		ret = PTR_ERR(ringbuf);
2212aee94f86SFrançois Tigeot 		goto error;
2213aee94f86SFrançois Tigeot 	}
22148621f407SFrançois Tigeot 	engine->buffer = ringbuf;
2215352ff8bdSFrançois Tigeot 
22161487f786SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev_priv)) {
22178621f407SFrançois Tigeot 		ret = init_status_page(engine);
2218e3adcf8fSFrançois Tigeot 		if (ret)
2219ba55f2f5SFrançois Tigeot 			goto error;
2220ba55f2f5SFrançois Tigeot 	} else {
22218621f407SFrançois Tigeot 		WARN_ON(engine->id != RCS);
22228621f407SFrançois Tigeot 		ret = init_phys_status_page(engine);
2223ba55f2f5SFrançois Tigeot 		if (ret)
2224ba55f2f5SFrançois Tigeot 			goto error;
2225ba55f2f5SFrançois Tigeot 	}
2226ba55f2f5SFrançois Tigeot 
22271487f786SFrançois Tigeot 	ret = intel_pin_and_map_ringbuffer_obj(dev_priv, ringbuf);
22282c9916cdSFrançois Tigeot 	if (ret) {
22292c9916cdSFrançois Tigeot 		DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
22308621f407SFrançois Tigeot 				engine->name, ret);
22312c9916cdSFrançois Tigeot 		intel_destroy_ringbuffer_obj(ringbuf);
2232ba55f2f5SFrançois Tigeot 		goto error;
2233ba55f2f5SFrançois Tigeot 	}
2234e3adcf8fSFrançois Tigeot 
2235e3adcf8fSFrançois Tigeot 	return 0;
2236e3adcf8fSFrançois Tigeot 
2237ba55f2f5SFrançois Tigeot error:
22388621f407SFrançois Tigeot 	intel_cleanup_engine(engine);
2239e3adcf8fSFrançois Tigeot 	return ret;
2240e3adcf8fSFrançois Tigeot }
2241e3adcf8fSFrançois Tigeot 
22428621f407SFrançois Tigeot void intel_cleanup_engine(struct intel_engine_cs *engine)
2243e3adcf8fSFrançois Tigeot {
22442c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv;
2245e3adcf8fSFrançois Tigeot 
22468621f407SFrançois Tigeot 	if (!intel_engine_initialized(engine))
2247e3adcf8fSFrançois Tigeot 		return;
2248e3adcf8fSFrançois Tigeot 
22491487f786SFrançois Tigeot 	dev_priv = engine->i915;
22502c9916cdSFrançois Tigeot 
22518621f407SFrançois Tigeot 	if (engine->buffer) {
22528621f407SFrançois Tigeot 		intel_stop_engine(engine);
22531487f786SFrançois Tigeot 		WARN_ON(!IS_GEN2(dev_priv) && (I915_READ_MODE(engine) & MODE_IDLE) == 0);
2254b030f26bSFrançois Tigeot 
22558621f407SFrançois Tigeot 		intel_unpin_ringbuffer_obj(engine->buffer);
22568621f407SFrançois Tigeot 		intel_ringbuffer_free(engine->buffer);
22578621f407SFrançois Tigeot 		engine->buffer = NULL;
2258aee94f86SFrançois Tigeot 	}
2259e3adcf8fSFrançois Tigeot 
22608621f407SFrançois Tigeot 	if (engine->cleanup)
22618621f407SFrançois Tigeot 		engine->cleanup(engine);
2262e3adcf8fSFrançois Tigeot 
22631487f786SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev_priv)) {
22648621f407SFrançois Tigeot 		cleanup_status_page(engine);
2265c0e85e96SFrançois Tigeot 	} else {
22668621f407SFrançois Tigeot 		WARN_ON(engine->id != RCS);
22678621f407SFrançois Tigeot 		cleanup_phys_status_page(engine);
2268c0e85e96SFrançois Tigeot 	}
2269ba55f2f5SFrançois Tigeot 
22708621f407SFrançois Tigeot 	i915_cmd_parser_fini_ring(engine);
22718621f407SFrançois Tigeot 	i915_gem_batch_pool_fini(&engine->batch_pool);
2272303bf270SFrançois Tigeot 	intel_engine_fini_breadcrumbs(engine);
22731487f786SFrançois Tigeot 
22741487f786SFrançois Tigeot 	intel_ring_context_unpin(dev_priv->kernel_context, engine);
22751487f786SFrançois Tigeot 
22761487f786SFrançois Tigeot 	engine->i915 = NULL;
2277e3adcf8fSFrançois Tigeot }
2278e3adcf8fSFrançois Tigeot 
22798621f407SFrançois Tigeot int intel_engine_idle(struct intel_engine_cs *engine)
2280b030f26bSFrançois Tigeot {
22812c9916cdSFrançois Tigeot 	struct drm_i915_gem_request *req;
2282b5c29a34SFrançois Tigeot 
2283b5c29a34SFrançois Tigeot 	/* Wait upon the last request to be completed */
22848621f407SFrançois Tigeot 	if (list_empty(&engine->request_list))
2285b5c29a34SFrançois Tigeot 		return 0;
2286b5c29a34SFrançois Tigeot 
22878621f407SFrançois Tigeot 	req = list_entry(engine->request_list.prev,
2288b5c29a34SFrançois Tigeot 			 struct drm_i915_gem_request,
22892c9916cdSFrançois Tigeot 			 list);
2290b5c29a34SFrançois Tigeot 
229119c468b4SFrançois Tigeot 	/* Make sure we do not trigger any retires */
229219c468b4SFrançois Tigeot 	return __i915_wait_request(req,
22938621f407SFrançois Tigeot 				   req->i915->mm.interruptible,
229419c468b4SFrançois Tigeot 				   NULL, NULL);
2295b5c29a34SFrançois Tigeot }
2296b5c29a34SFrançois Tigeot 
229719c468b4SFrançois Tigeot int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
2298b5c29a34SFrançois Tigeot {
22991487f786SFrançois Tigeot 	int ret;
23009edbd4a0SFrançois Tigeot 
23011487f786SFrançois Tigeot 	/* Flush enough space to reduce the likelihood of waiting after
23021487f786SFrançois Tigeot 	 * we start building the request - in which case we will just
23031487f786SFrançois Tigeot 	 * have to repeat work.
2304a05eeebfSFrançois Tigeot 	 */
23051487f786SFrançois Tigeot 	request->reserved_space += LEGACY_REQUEST_SIZE;
2306a2fdbec6SFrançois Tigeot 
23071487f786SFrançois Tigeot 	request->ringbuf = request->engine->buffer;
2308a2fdbec6SFrançois Tigeot 
23091487f786SFrançois Tigeot 	ret = intel_ring_begin(request, 0);
23101487f786SFrançois Tigeot 	if (ret)
23111487f786SFrançois Tigeot 		return ret;
2312a05eeebfSFrançois Tigeot 
23131487f786SFrançois Tigeot 	request->reserved_space -= LEGACY_REQUEST_SIZE;
23141487f786SFrançois Tigeot 	return 0;
2315a05eeebfSFrançois Tigeot }
2316a05eeebfSFrançois Tigeot 
23178621f407SFrançois Tigeot static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
2318a05eeebfSFrançois Tigeot {
23198621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = req->ringbuf;
23208621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
23218621f407SFrançois Tigeot 	struct drm_i915_gem_request *target;
23228621f407SFrançois Tigeot 
23238621f407SFrançois Tigeot 	intel_ring_update_space(ringbuf);
23248621f407SFrançois Tigeot 	if (ringbuf->space >= bytes)
23258621f407SFrançois Tigeot 		return 0;
23268621f407SFrançois Tigeot 
23278621f407SFrançois Tigeot 	/*
23288621f407SFrançois Tigeot 	 * Space is reserved in the ringbuffer for finalising the request,
23298621f407SFrançois Tigeot 	 * as that cannot be allowed to fail. During request finalisation,
23308621f407SFrançois Tigeot 	 * reserved_space is set to 0 to stop the overallocation and the
23318621f407SFrançois Tigeot 	 * assumption is that then we never need to wait (which has the
23328621f407SFrançois Tigeot 	 * risk of failing with EINTR).
23338621f407SFrançois Tigeot 	 *
23348621f407SFrançois Tigeot 	 * See also i915_gem_request_alloc() and i915_add_request().
23358621f407SFrançois Tigeot 	 */
23361487f786SFrançois Tigeot 	GEM_BUG_ON(!req->reserved_space);
23378621f407SFrançois Tigeot 
23388621f407SFrançois Tigeot 	list_for_each_entry(target, &engine->request_list, list) {
23398621f407SFrançois Tigeot 		unsigned space;
23408621f407SFrançois Tigeot 
23418621f407SFrançois Tigeot 		/*
23428621f407SFrançois Tigeot 		 * The request queue is per-engine, so can contain requests
23438621f407SFrançois Tigeot 		 * from multiple ringbuffers. Here, we must ignore any that
23448621f407SFrançois Tigeot 		 * aren't from the ringbuffer we're considering.
23458621f407SFrançois Tigeot 		 */
23468621f407SFrançois Tigeot 		if (target->ringbuf != ringbuf)
23478621f407SFrançois Tigeot 			continue;
23488621f407SFrançois Tigeot 
23498621f407SFrançois Tigeot 		/* Would completion of this request free enough space? */
23508621f407SFrançois Tigeot 		space = __intel_ring_space(target->postfix, ringbuf->tail,
23518621f407SFrançois Tigeot 					   ringbuf->size);
23528621f407SFrançois Tigeot 		if (space >= bytes)
23538621f407SFrançois Tigeot 			break;
23548621f407SFrançois Tigeot 	}
23558621f407SFrançois Tigeot 
23568621f407SFrançois Tigeot 	if (WARN_ON(&target->list == &engine->request_list))
23578621f407SFrançois Tigeot 		return -ENOSPC;
23588621f407SFrançois Tigeot 
23598621f407SFrançois Tigeot 	return i915_wait_request(target);
23608621f407SFrançois Tigeot }
23618621f407SFrançois Tigeot 
23628621f407SFrançois Tigeot int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords)
23638621f407SFrançois Tigeot {
23648621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = req->ringbuf;
2365a05eeebfSFrançois Tigeot 	int remain_actual = ringbuf->size - ringbuf->tail;
23668621f407SFrançois Tigeot 	int remain_usable = ringbuf->effective_size - ringbuf->tail;
23678621f407SFrançois Tigeot 	int bytes = num_dwords * sizeof(u32);
23688621f407SFrançois Tigeot 	int total_bytes, wait_bytes;
2369a05eeebfSFrançois Tigeot 	bool need_wrap = false;
2370a05eeebfSFrançois Tigeot 
23711487f786SFrançois Tigeot 	total_bytes = bytes + req->reserved_space;
2372a05eeebfSFrançois Tigeot 
2373a05eeebfSFrançois Tigeot 	if (unlikely(bytes > remain_usable)) {
2374a05eeebfSFrançois Tigeot 		/*
2375a05eeebfSFrançois Tigeot 		 * Not enough space for the basic request. So need to flush
2376a05eeebfSFrançois Tigeot 		 * out the remainder and then wait for base + reserved.
2377a05eeebfSFrançois Tigeot 		 */
2378a05eeebfSFrançois Tigeot 		wait_bytes = remain_actual + total_bytes;
2379a05eeebfSFrançois Tigeot 		need_wrap = true;
23808621f407SFrançois Tigeot 	} else if (unlikely(total_bytes > remain_usable)) {
2381a05eeebfSFrançois Tigeot 		/*
2382a05eeebfSFrançois Tigeot 		 * The base request will fit but the reserved space
23838621f407SFrançois Tigeot 		 * falls off the end. So we don't need an immediate wrap
2384c0e85e96SFrançois Tigeot 		 * and only need to effectively wait for the reserved
2385c0e85e96SFrançois Tigeot 		 * size space from the start of ringbuffer.
2386a05eeebfSFrançois Tigeot 		 */
23871487f786SFrançois Tigeot 		wait_bytes = remain_actual + req->reserved_space;
23888621f407SFrançois Tigeot 	} else {
2389a05eeebfSFrançois Tigeot 		/* No wrapping required, just waiting. */
2390a05eeebfSFrançois Tigeot 		wait_bytes = total_bytes;
2391a05eeebfSFrançois Tigeot 	}
2392a05eeebfSFrançois Tigeot 
23938621f407SFrançois Tigeot 	if (wait_bytes > ringbuf->space) {
23948621f407SFrançois Tigeot 		int ret = wait_for_space(req, wait_bytes);
2395a2fdbec6SFrançois Tigeot 		if (unlikely(ret))
2396a2fdbec6SFrançois Tigeot 			return ret;
2397a05eeebfSFrançois Tigeot 
23988621f407SFrançois Tigeot 		intel_ring_update_space(ringbuf);
23998621f407SFrançois Tigeot 		if (unlikely(ringbuf->space < wait_bytes))
24008621f407SFrançois Tigeot 			return -EAGAIN;
2401a2fdbec6SFrançois Tigeot 	}
2402a2fdbec6SFrançois Tigeot 
24038621f407SFrançois Tigeot 	if (unlikely(need_wrap)) {
24048621f407SFrançois Tigeot 		GEM_BUG_ON(remain_actual > ringbuf->space);
24058621f407SFrançois Tigeot 		GEM_BUG_ON(ringbuf->tail + remain_actual > ringbuf->size);
24068621f407SFrançois Tigeot 
24078621f407SFrançois Tigeot 		/* Fill the tail with MI_NOOP */
2408*87df8fc6SFrançois Tigeot 		memset(ringbuf->vaddr + ringbuf->tail, 0, remain_actual);
24098621f407SFrançois Tigeot 		ringbuf->tail = 0;
24108621f407SFrançois Tigeot 		ringbuf->space -= remain_actual;
2411a2fdbec6SFrançois Tigeot 	}
2412a2fdbec6SFrançois Tigeot 
24138621f407SFrançois Tigeot 	ringbuf->space -= bytes;
24148621f407SFrançois Tigeot 	GEM_BUG_ON(ringbuf->space < 0);
24159edbd4a0SFrançois Tigeot 	return 0;
24169edbd4a0SFrançois Tigeot }
24179edbd4a0SFrançois Tigeot 
24189edbd4a0SFrançois Tigeot /* Align the ring tail to a cacheline boundary */
2419a05eeebfSFrançois Tigeot int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
24209edbd4a0SFrançois Tigeot {
24218621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
24228621f407SFrançois Tigeot 	int num_dwords = (engine->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
24239edbd4a0SFrançois Tigeot 	int ret;
24249edbd4a0SFrançois Tigeot 
24259edbd4a0SFrançois Tigeot 	if (num_dwords == 0)
24269edbd4a0SFrançois Tigeot 		return 0;
24279edbd4a0SFrançois Tigeot 
2428ba55f2f5SFrançois Tigeot 	num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords;
2429a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, num_dwords);
24309edbd4a0SFrançois Tigeot 	if (ret)
24319edbd4a0SFrançois Tigeot 		return ret;
24329edbd4a0SFrançois Tigeot 
24339edbd4a0SFrançois Tigeot 	while (num_dwords--)
24348621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
24359edbd4a0SFrançois Tigeot 
24368621f407SFrançois Tigeot 	intel_ring_advance(engine);
24379edbd4a0SFrançois Tigeot 
24389edbd4a0SFrançois Tigeot 	return 0;
2439e3adcf8fSFrançois Tigeot }
2440e3adcf8fSFrançois Tigeot 
24418621f407SFrançois Tigeot void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno)
2442a2fdbec6SFrançois Tigeot {
24431487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2444a2fdbec6SFrançois Tigeot 
24458621f407SFrançois Tigeot 	/* Our semaphore implementation is strictly monotonic (i.e. we proceed
24468621f407SFrançois Tigeot 	 * so long as the semaphore value in the register/page is greater
24478621f407SFrançois Tigeot 	 * than the sync value), so whenever we reset the seqno,
24488621f407SFrançois Tigeot 	 * so long as we reset the tracking semaphore value to 0, it will
24498621f407SFrançois Tigeot 	 * always be before the next request's seqno. If we don't reset
24508621f407SFrançois Tigeot 	 * the semaphore value, then when the seqno moves backwards all
24518621f407SFrançois Tigeot 	 * future waits will complete instantly (causing rendering corruption).
24528621f407SFrançois Tigeot 	 */
24531487f786SFrançois Tigeot 	if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv)) {
24548621f407SFrançois Tigeot 		I915_WRITE(RING_SYNC_0(engine->mmio_base), 0);
24558621f407SFrançois Tigeot 		I915_WRITE(RING_SYNC_1(engine->mmio_base), 0);
24568621f407SFrançois Tigeot 		if (HAS_VEBOX(dev_priv))
24578621f407SFrançois Tigeot 			I915_WRITE(RING_SYNC_2(engine->mmio_base), 0);
24588621f407SFrançois Tigeot 	}
24598621f407SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
24608621f407SFrançois Tigeot 		struct drm_i915_gem_object *obj = dev_priv->semaphore_obj;
2461f0bba3d1SFrançois Tigeot 		struct page *page = i915_gem_object_get_dirty_page(obj, 0);
24621487f786SFrançois Tigeot 		void *semaphores = kmap(page);
24638621f407SFrançois Tigeot 		memset(semaphores + GEN8_SEMAPHORE_OFFSET(engine->id, 0),
24648621f407SFrançois Tigeot 		       0, I915_NUM_ENGINES * gen8_semaphore_seqno_size);
24658621f407SFrançois Tigeot 		kunmap(page);
24668621f407SFrançois Tigeot 	}
24678621f407SFrançois Tigeot 	memset(engine->semaphore.sync_seqno, 0,
24688621f407SFrançois Tigeot 	       sizeof(engine->semaphore.sync_seqno));
24698621f407SFrançois Tigeot 
2470303bf270SFrançois Tigeot 	intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
2471303bf270SFrançois Tigeot 	if (engine->irq_seqno_barrier)
2472303bf270SFrançois Tigeot 		engine->irq_seqno_barrier(engine);
24738621f407SFrançois Tigeot 	engine->last_submitted_seqno = seqno;
24748621f407SFrançois Tigeot 
24758621f407SFrançois Tigeot 	engine->hangcheck.seqno = seqno;
2476303bf270SFrançois Tigeot 
2477303bf270SFrançois Tigeot 	/* After manually advancing the seqno, fake the interrupt in case
2478303bf270SFrançois Tigeot 	 * there are any waiters for that seqno.
2479303bf270SFrançois Tigeot 	 */
2480303bf270SFrançois Tigeot 	rcu_read_lock();
2481303bf270SFrançois Tigeot 	intel_engine_wakeup(engine);
2482303bf270SFrançois Tigeot 	rcu_read_unlock();
2483e3adcf8fSFrançois Tigeot }
2484e3adcf8fSFrançois Tigeot 
24858621f407SFrançois Tigeot static void gen6_bsd_ring_write_tail(struct intel_engine_cs *engine,
2486f4e1c372SFrançois Tigeot 				     u32 value)
2487e3adcf8fSFrançois Tigeot {
24881487f786SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
24891487f786SFrançois Tigeot 
24901487f786SFrançois Tigeot 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
2491e3adcf8fSFrançois Tigeot 
2492e3adcf8fSFrançois Tigeot        /* Every tail move must follow the sequence below */
2493f4e1c372SFrançois Tigeot 
2494f4e1c372SFrançois Tigeot 	/* Disable notification that the ring is IDLE. The GT
2495f4e1c372SFrançois Tigeot 	 * will then assume that it is busy and bring it out of rc6.
2496f4e1c372SFrançois Tigeot 	 */
24971487f786SFrançois Tigeot 	I915_WRITE_FW(GEN6_BSD_SLEEP_PSMI_CONTROL,
2498f4e1c372SFrançois Tigeot 		      _MASKED_BIT_ENABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2499e3adcf8fSFrançois Tigeot 
2500f4e1c372SFrançois Tigeot 	/* Clear the context id. Here be magic! */
25011487f786SFrançois Tigeot 	I915_WRITE64_FW(GEN6_BSD_RNCID, 0x0);
2502e3adcf8fSFrançois Tigeot 
2503f4e1c372SFrançois Tigeot 	/* Wait for the ring not to be idle, i.e. for it to wake up. */
25041487f786SFrançois Tigeot 	if (intel_wait_for_register_fw(dev_priv,
25051487f786SFrançois Tigeot 				       GEN6_BSD_SLEEP_PSMI_CONTROL,
25061487f786SFrançois Tigeot 				       GEN6_BSD_SLEEP_INDICATOR,
25071487f786SFrançois Tigeot 				       0,
2508f4e1c372SFrançois Tigeot 				       50))
2509f4e1c372SFrançois Tigeot 		DRM_ERROR("timed out waiting for the BSD ring to wake up\n");
2510f4e1c372SFrançois Tigeot 
2511f4e1c372SFrançois Tigeot 	/* Now that the ring is fully powered up, update the tail */
25121487f786SFrançois Tigeot 	I915_WRITE_FW(RING_TAIL(engine->mmio_base), value);
25131487f786SFrançois Tigeot 	POSTING_READ_FW(RING_TAIL(engine->mmio_base));
2514f4e1c372SFrançois Tigeot 
2515f4e1c372SFrançois Tigeot 	/* Let the ring send IDLE messages to the GT again,
2516f4e1c372SFrançois Tigeot 	 * and so let it sleep to conserve power when idle.
2517f4e1c372SFrançois Tigeot 	 */
25181487f786SFrançois Tigeot 	I915_WRITE_FW(GEN6_BSD_SLEEP_PSMI_CONTROL,
2519f4e1c372SFrançois Tigeot 		      _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
25201487f786SFrançois Tigeot 
25211487f786SFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
2522e3adcf8fSFrançois Tigeot }
2523e3adcf8fSFrançois Tigeot 
2524a05eeebfSFrançois Tigeot static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req,
2525b5c29a34SFrançois Tigeot 			       u32 invalidate, u32 flush)
2526e3adcf8fSFrançois Tigeot {
25278621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2528e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2529e3adcf8fSFrançois Tigeot 	int ret;
2530e3adcf8fSFrançois Tigeot 
2531a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2532e3adcf8fSFrançois Tigeot 	if (ret)
2533e3adcf8fSFrançois Tigeot 		return ret;
2534e3adcf8fSFrançois Tigeot 
2535e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
25361487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8)
25379edbd4a0SFrançois Tigeot 		cmd += 1;
25382c9916cdSFrançois Tigeot 
25392c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
25402c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
25412c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
25422c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
25432c9916cdSFrançois Tigeot 	 */
25442c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
25452c9916cdSFrançois Tigeot 
2546b5c29a34SFrançois Tigeot 	/*
2547b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.5 - video engine command streamer:
2548b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2549b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2550b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2551b5c29a34SFrançois Tigeot 	 */
2552e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_GPU_DOMAINS)
25532c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
25542c9916cdSFrançois Tigeot 
25558621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
25568621f407SFrançois Tigeot 	intel_ring_emit(engine,
25578621f407SFrançois Tigeot 			I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
25581487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8) {
25598621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* upper addr */
25608621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* value */
25619edbd4a0SFrançois Tigeot 	} else  {
25628621f407SFrançois Tigeot 		intel_ring_emit(engine, 0);
25638621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
25649edbd4a0SFrançois Tigeot 	}
25658621f407SFrançois Tigeot 	intel_ring_advance(engine);
25669edbd4a0SFrançois Tigeot 	return 0;
25679edbd4a0SFrançois Tigeot }
25689edbd4a0SFrançois Tigeot 
25699edbd4a0SFrançois Tigeot static int
2570a05eeebfSFrançois Tigeot gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2571ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2572477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
25739edbd4a0SFrançois Tigeot {
25748621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
25758621f407SFrançois Tigeot 	bool ppgtt = USES_PPGTT(engine->dev) &&
2576477eb7f9SFrançois Tigeot 			!(dispatch_flags & I915_DISPATCH_SECURE);
25779edbd4a0SFrançois Tigeot 	int ret;
25789edbd4a0SFrançois Tigeot 
2579a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
25809edbd4a0SFrançois Tigeot 	if (ret)
25819edbd4a0SFrançois Tigeot 		return ret;
25829edbd4a0SFrançois Tigeot 
25839edbd4a0SFrançois Tigeot 	/* FIXME(BDW): Address space and security selectors. */
25848621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) |
2585a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2586a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
25878621f407SFrançois Tigeot 	intel_ring_emit(engine, lower_32_bits(offset));
25888621f407SFrançois Tigeot 	intel_ring_emit(engine, upper_32_bits(offset));
25898621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
25908621f407SFrançois Tigeot 	intel_ring_advance(engine);
25919edbd4a0SFrançois Tigeot 
2592e3adcf8fSFrançois Tigeot 	return 0;
2593e3adcf8fSFrançois Tigeot }
2594e3adcf8fSFrançois Tigeot 
2595e3adcf8fSFrançois Tigeot static int
2596a05eeebfSFrançois Tigeot hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2597ba55f2f5SFrançois Tigeot 			     u64 offset, u32 len,
2598477eb7f9SFrançois Tigeot 			     unsigned dispatch_flags)
2599e3adcf8fSFrançois Tigeot {
26008621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2601e3adcf8fSFrançois Tigeot 	int ret;
2602e3adcf8fSFrançois Tigeot 
2603a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2604e3adcf8fSFrançois Tigeot 	if (ret)
2605e3adcf8fSFrançois Tigeot 		return ret;
2606e3adcf8fSFrançois Tigeot 
26078621f407SFrançois Tigeot 	intel_ring_emit(engine,
26081b13d190SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2609477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2610a05eeebfSFrançois Tigeot 			 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) |
2611a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2612a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
2613b5c29a34SFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
26148621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
26158621f407SFrançois Tigeot 	intel_ring_advance(engine);
2616b5c29a34SFrançois Tigeot 
2617b5c29a34SFrançois Tigeot 	return 0;
2618b5c29a34SFrançois Tigeot }
2619b5c29a34SFrançois Tigeot 
2620b5c29a34SFrançois Tigeot static int
2621a05eeebfSFrançois Tigeot gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2622ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2623477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
2624b5c29a34SFrançois Tigeot {
26258621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2626b5c29a34SFrançois Tigeot 	int ret;
2627b5c29a34SFrançois Tigeot 
2628a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2629b5c29a34SFrançois Tigeot 	if (ret)
2630b5c29a34SFrançois Tigeot 		return ret;
2631b5c29a34SFrançois Tigeot 
26328621f407SFrançois Tigeot 	intel_ring_emit(engine,
2633b5c29a34SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2634477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2635477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
2636e3adcf8fSFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
26378621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
26388621f407SFrançois Tigeot 	intel_ring_advance(engine);
2639e3adcf8fSFrançois Tigeot 
2640e3adcf8fSFrançois Tigeot 	return 0;
2641e3adcf8fSFrançois Tigeot }
2642e3adcf8fSFrançois Tigeot 
2643e3adcf8fSFrançois Tigeot /* Blitter support (SandyBridge+) */
2644e3adcf8fSFrançois Tigeot 
2645a05eeebfSFrançois Tigeot static int gen6_ring_flush(struct drm_i915_gem_request *req,
2646b5c29a34SFrançois Tigeot 			   u32 invalidate, u32 flush)
2647e3adcf8fSFrançois Tigeot {
26488621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2649e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2650e3adcf8fSFrançois Tigeot 	int ret;
2651e3adcf8fSFrançois Tigeot 
2652a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2653e3adcf8fSFrançois Tigeot 	if (ret)
2654e3adcf8fSFrançois Tigeot 		return ret;
2655e3adcf8fSFrançois Tigeot 
2656e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
26571487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8)
26589edbd4a0SFrançois Tigeot 		cmd += 1;
26592c9916cdSFrançois Tigeot 
26602c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
26612c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
26622c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
26632c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
26642c9916cdSFrançois Tigeot 	 */
26652c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
26662c9916cdSFrançois Tigeot 
2667b5c29a34SFrançois Tigeot 	/*
2668b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.3 - blitter engine command streamer:
2669b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2670b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2671b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2672b5c29a34SFrançois Tigeot 	 */
2673e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_DOMAIN_RENDER)
26742c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB;
26758621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
26768621f407SFrançois Tigeot 	intel_ring_emit(engine,
26778621f407SFrançois Tigeot 			I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
26781487f786SFrançois Tigeot 	if (INTEL_GEN(req->i915) >= 8) {
26798621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* upper addr */
26808621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* value */
26819edbd4a0SFrançois Tigeot 	} else  {
26828621f407SFrançois Tigeot 		intel_ring_emit(engine, 0);
26838621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
26849edbd4a0SFrançois Tigeot 	}
26858621f407SFrançois Tigeot 	intel_ring_advance(engine);
26865d0b1887SFrançois Tigeot 
2687e3adcf8fSFrançois Tigeot 	return 0;
2688e3adcf8fSFrançois Tigeot }
2689e3adcf8fSFrançois Tigeot 
26901487f786SFrançois Tigeot static void intel_ring_init_semaphores(struct drm_i915_private *dev_priv,
26911487f786SFrançois Tigeot 				       struct intel_engine_cs *engine)
26921487f786SFrançois Tigeot {
26931487f786SFrançois Tigeot 	struct drm_i915_gem_object *obj;
26941487f786SFrançois Tigeot 	int ret, i;
26951487f786SFrançois Tigeot 
2696*87df8fc6SFrançois Tigeot 	if (!i915.semaphores)
26971487f786SFrançois Tigeot 		return;
26981487f786SFrançois Tigeot 
26991487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8 && !dev_priv->semaphore_obj) {
2700303bf270SFrançois Tigeot 		obj = i915_gem_object_create(&dev_priv->drm, 4096);
27011487f786SFrançois Tigeot 		if (IS_ERR(obj)) {
27021487f786SFrançois Tigeot 			DRM_ERROR("Failed to allocate semaphore bo. Disabling semaphores\n");
27031487f786SFrançois Tigeot 			i915.semaphores = 0;
27041487f786SFrançois Tigeot 		} else {
27051487f786SFrançois Tigeot 			i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
27061487f786SFrançois Tigeot 			ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_NONBLOCK);
27071487f786SFrançois Tigeot 			if (ret != 0) {
2708*87df8fc6SFrançois Tigeot 				i915_gem_object_put(obj);
27091487f786SFrançois Tigeot 				DRM_ERROR("Failed to pin semaphore bo. Disabling semaphores\n");
27101487f786SFrançois Tigeot 				i915.semaphores = 0;
27111487f786SFrançois Tigeot 			} else {
27121487f786SFrançois Tigeot 				dev_priv->semaphore_obj = obj;
27131487f786SFrançois Tigeot 			}
27141487f786SFrançois Tigeot 		}
27151487f786SFrançois Tigeot 	}
27161487f786SFrançois Tigeot 
2717*87df8fc6SFrançois Tigeot 	if (!i915.semaphores)
27181487f786SFrançois Tigeot 		return;
27191487f786SFrançois Tigeot 
27201487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
27211487f786SFrançois Tigeot 		u64 offset = i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj);
27221487f786SFrançois Tigeot 
27231487f786SFrançois Tigeot 		engine->semaphore.sync_to = gen8_ring_sync;
27241487f786SFrançois Tigeot 		engine->semaphore.signal = gen8_xcs_signal;
27251487f786SFrançois Tigeot 
27261487f786SFrançois Tigeot 		for (i = 0; i < I915_NUM_ENGINES; i++) {
27271487f786SFrançois Tigeot 			u64 ring_offset;
27281487f786SFrançois Tigeot 
27291487f786SFrançois Tigeot 			if (i != engine->id)
27301487f786SFrançois Tigeot 				ring_offset = offset + GEN8_SEMAPHORE_OFFSET(engine->id, i);
27311487f786SFrançois Tigeot 			else
27321487f786SFrançois Tigeot 				ring_offset = MI_SEMAPHORE_SYNC_INVALID;
27331487f786SFrançois Tigeot 
27341487f786SFrançois Tigeot 			engine->semaphore.signal_ggtt[i] = ring_offset;
27351487f786SFrançois Tigeot 		}
27361487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 6) {
27371487f786SFrançois Tigeot 		engine->semaphore.sync_to = gen6_ring_sync;
27381487f786SFrançois Tigeot 		engine->semaphore.signal = gen6_signal;
27391487f786SFrançois Tigeot 
27401487f786SFrançois Tigeot 		/*
27411487f786SFrançois Tigeot 		 * The current semaphore is only applied on pre-gen8
27421487f786SFrançois Tigeot 		 * platform.  And there is no VCS2 ring on the pre-gen8
27431487f786SFrançois Tigeot 		 * platform. So the semaphore between RCS and VCS2 is
27441487f786SFrançois Tigeot 		 * initialized as INVALID.  Gen8 will initialize the
27451487f786SFrançois Tigeot 		 * sema between VCS2 and RCS later.
27461487f786SFrançois Tigeot 		 */
27471487f786SFrançois Tigeot 		for (i = 0; i < I915_NUM_ENGINES; i++) {
27481487f786SFrançois Tigeot 			static const struct {
27491487f786SFrançois Tigeot 				u32 wait_mbox;
27501487f786SFrançois Tigeot 				i915_reg_t mbox_reg;
27511487f786SFrançois Tigeot 			} sem_data[I915_NUM_ENGINES][I915_NUM_ENGINES] = {
27521487f786SFrançois Tigeot 				[RCS] = {
27531487f786SFrançois Tigeot 					[VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RV,  .mbox_reg = GEN6_VRSYNC },
27541487f786SFrançois Tigeot 					[BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_RB,  .mbox_reg = GEN6_BRSYNC },
27551487f786SFrançois Tigeot 					[VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_RVE, .mbox_reg = GEN6_VERSYNC },
27561487f786SFrançois Tigeot 				},
27571487f786SFrançois Tigeot 				[VCS] = {
27581487f786SFrançois Tigeot 					[RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VR,  .mbox_reg = GEN6_RVSYNC },
27591487f786SFrançois Tigeot 					[BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VB,  .mbox_reg = GEN6_BVSYNC },
27601487f786SFrançois Tigeot 					[VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_VVE, .mbox_reg = GEN6_VEVSYNC },
27611487f786SFrançois Tigeot 				},
27621487f786SFrançois Tigeot 				[BCS] = {
27631487f786SFrançois Tigeot 					[RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BR,  .mbox_reg = GEN6_RBSYNC },
27641487f786SFrançois Tigeot 					[VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_BV,  .mbox_reg = GEN6_VBSYNC },
27651487f786SFrançois Tigeot 					[VECS] = { .wait_mbox = MI_SEMAPHORE_SYNC_BVE, .mbox_reg = GEN6_VEBSYNC },
27661487f786SFrançois Tigeot 				},
27671487f786SFrançois Tigeot 				[VECS] = {
27681487f786SFrançois Tigeot 					[RCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VER, .mbox_reg = GEN6_RVESYNC },
27691487f786SFrançois Tigeot 					[VCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEV, .mbox_reg = GEN6_VVESYNC },
27701487f786SFrançois Tigeot 					[BCS] =  { .wait_mbox = MI_SEMAPHORE_SYNC_VEB, .mbox_reg = GEN6_BVESYNC },
27711487f786SFrançois Tigeot 				},
27721487f786SFrançois Tigeot 			};
27731487f786SFrançois Tigeot 			u32 wait_mbox;
27741487f786SFrançois Tigeot 			i915_reg_t mbox_reg;
27751487f786SFrançois Tigeot 
27761487f786SFrançois Tigeot 			if (i == engine->id || i == VCS2) {
27771487f786SFrançois Tigeot 				wait_mbox = MI_SEMAPHORE_SYNC_INVALID;
27781487f786SFrançois Tigeot 				mbox_reg = GEN6_NOSYNC;
27791487f786SFrançois Tigeot 			} else {
27801487f786SFrançois Tigeot 				wait_mbox = sem_data[engine->id][i].wait_mbox;
27811487f786SFrançois Tigeot 				mbox_reg = sem_data[engine->id][i].mbox_reg;
27821487f786SFrançois Tigeot 			}
27831487f786SFrançois Tigeot 
27841487f786SFrançois Tigeot 			engine->semaphore.mbox.wait[i] = wait_mbox;
27851487f786SFrançois Tigeot 			engine->semaphore.mbox.signal[i] = mbox_reg;
27861487f786SFrançois Tigeot 		}
27871487f786SFrançois Tigeot 	}
27881487f786SFrançois Tigeot }
27891487f786SFrançois Tigeot 
27901487f786SFrançois Tigeot static void intel_ring_init_irq(struct drm_i915_private *dev_priv,
27911487f786SFrançois Tigeot 				struct intel_engine_cs *engine)
27921487f786SFrançois Tigeot {
2793*87df8fc6SFrançois Tigeot 	engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT << engine->irq_shift;
2794*87df8fc6SFrançois Tigeot 
27951487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
2796303bf270SFrançois Tigeot 		engine->irq_enable = gen8_irq_enable;
2797303bf270SFrançois Tigeot 		engine->irq_disable = gen8_irq_disable;
27981487f786SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
27991487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 6) {
2800303bf270SFrançois Tigeot 		engine->irq_enable = gen6_irq_enable;
2801303bf270SFrançois Tigeot 		engine->irq_disable = gen6_irq_disable;
28021487f786SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
28031487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 5) {
2804303bf270SFrançois Tigeot 		engine->irq_enable = gen5_irq_enable;
2805303bf270SFrançois Tigeot 		engine->irq_disable = gen5_irq_disable;
2806303bf270SFrançois Tigeot 		engine->irq_seqno_barrier = gen5_seqno_barrier;
28071487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 3) {
2808303bf270SFrançois Tigeot 		engine->irq_enable = i9xx_irq_enable;
2809303bf270SFrançois Tigeot 		engine->irq_disable = i9xx_irq_disable;
28101487f786SFrançois Tigeot 	} else {
2811303bf270SFrançois Tigeot 		engine->irq_enable = i8xx_irq_enable;
2812303bf270SFrançois Tigeot 		engine->irq_disable = i8xx_irq_disable;
28131487f786SFrançois Tigeot 	}
28141487f786SFrançois Tigeot }
28151487f786SFrançois Tigeot 
28161487f786SFrançois Tigeot static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
28171487f786SFrançois Tigeot 				      struct intel_engine_cs *engine)
28181487f786SFrançois Tigeot {
28191487f786SFrançois Tigeot 	engine->init_hw = init_ring_common;
28201487f786SFrançois Tigeot 	engine->write_tail = ring_write_tail;
28211487f786SFrançois Tigeot 
28221487f786SFrançois Tigeot 	engine->add_request = i9xx_add_request;
28231487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6)
28241487f786SFrançois Tigeot 		engine->add_request = gen6_add_request;
28251487f786SFrançois Tigeot 
28261487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8)
28271487f786SFrançois Tigeot 		engine->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
28281487f786SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 6)
28291487f786SFrançois Tigeot 		engine->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
28301487f786SFrançois Tigeot 	else if (INTEL_GEN(dev_priv) >= 4)
28311487f786SFrançois Tigeot 		engine->dispatch_execbuffer = i965_dispatch_execbuffer;
28321487f786SFrançois Tigeot 	else if (IS_I830(dev_priv) || IS_845G(dev_priv))
28331487f786SFrançois Tigeot 		engine->dispatch_execbuffer = i830_dispatch_execbuffer;
28341487f786SFrançois Tigeot 	else
28351487f786SFrançois Tigeot 		engine->dispatch_execbuffer = i915_dispatch_execbuffer;
28361487f786SFrançois Tigeot 
28371487f786SFrançois Tigeot 	intel_ring_init_irq(dev_priv, engine);
28381487f786SFrançois Tigeot 	intel_ring_init_semaphores(dev_priv, engine);
28391487f786SFrançois Tigeot }
28401487f786SFrançois Tigeot 
2841*87df8fc6SFrançois Tigeot int intel_init_render_ring_buffer(struct intel_engine_cs *engine)
2842e3adcf8fSFrançois Tigeot {
2843*87df8fc6SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
284424edb884SFrançois Tigeot 	int ret;
2845e3adcf8fSFrançois Tigeot 
28461487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
28472c9916cdSFrançois Tigeot 
2848303bf270SFrançois Tigeot 	if (HAS_L3_DPF(dev_priv))
2849303bf270SFrançois Tigeot 		engine->irq_keep_mask = GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
2850303bf270SFrançois Tigeot 
28511487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 8) {
28528621f407SFrançois Tigeot 		engine->init_context = intel_rcs_ctx_init;
28531487f786SFrançois Tigeot 		engine->add_request = gen8_render_add_request;
28548621f407SFrançois Tigeot 		engine->flush = gen8_render_ring_flush;
2855*87df8fc6SFrançois Tigeot 		if (i915.semaphores)
28568621f407SFrançois Tigeot 			engine->semaphore.signal = gen8_rcs_signal;
28571487f786SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 6) {
28588621f407SFrançois Tigeot 		engine->init_context = intel_rcs_ctx_init;
28598621f407SFrançois Tigeot 		engine->flush = gen7_render_ring_flush;
28601487f786SFrançois Tigeot 		if (IS_GEN6(dev_priv))
28618621f407SFrançois Tigeot 			engine->flush = gen6_render_ring_flush;
28621487f786SFrançois Tigeot 	} else if (IS_GEN5(dev_priv)) {
28638621f407SFrançois Tigeot 		engine->flush = gen4_render_ring_flush;
2864686a02f1SFrançois Tigeot 	} else {
28651487f786SFrançois Tigeot 		if (INTEL_GEN(dev_priv) < 4)
28668621f407SFrançois Tigeot 			engine->flush = gen2_render_ring_flush;
2867686a02f1SFrançois Tigeot 		else
28688621f407SFrançois Tigeot 			engine->flush = gen4_render_ring_flush;
28698621f407SFrançois Tigeot 		engine->irq_enable_mask = I915_USER_INTERRUPT;
2870686a02f1SFrançois Tigeot 	}
287124edb884SFrançois Tigeot 
28721487f786SFrançois Tigeot 	if (IS_HASWELL(dev_priv))
28738621f407SFrançois Tigeot 		engine->dispatch_execbuffer = hsw_ring_dispatch_execbuffer;
28741487f786SFrançois Tigeot 
28758621f407SFrançois Tigeot 	engine->init_hw = init_render_ring;
28768621f407SFrançois Tigeot 	engine->cleanup = render_ring_cleanup;
2877e3adcf8fSFrançois Tigeot 
2878*87df8fc6SFrançois Tigeot 	ret = intel_init_ring_buffer(engine);
2879b5c29a34SFrançois Tigeot 	if (ret)
28802c9916cdSFrançois Tigeot 		return ret;
28812c9916cdSFrançois Tigeot 
2882303bf270SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6) {
2883303bf270SFrançois Tigeot 		ret = intel_init_pipe_control(engine, 4096);
2884303bf270SFrançois Tigeot 		if (ret)
2885303bf270SFrançois Tigeot 			return ret;
2886303bf270SFrançois Tigeot 	} else if (HAS_BROKEN_CS_TLB(dev_priv)) {
2887303bf270SFrançois Tigeot 		ret = intel_init_pipe_control(engine, I830_WA_SIZE);
28882c9916cdSFrançois Tigeot 		if (ret)
28892c9916cdSFrançois Tigeot 			return ret;
2890b5c29a34SFrançois Tigeot 	}
2891b5c29a34SFrançois Tigeot 
2892e3adcf8fSFrançois Tigeot 	return 0;
2893e3adcf8fSFrançois Tigeot }
2894e3adcf8fSFrançois Tigeot 
2895*87df8fc6SFrançois Tigeot int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine)
2896e3adcf8fSFrançois Tigeot {
2897*87df8fc6SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
2898686a02f1SFrançois Tigeot 
28991487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
29001487f786SFrançois Tigeot 
29011487f786SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 6) {
2902686a02f1SFrançois Tigeot 		/* gen6 bsd needs a special wa for tail updates */
29031487f786SFrançois Tigeot 		if (IS_GEN6(dev_priv))
29048621f407SFrançois Tigeot 			engine->write_tail = gen6_bsd_ring_write_tail;
29058621f407SFrançois Tigeot 		engine->flush = gen6_bsd_ring_flush;
2906*87df8fc6SFrançois Tigeot 		if (INTEL_GEN(dev_priv) < 8)
29078621f407SFrançois Tigeot 			engine->irq_enable_mask = GT_BSD_USER_INTERRUPT;
2908686a02f1SFrançois Tigeot 	} else {
29098621f407SFrançois Tigeot 		engine->mmio_base = BSD_RING_BASE;
29108621f407SFrançois Tigeot 		engine->flush = bsd_ring_flush;
29111487f786SFrançois Tigeot 		if (IS_GEN5(dev_priv))
29128621f407SFrançois Tigeot 			engine->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
29131487f786SFrançois Tigeot 		else
29148621f407SFrançois Tigeot 			engine->irq_enable_mask = I915_BSD_USER_INTERRUPT;
2915686a02f1SFrançois Tigeot 	}
2916e3adcf8fSFrançois Tigeot 
2917*87df8fc6SFrançois Tigeot 	return intel_init_ring_buffer(engine);
2918e3adcf8fSFrançois Tigeot }
2919e3adcf8fSFrançois Tigeot 
2920ba55f2f5SFrançois Tigeot /**
2921477eb7f9SFrançois Tigeot  * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
2922ba55f2f5SFrançois Tigeot  */
2923*87df8fc6SFrançois Tigeot int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine)
2924ba55f2f5SFrançois Tigeot {
2925*87df8fc6SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
29261487f786SFrançois Tigeot 
29271487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
29281487f786SFrançois Tigeot 
29298621f407SFrançois Tigeot 	engine->flush = gen6_bsd_ring_flush;
2930ba55f2f5SFrançois Tigeot 
2931*87df8fc6SFrançois Tigeot 	return intel_init_ring_buffer(engine);
2932ba55f2f5SFrançois Tigeot }
2933ba55f2f5SFrançois Tigeot 
2934*87df8fc6SFrançois Tigeot int intel_init_blt_ring_buffer(struct intel_engine_cs *engine)
2935e3adcf8fSFrançois Tigeot {
2936*87df8fc6SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
29371487f786SFrançois Tigeot 
29381487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
29391487f786SFrançois Tigeot 
29408621f407SFrançois Tigeot 	engine->flush = gen6_ring_flush;
2941*87df8fc6SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 8)
29428621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_BLT_USER_INTERRUPT;
29435d0b1887SFrançois Tigeot 
2944*87df8fc6SFrançois Tigeot 	return intel_init_ring_buffer(engine);
29455d0b1887SFrançois Tigeot }
29465d0b1887SFrançois Tigeot 
2947*87df8fc6SFrançois Tigeot int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine)
29485d0b1887SFrançois Tigeot {
2949*87df8fc6SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->i915;
29509edbd4a0SFrançois Tigeot 
29511487f786SFrançois Tigeot 	intel_ring_default_vfuncs(dev_priv, engine);
29521487f786SFrançois Tigeot 
29531487f786SFrançois Tigeot 	engine->flush = gen6_ring_flush;
29541487f786SFrançois Tigeot 
2955*87df8fc6SFrançois Tigeot 	if (INTEL_GEN(dev_priv) < 8) {
29568621f407SFrançois Tigeot 		engine->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
2957303bf270SFrançois Tigeot 		engine->irq_enable = hsw_vebox_irq_enable;
2958303bf270SFrançois Tigeot 		engine->irq_disable = hsw_vebox_irq_disable;
295924edb884SFrançois Tigeot 	}
2960e3adcf8fSFrançois Tigeot 
2961*87df8fc6SFrançois Tigeot 	return intel_init_ring_buffer(engine);
2962e3adcf8fSFrançois Tigeot }
2963b030f26bSFrançois Tigeot 
2964b030f26bSFrançois Tigeot int
2965a05eeebfSFrançois Tigeot intel_ring_flush_all_caches(struct drm_i915_gem_request *req)
2966b030f26bSFrançois Tigeot {
29678621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2968b030f26bSFrançois Tigeot 	int ret;
2969b030f26bSFrançois Tigeot 
29708621f407SFrançois Tigeot 	if (!engine->gpu_caches_dirty)
2971b030f26bSFrançois Tigeot 		return 0;
2972b030f26bSFrançois Tigeot 
29738621f407SFrançois Tigeot 	ret = engine->flush(req, 0, I915_GEM_GPU_DOMAINS);
2974b030f26bSFrançois Tigeot 	if (ret)
2975b030f26bSFrançois Tigeot 		return ret;
2976b030f26bSFrançois Tigeot 
2977a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS);
2978a2fdbec6SFrançois Tigeot 
29798621f407SFrançois Tigeot 	engine->gpu_caches_dirty = false;
2980b030f26bSFrançois Tigeot 	return 0;
2981b030f26bSFrançois Tigeot }
2982b030f26bSFrançois Tigeot 
2983b030f26bSFrançois Tigeot int
2984a05eeebfSFrançois Tigeot intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
2985b030f26bSFrançois Tigeot {
29868621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2987b030f26bSFrançois Tigeot 	uint32_t flush_domains;
2988b030f26bSFrançois Tigeot 	int ret;
2989b030f26bSFrançois Tigeot 
2990b030f26bSFrançois Tigeot 	flush_domains = 0;
29918621f407SFrançois Tigeot 	if (engine->gpu_caches_dirty)
2992b030f26bSFrançois Tigeot 		flush_domains = I915_GEM_GPU_DOMAINS;
2993b030f26bSFrançois Tigeot 
29948621f407SFrançois Tigeot 	ret = engine->flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
2995b030f26bSFrançois Tigeot 	if (ret)
2996b030f26bSFrançois Tigeot 		return ret;
2997b030f26bSFrançois Tigeot 
2998a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
2999a2fdbec6SFrançois Tigeot 
30008621f407SFrançois Tigeot 	engine->gpu_caches_dirty = false;
3001b030f26bSFrançois Tigeot 	return 0;
3002b030f26bSFrançois Tigeot }
3003ba55f2f5SFrançois Tigeot 
3004ba55f2f5SFrançois Tigeot void
30058621f407SFrançois Tigeot intel_stop_engine(struct intel_engine_cs *engine)
3006ba55f2f5SFrançois Tigeot {
3007ba55f2f5SFrançois Tigeot 	int ret;
3008ba55f2f5SFrançois Tigeot 
30098621f407SFrançois Tigeot 	if (!intel_engine_initialized(engine))
3010ba55f2f5SFrançois Tigeot 		return;
3011ba55f2f5SFrançois Tigeot 
30128621f407SFrançois Tigeot 	ret = intel_engine_idle(engine);
30138621f407SFrançois Tigeot 	if (ret)
3014ba55f2f5SFrançois Tigeot 		DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
30158621f407SFrançois Tigeot 			  engine->name, ret);
3016ba55f2f5SFrançois Tigeot 
30178621f407SFrançois Tigeot 	stop_ring(engine);
3018ba55f2f5SFrançois Tigeot }
3019