xref: /dflybsd-src/sys/dev/drm/i915/intel_ringbuffer.c (revision f0bba3d1dd5ba7adfae61269b5424d4ad443ab97)
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 
371b13d190SFrançois Tigeot int __intel_ring_space(int head, int tail, int size)
38e3adcf8fSFrançois Tigeot {
392c9916cdSFrançois Tigeot 	int space = head - tail;
402c9916cdSFrançois Tigeot 	if (space <= 0)
41ba55f2f5SFrançois Tigeot 		space += size;
422c9916cdSFrançois Tigeot 	return space - I915_RING_FREE_SPACE;
432c9916cdSFrançois Tigeot }
442c9916cdSFrançois Tigeot 
452c9916cdSFrançois Tigeot void intel_ring_update_space(struct intel_ringbuffer *ringbuf)
462c9916cdSFrançois Tigeot {
472c9916cdSFrançois Tigeot 	if (ringbuf->last_retired_head != -1) {
482c9916cdSFrançois Tigeot 		ringbuf->head = ringbuf->last_retired_head;
492c9916cdSFrançois Tigeot 		ringbuf->last_retired_head = -1;
502c9916cdSFrançois Tigeot 	}
512c9916cdSFrançois Tigeot 
522c9916cdSFrançois Tigeot 	ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,
532c9916cdSFrançois Tigeot 					    ringbuf->tail, ringbuf->size);
54e3adcf8fSFrançois Tigeot }
55e3adcf8fSFrançois Tigeot 
568621f407SFrançois Tigeot bool intel_engine_stopped(struct intel_engine_cs *engine)
57ba55f2f5SFrançois Tigeot {
588621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
598621f407SFrançois Tigeot 	return dev_priv->gpu_error.stop_rings & intel_engine_flag(engine);
60ba55f2f5SFrançois Tigeot }
61ba55f2f5SFrançois Tigeot 
628621f407SFrançois Tigeot static void __intel_ring_advance(struct intel_engine_cs *engine)
639edbd4a0SFrançois Tigeot {
648621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = engine->buffer;
65ba55f2f5SFrançois Tigeot 	ringbuf->tail &= ringbuf->size - 1;
668621f407SFrançois Tigeot 	if (intel_engine_stopped(engine))
679edbd4a0SFrançois Tigeot 		return;
688621f407SFrançois Tigeot 	engine->write_tail(engine, ringbuf->tail);
699edbd4a0SFrançois Tigeot }
709edbd4a0SFrançois Tigeot 
71e3adcf8fSFrançois Tigeot static int
72a05eeebfSFrançois Tigeot gen2_render_ring_flush(struct drm_i915_gem_request *req,
73686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
74686a02f1SFrançois Tigeot 		       u32	flush_domains)
75686a02f1SFrançois Tigeot {
768621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
77686a02f1SFrançois Tigeot 	u32 cmd;
78686a02f1SFrançois Tigeot 	int ret;
79686a02f1SFrançois Tigeot 
80686a02f1SFrançois Tigeot 	cmd = MI_FLUSH;
81686a02f1SFrançois Tigeot 	if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0)
82686a02f1SFrançois Tigeot 		cmd |= MI_NO_WRITE_FLUSH;
83686a02f1SFrançois Tigeot 
84686a02f1SFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
85686a02f1SFrançois Tigeot 		cmd |= MI_READ_FLUSH;
86686a02f1SFrançois Tigeot 
87a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
88686a02f1SFrançois Tigeot 	if (ret)
89686a02f1SFrançois Tigeot 		return ret;
90686a02f1SFrançois Tigeot 
918621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
928621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
938621f407SFrançois Tigeot 	intel_ring_advance(engine);
94686a02f1SFrançois Tigeot 
95686a02f1SFrançois Tigeot 	return 0;
96686a02f1SFrançois Tigeot }
97686a02f1SFrançois Tigeot 
98686a02f1SFrançois Tigeot static int
99a05eeebfSFrançois Tigeot gen4_render_ring_flush(struct drm_i915_gem_request *req,
100686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
101686a02f1SFrançois Tigeot 		       u32	flush_domains)
102e3adcf8fSFrançois Tigeot {
1038621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1048621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
105686a02f1SFrançois Tigeot 	u32 cmd;
106e3adcf8fSFrançois Tigeot 	int ret;
107e3adcf8fSFrançois Tigeot 
108e3adcf8fSFrançois Tigeot 	/*
109e3adcf8fSFrançois Tigeot 	 * read/write caches:
110e3adcf8fSFrançois Tigeot 	 *
111e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER is always invalidated, but is
112e3adcf8fSFrançois Tigeot 	 * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
113e3adcf8fSFrançois Tigeot 	 * also flushed at 2d versus 3d pipeline switches.
114e3adcf8fSFrançois Tigeot 	 *
115e3adcf8fSFrançois Tigeot 	 * read-only caches:
116e3adcf8fSFrançois Tigeot 	 *
117e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
118e3adcf8fSFrançois Tigeot 	 * MI_READ_FLUSH is set, and is always flushed on 965.
119e3adcf8fSFrançois Tigeot 	 *
120e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_COMMAND may not exist?
121e3adcf8fSFrançois Tigeot 	 *
122e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
123e3adcf8fSFrançois Tigeot 	 * invalidated when MI_EXE_FLUSH is set.
124e3adcf8fSFrançois Tigeot 	 *
125e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
126e3adcf8fSFrançois Tigeot 	 * invalidated with every MI_FLUSH.
127e3adcf8fSFrançois Tigeot 	 *
128e3adcf8fSFrançois Tigeot 	 * TLBs:
129e3adcf8fSFrançois Tigeot 	 *
130e3adcf8fSFrançois Tigeot 	 * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
131e3adcf8fSFrançois Tigeot 	 * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
132e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
133e3adcf8fSFrançois Tigeot 	 * are flushed at any MI_FLUSH.
134e3adcf8fSFrançois Tigeot 	 */
135e3adcf8fSFrançois Tigeot 
136e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
137686a02f1SFrançois Tigeot 	if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER)
138e3adcf8fSFrançois Tigeot 		cmd &= ~MI_NO_WRITE_FLUSH;
139e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
140e3adcf8fSFrançois Tigeot 		cmd |= MI_EXE_FLUSH;
141e3adcf8fSFrançois Tigeot 
142e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
143e3adcf8fSFrançois Tigeot 	    (IS_G4X(dev) || IS_GEN5(dev)))
144e3adcf8fSFrançois Tigeot 		cmd |= MI_INVALIDATE_ISP;
145e3adcf8fSFrançois Tigeot 
146a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
147e3adcf8fSFrançois Tigeot 	if (ret)
148e3adcf8fSFrançois Tigeot 		return ret;
149e3adcf8fSFrançois Tigeot 
1508621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
1518621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
1528621f407SFrançois Tigeot 	intel_ring_advance(engine);
153e3adcf8fSFrançois Tigeot 
154e3adcf8fSFrançois Tigeot 	return 0;
155e3adcf8fSFrançois Tigeot }
156e3adcf8fSFrançois Tigeot 
157e3adcf8fSFrançois Tigeot /**
158e3adcf8fSFrançois Tigeot  * Emits a PIPE_CONTROL with a non-zero post-sync operation, for
159e3adcf8fSFrançois Tigeot  * implementing two workarounds on gen6.  From section 1.4.7.1
160e3adcf8fSFrançois Tigeot  * "PIPE_CONTROL" of the Sandy Bridge PRM volume 2 part 1:
161e3adcf8fSFrançois Tigeot  *
162e3adcf8fSFrançois Tigeot  * [DevSNB-C+{W/A}] Before any depth stall flush (including those
163e3adcf8fSFrançois Tigeot  * produced by non-pipelined state commands), software needs to first
164e3adcf8fSFrançois Tigeot  * send a PIPE_CONTROL with no bits set except Post-Sync Operation !=
165e3adcf8fSFrançois Tigeot  * 0.
166e3adcf8fSFrançois Tigeot  *
167e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Before a PIPE_CONTROL with Write Cache Flush Enable
168e3adcf8fSFrançois Tigeot  * =1, a PIPE_CONTROL with any non-zero post-sync-op is required.
169e3adcf8fSFrançois Tigeot  *
170e3adcf8fSFrançois Tigeot  * And the workaround for these two requires this workaround first:
171e3adcf8fSFrançois Tigeot  *
172e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
173e3adcf8fSFrançois Tigeot  * BEFORE the pipe-control with a post-sync op and no write-cache
174e3adcf8fSFrançois Tigeot  * flushes.
175e3adcf8fSFrançois Tigeot  *
176e3adcf8fSFrançois Tigeot  * And this last workaround is tricky because of the requirements on
177e3adcf8fSFrançois Tigeot  * that bit.  From section 1.4.7.2.3 "Stall" of the Sandy Bridge PRM
178e3adcf8fSFrançois Tigeot  * volume 2 part 1:
179e3adcf8fSFrançois Tigeot  *
180e3adcf8fSFrançois Tigeot  *     "1 of the following must also be set:
181e3adcf8fSFrançois Tigeot  *      - Render Target Cache Flush Enable ([12] of DW1)
182e3adcf8fSFrançois Tigeot  *      - Depth Cache Flush Enable ([0] of DW1)
183e3adcf8fSFrançois Tigeot  *      - Stall at Pixel Scoreboard ([1] of DW1)
184e3adcf8fSFrançois Tigeot  *      - Depth Stall ([13] of DW1)
185e3adcf8fSFrançois Tigeot  *      - Post-Sync Operation ([13] of DW1)
186e3adcf8fSFrançois Tigeot  *      - Notify Enable ([8] of DW1)"
187e3adcf8fSFrançois Tigeot  *
188e3adcf8fSFrançois Tigeot  * The cache flushes require the workaround flush that triggered this
189e3adcf8fSFrançois Tigeot  * one, so we can't use it.  Depth stall would trigger the same.
190e3adcf8fSFrançois Tigeot  * Post-sync nonzero is what triggered this second workaround, so we
191e3adcf8fSFrançois Tigeot  * can't use that one either.  Notify enable is IRQs, which aren't
192e3adcf8fSFrançois Tigeot  * really our business.  That leaves only stall at scoreboard.
193e3adcf8fSFrançois Tigeot  */
194e3adcf8fSFrançois Tigeot static int
195a05eeebfSFrançois Tigeot intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
196e3adcf8fSFrançois Tigeot {
1978621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1988621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
199e3adcf8fSFrançois Tigeot 	int ret;
200e3adcf8fSFrançois Tigeot 
201a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
202e3adcf8fSFrançois Tigeot 	if (ret)
203e3adcf8fSFrançois Tigeot 		return ret;
204e3adcf8fSFrançois Tigeot 
2058621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
2068621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
207e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_STALL_AT_SCOREBOARD);
2088621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
2098621f407SFrançois Tigeot 	intel_ring_emit(engine, 0); /* low dword */
2108621f407SFrançois Tigeot 	intel_ring_emit(engine, 0); /* high dword */
2118621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
2128621f407SFrançois Tigeot 	intel_ring_advance(engine);
213e3adcf8fSFrançois Tigeot 
214a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
215e3adcf8fSFrançois Tigeot 	if (ret)
216e3adcf8fSFrançois Tigeot 		return ret;
217e3adcf8fSFrançois Tigeot 
2188621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(5));
2198621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_QW_WRITE);
2208621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
2218621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2228621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2238621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
2248621f407SFrançois Tigeot 	intel_ring_advance(engine);
225e3adcf8fSFrançois Tigeot 
226e3adcf8fSFrançois Tigeot 	return 0;
227e3adcf8fSFrançois Tigeot }
228e3adcf8fSFrançois Tigeot 
229e3adcf8fSFrançois Tigeot static int
230a05eeebfSFrançois Tigeot gen6_render_ring_flush(struct drm_i915_gem_request *req,
231e3adcf8fSFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
232e3adcf8fSFrançois Tigeot {
2338621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
234e3adcf8fSFrançois Tigeot 	u32 flags = 0;
2358621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
236e3adcf8fSFrançois Tigeot 	int ret;
237e3adcf8fSFrançois Tigeot 
238e3adcf8fSFrançois Tigeot 	/* Force SNB workarounds for PIPE_CONTROL flushes */
239a05eeebfSFrançois Tigeot 	ret = intel_emit_post_sync_nonzero_flush(req);
240686a02f1SFrançois Tigeot 	if (ret)
241686a02f1SFrançois Tigeot 		return ret;
242e3adcf8fSFrançois Tigeot 
243e3adcf8fSFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
244e3adcf8fSFrançois Tigeot 	 * number of bits based on the write domains has little performance
245e3adcf8fSFrançois Tigeot 	 * impact.
246e3adcf8fSFrançois Tigeot 	 */
247b5c29a34SFrançois Tigeot 	if (flush_domains) {
248e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
249b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
250b5c29a34SFrançois Tigeot 		/*
251b5c29a34SFrançois Tigeot 		 * Ensure that any following seqno writes only happen
252b5c29a34SFrançois Tigeot 		 * when the render cache is indeed flushed.
253b5c29a34SFrançois Tigeot 		 */
254b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CS_STALL;
255b5c29a34SFrançois Tigeot 	}
256b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
257686a02f1SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
258e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
259e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
260e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
261e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
262e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
263686a02f1SFrançois Tigeot 		/*
264b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
265686a02f1SFrançois Tigeot 		 */
266b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL;
267b5c29a34SFrançois Tigeot 	}
268e3adcf8fSFrançois Tigeot 
269a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
270e3adcf8fSFrançois Tigeot 	if (ret)
271e3adcf8fSFrançois Tigeot 		return ret;
272e3adcf8fSFrançois Tigeot 
2738621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
2748621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
2758621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
2768621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2778621f407SFrançois Tigeot 	intel_ring_advance(engine);
278b5c29a34SFrançois Tigeot 
279b5c29a34SFrançois Tigeot 	return 0;
280b5c29a34SFrançois Tigeot }
281b5c29a34SFrançois Tigeot 
282b5c29a34SFrançois Tigeot static int
283a05eeebfSFrançois Tigeot gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
284b5c29a34SFrançois Tigeot {
2858621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
286b5c29a34SFrançois Tigeot 	int ret;
287b5c29a34SFrançois Tigeot 
288a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
289b5c29a34SFrançois Tigeot 	if (ret)
290b5c29a34SFrançois Tigeot 		return ret;
291b5c29a34SFrançois Tigeot 
2928621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
2938621f407SFrançois Tigeot 	intel_ring_emit(engine, PIPE_CONTROL_CS_STALL |
294b5c29a34SFrançois Tigeot 			      PIPE_CONTROL_STALL_AT_SCOREBOARD);
2958621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2968621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
2978621f407SFrançois Tigeot 	intel_ring_advance(engine);
298b5c29a34SFrançois Tigeot 
299b5c29a34SFrançois Tigeot 	return 0;
300b5c29a34SFrançois Tigeot }
301b5c29a34SFrançois Tigeot 
302b5c29a34SFrançois Tigeot static int
303a05eeebfSFrançois Tigeot gen7_render_ring_flush(struct drm_i915_gem_request *req,
304b5c29a34SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
305b5c29a34SFrançois Tigeot {
3068621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
307b5c29a34SFrançois Tigeot 	u32 flags = 0;
3088621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
309b5c29a34SFrançois Tigeot 	int ret;
310b5c29a34SFrançois Tigeot 
311b5c29a34SFrançois Tigeot 	/*
312b5c29a34SFrançois Tigeot 	 * Ensure that any following seqno writes only happen when the render
313b5c29a34SFrançois Tigeot 	 * cache is indeed flushed.
314b5c29a34SFrançois Tigeot 	 *
315b5c29a34SFrançois Tigeot 	 * Workaround: 4th PIPE_CONTROL command (except the ones with only
316b5c29a34SFrançois Tigeot 	 * read-cache invalidate bits set) must have the CS_STALL bit set. We
317b5c29a34SFrançois Tigeot 	 * don't try to be clever and just set it unconditionally.
318b5c29a34SFrançois Tigeot 	 */
319b5c29a34SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
320b5c29a34SFrançois Tigeot 
321b5c29a34SFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
322b5c29a34SFrançois Tigeot 	 * number of bits based on the write domains has little performance
323b5c29a34SFrançois Tigeot 	 * impact.
324b5c29a34SFrançois Tigeot 	 */
325b5c29a34SFrançois Tigeot 	if (flush_domains) {
326b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
327b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
328aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
329b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
330b5c29a34SFrançois Tigeot 	}
331b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
332b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
333b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
334b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
335b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
336b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
337b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
3382c9916cdSFrançois Tigeot 		flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR;
339b5c29a34SFrançois Tigeot 		/*
340b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
341b5c29a34SFrançois Tigeot 		 */
342b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
343a2fdbec6SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
344b5c29a34SFrançois Tigeot 
3450dbf0ea8SMatthew Dillon 		flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD;
3460dbf0ea8SMatthew Dillon 
347b5c29a34SFrançois Tigeot 		/* Workaround: we must issue a pipe_control with CS-stall bit
348b5c29a34SFrançois Tigeot 		 * set before a pipe_control command that has the state cache
349b5c29a34SFrançois Tigeot 		 * invalidate bit set. */
350a05eeebfSFrançois Tigeot 		gen7_render_ring_cs_stall_wa(req);
351b5c29a34SFrançois Tigeot 	}
352b5c29a34SFrançois Tigeot 
353a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
354b5c29a34SFrançois Tigeot 	if (ret)
355b5c29a34SFrançois Tigeot 		return ret;
356b5c29a34SFrançois Tigeot 
3578621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(4));
3588621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
3598621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr);
3608621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3618621f407SFrançois Tigeot 	intel_ring_advance(engine);
362e3adcf8fSFrançois Tigeot 
363e3adcf8fSFrançois Tigeot 	return 0;
364e3adcf8fSFrançois Tigeot }
365e3adcf8fSFrançois Tigeot 
3669edbd4a0SFrançois Tigeot static int
367a05eeebfSFrançois Tigeot gen8_emit_pipe_control(struct drm_i915_gem_request *req,
36824edb884SFrançois Tigeot 		       u32 flags, u32 scratch_addr)
36924edb884SFrançois Tigeot {
3708621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
37124edb884SFrançois Tigeot 	int ret;
37224edb884SFrançois Tigeot 
373a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
37424edb884SFrançois Tigeot 	if (ret)
37524edb884SFrançois Tigeot 		return ret;
37624edb884SFrançois Tigeot 
3778621f407SFrançois Tigeot 	intel_ring_emit(engine, GFX_OP_PIPE_CONTROL(6));
3788621f407SFrançois Tigeot 	intel_ring_emit(engine, flags);
3798621f407SFrançois Tigeot 	intel_ring_emit(engine, scratch_addr);
3808621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3818621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3828621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
3838621f407SFrançois Tigeot 	intel_ring_advance(engine);
38424edb884SFrançois Tigeot 
38524edb884SFrançois Tigeot 	return 0;
38624edb884SFrançois Tigeot }
38724edb884SFrançois Tigeot 
38824edb884SFrançois Tigeot static int
389a05eeebfSFrançois Tigeot gen8_render_ring_flush(struct drm_i915_gem_request *req,
3909edbd4a0SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
3919edbd4a0SFrançois Tigeot {
3929edbd4a0SFrançois Tigeot 	u32 flags = 0;
3938621f407SFrançois Tigeot 	u32 scratch_addr = req->engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
3949edbd4a0SFrançois Tigeot 	int ret;
3959edbd4a0SFrançois Tigeot 
3969edbd4a0SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
3979edbd4a0SFrançois Tigeot 
3989edbd4a0SFrançois Tigeot 	if (flush_domains) {
3999edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
4009edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
401aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
402b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
4039edbd4a0SFrançois Tigeot 	}
4049edbd4a0SFrançois Tigeot 	if (invalidate_domains) {
4059edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
4069edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
4079edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
4089edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
4099edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
4109edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
4119edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
4129edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
4139edbd4a0SFrançois Tigeot 
41424edb884SFrançois Tigeot 		/* WaCsStallBeforeStateCacheInvalidate:bdw,chv */
415a05eeebfSFrançois Tigeot 		ret = gen8_emit_pipe_control(req,
41624edb884SFrançois Tigeot 					     PIPE_CONTROL_CS_STALL |
41724edb884SFrançois Tigeot 					     PIPE_CONTROL_STALL_AT_SCOREBOARD,
41824edb884SFrançois Tigeot 					     0);
4199edbd4a0SFrançois Tigeot 		if (ret)
4209edbd4a0SFrançois Tigeot 			return ret;
42124edb884SFrançois Tigeot 	}
4229edbd4a0SFrançois Tigeot 
423a05eeebfSFrançois Tigeot 	return gen8_emit_pipe_control(req, flags, scratch_addr);
4249edbd4a0SFrançois Tigeot }
4259edbd4a0SFrançois Tigeot 
4268621f407SFrançois Tigeot static void ring_write_tail(struct intel_engine_cs *engine,
427b5c29a34SFrançois Tigeot 			    u32 value)
428e3adcf8fSFrançois Tigeot {
4298621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
4308621f407SFrançois Tigeot 	I915_WRITE_TAIL(engine, value);
431e3adcf8fSFrançois Tigeot }
432e3adcf8fSFrançois Tigeot 
4338621f407SFrançois Tigeot u64 intel_ring_get_active_head(struct intel_engine_cs *engine)
434e3adcf8fSFrançois Tigeot {
4358621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
436ba55f2f5SFrançois Tigeot 	u64 acthd;
437e3adcf8fSFrançois Tigeot 
4388621f407SFrançois Tigeot 	if (INTEL_INFO(engine->dev)->gen >= 8)
4398621f407SFrançois Tigeot 		acthd = I915_READ64_2x32(RING_ACTHD(engine->mmio_base),
4408621f407SFrançois Tigeot 					 RING_ACTHD_UDW(engine->mmio_base));
4418621f407SFrançois Tigeot 	else if (INTEL_INFO(engine->dev)->gen >= 4)
4428621f407SFrançois Tigeot 		acthd = I915_READ(RING_ACTHD(engine->mmio_base));
443ba55f2f5SFrançois Tigeot 	else
444ba55f2f5SFrançois Tigeot 		acthd = I915_READ(ACTHD);
445ba55f2f5SFrançois Tigeot 
446ba55f2f5SFrançois Tigeot 	return acthd;
447e3adcf8fSFrançois Tigeot }
448e3adcf8fSFrançois Tigeot 
4498621f407SFrançois Tigeot static void ring_setup_phys_status_page(struct intel_engine_cs *engine)
4505d0b1887SFrançois Tigeot {
4518621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
4525d0b1887SFrançois Tigeot 	u32 addr;
4535d0b1887SFrançois Tigeot 
4545d0b1887SFrançois Tigeot 	addr = dev_priv->status_page_dmah->busaddr;
4558621f407SFrançois Tigeot 	if (INTEL_INFO(engine->dev)->gen >= 4)
4565d0b1887SFrançois Tigeot 		addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0;
4575d0b1887SFrançois Tigeot 	I915_WRITE(HWS_PGA, addr);
4585d0b1887SFrançois Tigeot }
4595d0b1887SFrançois Tigeot 
4608621f407SFrançois Tigeot static void intel_ring_setup_status_page(struct intel_engine_cs *engine)
461477eb7f9SFrançois Tigeot {
4628621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
4638621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
464aee94f86SFrançois Tigeot 	i915_reg_t mmio;
465477eb7f9SFrançois Tigeot 
466477eb7f9SFrançois Tigeot 	/* The ring status page addresses are no longer next to the rest of
467477eb7f9SFrançois Tigeot 	 * the ring registers as of gen7.
468477eb7f9SFrançois Tigeot 	 */
469477eb7f9SFrançois Tigeot 	if (IS_GEN7(dev)) {
4708621f407SFrançois Tigeot 		switch (engine->id) {
471477eb7f9SFrançois Tigeot 		case RCS:
472477eb7f9SFrançois Tigeot 			mmio = RENDER_HWS_PGA_GEN7;
473477eb7f9SFrançois Tigeot 			break;
474477eb7f9SFrançois Tigeot 		case BCS:
475477eb7f9SFrançois Tigeot 			mmio = BLT_HWS_PGA_GEN7;
476477eb7f9SFrançois Tigeot 			break;
477477eb7f9SFrançois Tigeot 		/*
478477eb7f9SFrançois Tigeot 		 * VCS2 actually doesn't exist on Gen7. Only shut up
479477eb7f9SFrançois Tigeot 		 * gcc switch check warning
480477eb7f9SFrançois Tigeot 		 */
481477eb7f9SFrançois Tigeot 		case VCS2:
482477eb7f9SFrançois Tigeot 		case VCS:
483477eb7f9SFrançois Tigeot 			mmio = BSD_HWS_PGA_GEN7;
484477eb7f9SFrançois Tigeot 			break;
485477eb7f9SFrançois Tigeot 		case VECS:
486477eb7f9SFrançois Tigeot 			mmio = VEBOX_HWS_PGA_GEN7;
487477eb7f9SFrançois Tigeot 			break;
488477eb7f9SFrançois Tigeot 		}
4898621f407SFrançois Tigeot 	} else if (IS_GEN6(engine->dev)) {
4908621f407SFrançois Tigeot 		mmio = RING_HWS_PGA_GEN6(engine->mmio_base);
491477eb7f9SFrançois Tigeot 	} else {
492477eb7f9SFrançois Tigeot 		/* XXX: gen8 returns to sanity */
4938621f407SFrançois Tigeot 		mmio = RING_HWS_PGA(engine->mmio_base);
494477eb7f9SFrançois Tigeot 	}
495477eb7f9SFrançois Tigeot 
4968621f407SFrançois Tigeot 	I915_WRITE(mmio, (u32)engine->status_page.gfx_addr);
497477eb7f9SFrançois Tigeot 	POSTING_READ(mmio);
498477eb7f9SFrançois Tigeot 
499477eb7f9SFrançois Tigeot 	/*
500477eb7f9SFrançois Tigeot 	 * Flush the TLB for this page
501477eb7f9SFrançois Tigeot 	 *
502477eb7f9SFrançois Tigeot 	 * FIXME: These two bits have disappeared on gen8, so a question
503477eb7f9SFrançois Tigeot 	 * arises: do we still need this and if so how should we go about
504477eb7f9SFrançois Tigeot 	 * invalidating the TLB?
505477eb7f9SFrançois Tigeot 	 */
506477eb7f9SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
5078621f407SFrançois Tigeot 		i915_reg_t reg = RING_INSTPM(engine->mmio_base);
508477eb7f9SFrançois Tigeot 
509477eb7f9SFrançois Tigeot 		/* ring should be idle before issuing a sync flush*/
5108621f407SFrançois Tigeot 		WARN_ON((I915_READ_MODE(engine) & MODE_IDLE) == 0);
511477eb7f9SFrançois Tigeot 
512477eb7f9SFrançois Tigeot 		I915_WRITE(reg,
513477eb7f9SFrançois Tigeot 			   _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
514477eb7f9SFrançois Tigeot 					      INSTPM_SYNC_FLUSH));
515477eb7f9SFrançois Tigeot 		if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0,
516477eb7f9SFrançois Tigeot 			     1000))
517477eb7f9SFrançois Tigeot 			DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
5188621f407SFrançois Tigeot 				  engine->name);
519477eb7f9SFrançois Tigeot 	}
520477eb7f9SFrançois Tigeot }
521477eb7f9SFrançois Tigeot 
5228621f407SFrançois Tigeot static bool stop_ring(struct intel_engine_cs *engine)
523e3adcf8fSFrançois Tigeot {
5248621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(engine->dev);
525e3adcf8fSFrançois Tigeot 
5268621f407SFrançois Tigeot 	if (!IS_GEN2(engine->dev)) {
5278621f407SFrançois Tigeot 		I915_WRITE_MODE(engine, _MASKED_BIT_ENABLE(STOP_RING));
5288621f407SFrançois Tigeot 		if (wait_for((I915_READ_MODE(engine) & MODE_IDLE) != 0, 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 
5448621f407SFrançois Tigeot 	if (!IS_GEN2(engine->dev)) {
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 void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
553ba55f2f5SFrançois Tigeot {
5548621f407SFrançois Tigeot 	memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
5558621f407SFrançois Tigeot }
5568621f407SFrançois Tigeot 
5578621f407SFrançois Tigeot static int init_ring_common(struct intel_engine_cs *engine)
5588621f407SFrançois Tigeot {
5598621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
560ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
5618621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = engine->buffer;
562ba55f2f5SFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
563ba55f2f5SFrançois Tigeot 	int ret = 0;
564ba55f2f5SFrançois Tigeot 
5652c9916cdSFrançois Tigeot 	intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
566ba55f2f5SFrançois Tigeot 
5678621f407SFrançois Tigeot 	if (!stop_ring(engine)) {
568ba55f2f5SFrançois Tigeot 		/* G45 ring initialization often fails to reset head to zero */
569b5c29a34SFrançois Tigeot 		DRM_DEBUG_KMS("%s head not reset to zero "
570e3adcf8fSFrançois Tigeot 			      "ctl %08x head %08x tail %08x start %08x\n",
5718621f407SFrançois Tigeot 			      engine->name,
5728621f407SFrançois Tigeot 			      I915_READ_CTL(engine),
5738621f407SFrançois Tigeot 			      I915_READ_HEAD(engine),
5748621f407SFrançois Tigeot 			      I915_READ_TAIL(engine),
5758621f407SFrançois Tigeot 			      I915_READ_START(engine));
576e3adcf8fSFrançois Tigeot 
5778621f407SFrançois Tigeot 		if (!stop_ring(engine)) {
578e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to set %s head to zero "
579e3adcf8fSFrançois Tigeot 				  "ctl %08x head %08x tail %08x start %08x\n",
5808621f407SFrançois Tigeot 				  engine->name,
5818621f407SFrançois Tigeot 				  I915_READ_CTL(engine),
5828621f407SFrançois Tigeot 				  I915_READ_HEAD(engine),
5838621f407SFrançois Tigeot 				  I915_READ_TAIL(engine),
5848621f407SFrançois Tigeot 				  I915_READ_START(engine));
585686a02f1SFrançois Tigeot 			ret = -EIO;
586686a02f1SFrançois Tigeot 			goto out;
587e3adcf8fSFrançois Tigeot 		}
588ba55f2f5SFrançois Tigeot 	}
589ba55f2f5SFrançois Tigeot 
590ba55f2f5SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev))
5918621f407SFrançois Tigeot 		intel_ring_setup_status_page(engine);
592ba55f2f5SFrançois Tigeot 	else
5938621f407SFrançois Tigeot 		ring_setup_phys_status_page(engine);
594ba55f2f5SFrançois Tigeot 
5950f370975SMatthew Dillon 	/* Enforce ordering by reading HEAD register back */
5968621f407SFrançois Tigeot 	I915_READ_HEAD(engine);
5970f370975SMatthew Dillon 
598ba55f2f5SFrançois Tigeot 	/* Initialize the ring. This must happen _after_ we've cleared the ring
599ba55f2f5SFrançois Tigeot 	 * registers with the above sequence (the readback of the HEAD registers
600ba55f2f5SFrançois Tigeot 	 * also enforces ordering), otherwise the hw might lose the new ring
601ba55f2f5SFrançois Tigeot 	 * register values. */
6028621f407SFrançois Tigeot 	I915_WRITE_START(engine, i915_gem_obj_ggtt_offset(obj));
6031b13d190SFrançois Tigeot 
6041b13d190SFrançois Tigeot 	/* WaClearRingBufHeadRegAtInit:ctg,elk */
6058621f407SFrançois Tigeot 	if (I915_READ_HEAD(engine))
6061b13d190SFrançois Tigeot 		DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
6078621f407SFrançois Tigeot 			  engine->name, I915_READ_HEAD(engine));
6088621f407SFrançois Tigeot 	I915_WRITE_HEAD(engine, 0);
6098621f407SFrançois Tigeot 	(void)I915_READ_HEAD(engine);
6101b13d190SFrançois Tigeot 
6118621f407SFrançois Tigeot 	I915_WRITE_CTL(engine,
612ba55f2f5SFrançois Tigeot 			((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES)
613ba55f2f5SFrançois Tigeot 			| RING_VALID);
614ba55f2f5SFrançois Tigeot 
615ba55f2f5SFrançois Tigeot 	/* If the head is still not zero, the ring is dead */
6168621f407SFrançois Tigeot 	if (wait_for((I915_READ_CTL(engine) & RING_VALID) != 0 &&
6178621f407SFrançois Tigeot 		     I915_READ_START(engine) == i915_gem_obj_ggtt_offset(obj) &&
6188621f407SFrançois Tigeot 		     (I915_READ_HEAD(engine) & HEAD_ADDR) == 0, 50)) {
619ba55f2f5SFrançois Tigeot 		DRM_ERROR("%s initialization failed "
620ba55f2f5SFrançois Tigeot 			  "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08lx]\n",
6218621f407SFrançois Tigeot 			  engine->name,
6228621f407SFrançois Tigeot 			  I915_READ_CTL(engine),
6238621f407SFrançois Tigeot 			  I915_READ_CTL(engine) & RING_VALID,
6248621f407SFrançois Tigeot 			  I915_READ_HEAD(engine), I915_READ_TAIL(engine),
6258621f407SFrançois Tigeot 			  I915_READ_START(engine),
6268621f407SFrançois Tigeot 			  (unsigned long)i915_gem_obj_ggtt_offset(obj));
627ba55f2f5SFrançois Tigeot 		ret = -EIO;
628ba55f2f5SFrançois Tigeot 		goto out;
629ba55f2f5SFrançois Tigeot 	}
630e3adcf8fSFrançois Tigeot 
6312c9916cdSFrançois Tigeot 	ringbuf->last_retired_head = -1;
6328621f407SFrançois Tigeot 	ringbuf->head = I915_READ_HEAD(engine);
6338621f407SFrançois Tigeot 	ringbuf->tail = I915_READ_TAIL(engine) & TAIL_ADDR;
6342c9916cdSFrançois Tigeot 	intel_ring_update_space(ringbuf);
635e3adcf8fSFrançois Tigeot 
6368621f407SFrançois Tigeot 	intel_engine_init_hangcheck(engine);
6375d0b1887SFrançois Tigeot 
638686a02f1SFrançois Tigeot out:
6392c9916cdSFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
640686a02f1SFrançois Tigeot 
641686a02f1SFrançois Tigeot 	return ret;
642e3adcf8fSFrançois Tigeot }
643e3adcf8fSFrançois Tigeot 
6441b13d190SFrançois Tigeot void
6458621f407SFrançois Tigeot intel_fini_pipe_control(struct intel_engine_cs *engine)
6461b13d190SFrançois Tigeot {
6478621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
6481b13d190SFrançois Tigeot 
6498621f407SFrançois Tigeot 	if (engine->scratch.obj == NULL)
6501b13d190SFrançois Tigeot 		return;
6511b13d190SFrançois Tigeot 
6521b13d190SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 5) {
6538621f407SFrançois Tigeot 		kunmap(sg_page(engine->scratch.obj->pages->sgl));
6548621f407SFrançois Tigeot 		i915_gem_object_ggtt_unpin(engine->scratch.obj);
6551b13d190SFrançois Tigeot 	}
6561b13d190SFrançois Tigeot 
6578621f407SFrançois Tigeot 	drm_gem_object_unreference(&engine->scratch.obj->base);
6588621f407SFrançois Tigeot 	engine->scratch.obj = NULL;
6591b13d190SFrançois Tigeot }
6601b13d190SFrançois Tigeot 
6611b13d190SFrançois Tigeot int
6628621f407SFrançois Tigeot intel_init_pipe_control(struct intel_engine_cs *engine)
663e3adcf8fSFrançois Tigeot {
664e3adcf8fSFrançois Tigeot 	int ret;
665e3adcf8fSFrançois Tigeot 
6668621f407SFrançois Tigeot 	WARN_ON(engine->scratch.obj);
667e3adcf8fSFrançois Tigeot 
6688621f407SFrançois Tigeot 	engine->scratch.obj = i915_gem_alloc_object(engine->dev, 4096);
6698621f407SFrançois Tigeot 	if (engine->scratch.obj == NULL) {
670e3adcf8fSFrançois Tigeot 		DRM_ERROR("Failed to allocate seqno page\n");
671e3adcf8fSFrançois Tigeot 		ret = -ENOMEM;
672e3adcf8fSFrançois Tigeot 		goto err;
673e3adcf8fSFrançois Tigeot 	}
674e3adcf8fSFrançois Tigeot 
6758621f407SFrançois Tigeot 	ret = i915_gem_object_set_cache_level(engine->scratch.obj,
6768621f407SFrançois Tigeot 					      I915_CACHE_LLC);
677ba55f2f5SFrançois Tigeot 	if (ret)
678ba55f2f5SFrançois Tigeot 		goto err_unref;
679e3adcf8fSFrançois Tigeot 
6808621f407SFrançois Tigeot 	ret = i915_gem_obj_ggtt_pin(engine->scratch.obj, 4096, 0);
681e3adcf8fSFrançois Tigeot 	if (ret)
682e3adcf8fSFrançois Tigeot 		goto err_unref;
683e3adcf8fSFrançois Tigeot 
6848621f407SFrançois Tigeot 	engine->scratch.gtt_offset = i915_gem_obj_ggtt_offset(engine->scratch.obj);
6858621f407SFrançois Tigeot 	engine->scratch.cpu_page = kmap(sg_page(engine->scratch.obj->pages->sgl));
6868621f407SFrançois Tigeot 	if (engine->scratch.cpu_page == NULL) {
6875d0b1887SFrançois Tigeot 		ret = -ENOMEM;
688e3adcf8fSFrançois Tigeot 		goto err_unpin;
6895d0b1887SFrançois Tigeot 	}
690a2fdbec6SFrançois Tigeot 
691a2fdbec6SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
6928621f407SFrançois Tigeot 			 engine->name, engine->scratch.gtt_offset);
693e3adcf8fSFrançois Tigeot 	return 0;
694e3adcf8fSFrançois Tigeot 
695e3adcf8fSFrançois Tigeot err_unpin:
6968621f407SFrançois Tigeot 	i915_gem_object_ggtt_unpin(engine->scratch.obj);
697e3adcf8fSFrançois Tigeot err_unref:
6988621f407SFrançois Tigeot 	drm_gem_object_unreference(&engine->scratch.obj->base);
699e3adcf8fSFrançois Tigeot err:
700e3adcf8fSFrançois Tigeot 	return ret;
701e3adcf8fSFrançois Tigeot }
702e3adcf8fSFrançois Tigeot 
703a05eeebfSFrançois Tigeot static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
7041b13d190SFrançois Tigeot {
7052c9916cdSFrançois Tigeot 	int ret, i;
7068621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
7078621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
7081b13d190SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
7092c9916cdSFrançois Tigeot 	struct i915_workarounds *w = &dev_priv->workarounds;
7101b13d190SFrançois Tigeot 
711352ff8bdSFrançois Tigeot 	if (w->count == 0)
7122c9916cdSFrançois Tigeot 		return 0;
7131b13d190SFrançois Tigeot 
7148621f407SFrançois Tigeot 	engine->gpu_caches_dirty = true;
715a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7161b13d190SFrançois Tigeot 	if (ret)
7171b13d190SFrançois Tigeot 		return ret;
7181b13d190SFrançois Tigeot 
719a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, (w->count * 2 + 2));
7202c9916cdSFrançois Tigeot 	if (ret)
7212c9916cdSFrançois Tigeot 		return ret;
7222c9916cdSFrançois Tigeot 
7238621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_LOAD_REGISTER_IMM(w->count));
7242c9916cdSFrançois Tigeot 	for (i = 0; i < w->count; i++) {
7258621f407SFrançois Tigeot 		intel_ring_emit_reg(engine, w->reg[i].addr);
7268621f407SFrançois Tigeot 		intel_ring_emit(engine, w->reg[i].value);
7272c9916cdSFrançois Tigeot 	}
7288621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
7292c9916cdSFrançois Tigeot 
7308621f407SFrançois Tigeot 	intel_ring_advance(engine);
7312c9916cdSFrançois Tigeot 
7328621f407SFrançois Tigeot 	engine->gpu_caches_dirty = true;
733a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7342c9916cdSFrançois Tigeot 	if (ret)
7352c9916cdSFrançois Tigeot 		return ret;
7362c9916cdSFrançois Tigeot 
7372c9916cdSFrançois Tigeot 	DRM_DEBUG_DRIVER("Number of Workarounds emitted: %d\n", w->count);
7382c9916cdSFrançois Tigeot 
7392c9916cdSFrançois Tigeot 	return 0;
7402c9916cdSFrançois Tigeot }
7412c9916cdSFrançois Tigeot 
742a05eeebfSFrançois Tigeot static int intel_rcs_ctx_init(struct drm_i915_gem_request *req)
7432c9916cdSFrançois Tigeot {
7442c9916cdSFrançois Tigeot 	int ret;
7452c9916cdSFrançois Tigeot 
746a05eeebfSFrançois Tigeot 	ret = intel_ring_workarounds_emit(req);
7472c9916cdSFrançois Tigeot 	if (ret != 0)
7482c9916cdSFrançois Tigeot 		return ret;
7492c9916cdSFrançois Tigeot 
750a05eeebfSFrançois Tigeot 	ret = i915_gem_render_state_init(req);
7512c9916cdSFrançois Tigeot 	if (ret)
7522c9916cdSFrançois Tigeot 		return ret;
753c0e85e96SFrançois Tigeot 
754c0e85e96SFrançois Tigeot 	return 0;
7552c9916cdSFrançois Tigeot }
7562c9916cdSFrançois Tigeot 
7572c9916cdSFrançois Tigeot static int wa_add(struct drm_i915_private *dev_priv,
758aee94f86SFrançois Tigeot 		  i915_reg_t addr,
759aee94f86SFrançois Tigeot 		  const u32 mask, const u32 val)
7602c9916cdSFrançois Tigeot {
7612c9916cdSFrançois Tigeot 	const u32 idx = dev_priv->workarounds.count;
7622c9916cdSFrançois Tigeot 
7632c9916cdSFrançois Tigeot 	if (WARN_ON(idx >= I915_MAX_WA_REGS))
7642c9916cdSFrançois Tigeot 		return -ENOSPC;
7652c9916cdSFrançois Tigeot 
7662c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].addr = addr;
7672c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].value = val;
7682c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].mask = mask;
7692c9916cdSFrançois Tigeot 
7702c9916cdSFrançois Tigeot 	dev_priv->workarounds.count++;
7712c9916cdSFrançois Tigeot 
7722c9916cdSFrançois Tigeot 	return 0;
7732c9916cdSFrançois Tigeot }
7742c9916cdSFrançois Tigeot 
775a05eeebfSFrançois Tigeot #define WA_REG(addr, mask, val) do { \
7762c9916cdSFrançois Tigeot 		const int r = wa_add(dev_priv, (addr), (mask), (val)); \
7772c9916cdSFrançois Tigeot 		if (r) \
7782c9916cdSFrançois Tigeot 			return r; \
779a05eeebfSFrançois Tigeot 	} while (0)
7802c9916cdSFrançois Tigeot 
7812c9916cdSFrançois Tigeot #define WA_SET_BIT_MASKED(addr, mask) \
7822c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask))
7832c9916cdSFrançois Tigeot 
7842c9916cdSFrançois Tigeot #define WA_CLR_BIT_MASKED(addr, mask) \
7852c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_DISABLE(mask))
7862c9916cdSFrançois Tigeot 
7872c9916cdSFrançois Tigeot #define WA_SET_FIELD_MASKED(addr, mask, value) \
7882c9916cdSFrançois Tigeot 	WA_REG(addr, mask, _MASKED_FIELD(mask, value))
7892c9916cdSFrançois Tigeot 
7902c9916cdSFrançois Tigeot #define WA_SET_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) | (mask))
7912c9916cdSFrançois Tigeot #define WA_CLR_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) & ~(mask))
7922c9916cdSFrançois Tigeot 
7932c9916cdSFrançois Tigeot #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
7942c9916cdSFrançois Tigeot 
7958621f407SFrançois Tigeot static int wa_ring_whitelist_reg(struct intel_engine_cs *engine,
7968621f407SFrançois Tigeot 				 i915_reg_t reg)
797c0e85e96SFrançois Tigeot {
7988621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
799c0e85e96SFrançois Tigeot 	struct i915_workarounds *wa = &dev_priv->workarounds;
8008621f407SFrançois Tigeot 	const uint32_t index = wa->hw_whitelist_count[engine->id];
801c0e85e96SFrançois Tigeot 
802c0e85e96SFrançois Tigeot 	if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS))
803c0e85e96SFrançois Tigeot 		return -EINVAL;
804c0e85e96SFrançois Tigeot 
8058621f407SFrançois Tigeot 	WA_WRITE(RING_FORCE_TO_NONPRIV(engine->mmio_base, index),
806c0e85e96SFrançois Tigeot 		 i915_mmio_reg_offset(reg));
8078621f407SFrançois Tigeot 	wa->hw_whitelist_count[engine->id]++;
808c0e85e96SFrançois Tigeot 
809c0e85e96SFrançois Tigeot 	return 0;
810c0e85e96SFrançois Tigeot }
811c0e85e96SFrançois Tigeot 
8128621f407SFrançois Tigeot static int gen8_init_workarounds(struct intel_engine_cs *engine)
8132c9916cdSFrançois Tigeot {
8148621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
8152c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
8162c9916cdSFrançois Tigeot 
817a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
818a05eeebfSFrançois Tigeot 
819352ff8bdSFrançois Tigeot 	/* WaDisableAsyncFlipPerfMode:bdw,chv */
820a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE);
821a05eeebfSFrançois Tigeot 
822352ff8bdSFrançois Tigeot 	/* WaDisablePartialInstShootdown:bdw,chv */
8232c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
824352ff8bdSFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
8251b13d190SFrançois Tigeot 
8261b13d190SFrançois Tigeot 	/* Use Force Non-Coherent whenever executing a 3D context. This is a
8271b13d190SFrançois Tigeot 	 * workaround for for a possible hang in the unlikely event a TLB
8281b13d190SFrançois Tigeot 	 * invalidation occurs during a PSD flush.
8291b13d190SFrançois Tigeot 	 */
830352ff8bdSFrançois Tigeot 	/* WaForceEnableNonCoherent:bdw,chv */
831352ff8bdSFrançois Tigeot 	/* WaHdcDisableFetchWhenMasked:bdw,chv */
8322c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
8332c9916cdSFrançois Tigeot 			  HDC_DONOT_FETCH_MEM_WHEN_MASKED |
834352ff8bdSFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
8352c9916cdSFrançois Tigeot 
8362c9916cdSFrançois Tigeot 	/* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
8372c9916cdSFrançois Tigeot 	 * "The Hierarchical Z RAW Stall Optimization allows non-overlapping
8382c9916cdSFrançois Tigeot 	 *  polygons in the same 8x4 pixel/sample area to be processed without
8392c9916cdSFrançois Tigeot 	 *  stalling waiting for the earlier ones to write to Hierarchical Z
8402c9916cdSFrançois Tigeot 	 *  buffer."
8412c9916cdSFrançois Tigeot 	 *
842352ff8bdSFrançois Tigeot 	 * This optimization is off by default for BDW and CHV; turn it on.
8432c9916cdSFrançois Tigeot 	 */
8442c9916cdSFrançois Tigeot 	WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
8451b13d190SFrançois Tigeot 
846352ff8bdSFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:bdw,chv */
847352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
8481b13d190SFrançois Tigeot 
8491b13d190SFrançois Tigeot 	/*
8501b13d190SFrançois Tigeot 	 * BSpec recommends 8x4 when MSAA is used,
8511b13d190SFrançois Tigeot 	 * however in practice 16x4 seems fastest.
8521b13d190SFrançois Tigeot 	 *
8531b13d190SFrançois Tigeot 	 * Note that PS/WM thread counts depend on the WIZ hashing
8541b13d190SFrançois Tigeot 	 * disable bit, which we don't touch here, but it's good
8551b13d190SFrançois Tigeot 	 * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
8561b13d190SFrançois Tigeot 	 */
8572c9916cdSFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
8582c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_MASK,
8592c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_16x4);
8601b13d190SFrançois Tigeot 
8611b13d190SFrançois Tigeot 	return 0;
8621b13d190SFrançois Tigeot }
8631b13d190SFrançois Tigeot 
8648621f407SFrançois Tigeot static int bdw_init_workarounds(struct intel_engine_cs *engine)
8651b13d190SFrançois Tigeot {
866352ff8bdSFrançois Tigeot 	int ret;
8678621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
8681b13d190SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
8691b13d190SFrançois Tigeot 
8708621f407SFrançois Tigeot 	ret = gen8_init_workarounds(engine);
871352ff8bdSFrançois Tigeot 	if (ret)
872352ff8bdSFrançois Tigeot 		return ret;
873a05eeebfSFrançois Tigeot 
874352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bdw (pre-production) */
875352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
876a05eeebfSFrançois Tigeot 
877352ff8bdSFrançois Tigeot 	/* WaDisableDopClockGating:bdw */
878352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
879352ff8bdSFrançois Tigeot 			  DOP_CLOCK_GATING_DISABLE);
8801b13d190SFrançois Tigeot 
881352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
882352ff8bdSFrançois Tigeot 			  GEN8_SAMPLER_POWER_BYPASS_DIS);
883352ff8bdSFrançois Tigeot 
8842c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
885352ff8bdSFrançois Tigeot 			  /* WaForceContextSaveRestoreNonCoherent:bdw */
886352ff8bdSFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
887352ff8bdSFrançois Tigeot 			  /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
888352ff8bdSFrançois Tigeot 			  (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
8891b13d190SFrançois Tigeot 
890352ff8bdSFrançois Tigeot 	return 0;
891352ff8bdSFrançois Tigeot }
8921b13d190SFrançois Tigeot 
8938621f407SFrançois Tigeot static int chv_init_workarounds(struct intel_engine_cs *engine)
894352ff8bdSFrançois Tigeot {
895352ff8bdSFrançois Tigeot 	int ret;
8968621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
897352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
898352ff8bdSFrançois Tigeot 
8998621f407SFrançois Tigeot 	ret = gen8_init_workarounds(engine);
900352ff8bdSFrançois Tigeot 	if (ret)
901352ff8bdSFrançois Tigeot 		return ret;
902352ff8bdSFrançois Tigeot 
903352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:chv */
904352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
9052c9916cdSFrançois Tigeot 
9062c9916cdSFrançois Tigeot 	/* Improve HiZ throughput on CHV. */
9072c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
9082c9916cdSFrançois Tigeot 
9092c9916cdSFrançois Tigeot 	return 0;
9102c9916cdSFrançois Tigeot }
9112c9916cdSFrançois Tigeot 
9128621f407SFrançois Tigeot static int gen9_init_workarounds(struct intel_engine_cs *engine)
913477eb7f9SFrançois Tigeot {
9148621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
915477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
916c0e85e96SFrançois Tigeot 	int ret;
917477eb7f9SFrançois Tigeot 
9188621f407SFrançois Tigeot 	/* WaConextSwitchWithConcurrentTLBInvalidate:skl,bxt,kbl */
9198621f407SFrançois Tigeot 	I915_WRITE(GEN9_CSFE_CHICKEN1_RCS, _MASKED_BIT_ENABLE(GEN9_PREEMPT_GPGPU_SYNC_SWITCH_DISABLE));
9208621f407SFrançois Tigeot 
9218621f407SFrançois Tigeot 	/* WaEnableLbsSlaRetryTimerDecrement:skl,bxt,kbl */
922352ff8bdSFrançois Tigeot 	I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
923352ff8bdSFrançois Tigeot 		   GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
924352ff8bdSFrançois Tigeot 
9258621f407SFrançois Tigeot 	/* WaDisableKillLogic:bxt,skl,kbl */
926352ff8bdSFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
927352ff8bdSFrançois Tigeot 		   ECOCHK_DIS_TLB);
928352ff8bdSFrançois Tigeot 
9298621f407SFrançois Tigeot 	/* WaClearFlowControlGpgpuContextSave:skl,bxt,kbl */
9308621f407SFrançois Tigeot 	/* WaDisablePartialInstShootdown:skl,bxt,kbl */
931477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
9328621f407SFrançois Tigeot 			  FLOW_CONTROL_ENABLE |
933477eb7f9SFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
934477eb7f9SFrançois Tigeot 
9358621f407SFrançois Tigeot 	/* Syncing dependencies between camera and graphics:skl,bxt,kbl */
936477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
937477eb7f9SFrançois Tigeot 			  GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
938477eb7f9SFrançois Tigeot 
93919c468b4SFrançois Tigeot 	/* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
940aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
941aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
942477eb7f9SFrançois Tigeot 		WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
943477eb7f9SFrançois Tigeot 				  GEN9_DG_MIRROR_FIX_ENABLE);
944477eb7f9SFrançois Tigeot 
94519c468b4SFrançois Tigeot 	/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
946aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
947aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
948477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
949477eb7f9SFrançois Tigeot 				  GEN9_RHWO_OPTIMIZATION_DISABLE);
950a05eeebfSFrançois Tigeot 		/*
951a05eeebfSFrançois Tigeot 		 * WA also requires GEN9_SLICE_COMMON_ECO_CHICKEN0[14:14] to be set
952a05eeebfSFrançois Tigeot 		 * but we do that in per ctx batchbuffer as there is an issue
953a05eeebfSFrançois Tigeot 		 * with this register not getting restored on ctx restore
954a05eeebfSFrançois Tigeot 		 */
955477eb7f9SFrançois Tigeot 	}
956477eb7f9SFrançois Tigeot 
9578621f407SFrançois Tigeot 	/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt,kbl */
9588621f407SFrançois Tigeot 	/* WaEnableSamplerGPGPUPreemptionSupport:skl,bxt,kbl */
959477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
9608621f407SFrançois Tigeot 			  GEN9_ENABLE_YV12_BUGFIX |
9618621f407SFrançois Tigeot 			  GEN9_ENABLE_GPGPU_PREEMPTION);
962477eb7f9SFrançois Tigeot 
9638621f407SFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:skl,bxt,kbl */
9648621f407SFrançois Tigeot 	/* WaDisablePartialResolveInVc:skl,bxt,kbl */
965352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE |
966352ff8bdSFrançois Tigeot 					 GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE));
967477eb7f9SFrançois Tigeot 
9688621f407SFrançois Tigeot 	/* WaCcsTlbPrefetchDisable:skl,bxt,kbl */
969477eb7f9SFrançois Tigeot 	WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
970477eb7f9SFrançois Tigeot 			  GEN9_CCS_TLB_PREFETCH_ENABLE);
971477eb7f9SFrançois Tigeot 
97219c468b4SFrançois Tigeot 	/* WaDisableMaskBasedCammingInRCC:skl,bxt */
973aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_C0) ||
974aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
97519c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
97619c468b4SFrançois Tigeot 				  PIXEL_MASK_CAMMING_DISABLE);
97719c468b4SFrançois Tigeot 
9788621f407SFrançois Tigeot 	/* WaForceContextSaveRestoreNonCoherent:skl,bxt,kbl */
9798621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
9808621f407SFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
9818621f407SFrançois Tigeot 			  HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE);
98219c468b4SFrançois Tigeot 
9838621f407SFrançois Tigeot 	/* WaForceEnableNonCoherent and WaDisableHDCInvalidation are
9848621f407SFrançois Tigeot 	 * both tied to WaForceContextSaveRestoreNonCoherent
9858621f407SFrançois Tigeot 	 * in some hsds for skl. We keep the tie for all gen9. The
9868621f407SFrançois Tigeot 	 * documentation is a bit hazy and so we want to get common behaviour,
9878621f407SFrançois Tigeot 	 * even though there is no clear evidence we would need both on kbl/bxt.
9888621f407SFrançois Tigeot 	 * This area has been source of system hangs so we play it safe
9898621f407SFrançois Tigeot 	 * and mimic the skl regardless of what bspec says.
9908621f407SFrançois Tigeot 	 *
9918621f407SFrançois Tigeot 	 * Use Force Non-Coherent whenever executing a 3D context. This
9928621f407SFrançois Tigeot 	 * is a workaround for a possible hang in the unlikely event
9938621f407SFrançois Tigeot 	 * a TLB invalidation occurs during a PSD flush.
9948621f407SFrançois Tigeot 	 */
9958621f407SFrançois Tigeot 
9968621f407SFrançois Tigeot 	/* WaForceEnableNonCoherent:skl,bxt,kbl */
9978621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
9988621f407SFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
9998621f407SFrançois Tigeot 
10008621f407SFrançois Tigeot 	/* WaDisableHDCInvalidation:skl,bxt,kbl */
10018621f407SFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
10028621f407SFrançois Tigeot 		   BDW_DISABLE_HDC_INVALIDATION);
10038621f407SFrançois Tigeot 
10048621f407SFrançois Tigeot 	/* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt,kbl */
10058621f407SFrançois Tigeot 	if (IS_SKYLAKE(dev_priv) ||
10068621f407SFrançois Tigeot 	    IS_KABYLAKE(dev_priv) ||
10078621f407SFrançois Tigeot 	    IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
1008352ff8bdSFrançois Tigeot 		WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
1009352ff8bdSFrançois Tigeot 				  GEN8_SAMPLER_POWER_BYPASS_DIS);
1010352ff8bdSFrançois Tigeot 
10118621f407SFrançois Tigeot 	/* WaDisableSTUnitPowerOptimization:skl,bxt,kbl */
1012352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
1013352ff8bdSFrançois Tigeot 
10148621f407SFrançois Tigeot 	/* WaOCLCoherentLineFlush:skl,bxt,kbl */
1015c0e85e96SFrançois Tigeot 	I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) |
1016c0e85e96SFrançois Tigeot 				    GEN8_LQSC_FLUSH_COHERENT_LINES));
1017c0e85e96SFrançois Tigeot 
10188621f407SFrançois Tigeot 	/* WaVFEStateAfterPipeControlwithMediaStateClear:skl,bxt */
10198621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN9_CTX_PREEMPT_REG);
1020c0e85e96SFrançois Tigeot 	if (ret)
1021c0e85e96SFrançois Tigeot 		return ret;
1022c0e85e96SFrançois Tigeot 
10238621f407SFrançois Tigeot 	/* WaEnablePreemptionGranularityControlByUMD:skl,bxt,kbl */
10248621f407SFrançois Tigeot 	ret= wa_ring_whitelist_reg(engine, GEN8_CS_CHICKEN1);
10258621f407SFrançois Tigeot 	if (ret)
10268621f407SFrançois Tigeot 		return ret;
10278621f407SFrançois Tigeot 
10288621f407SFrançois Tigeot 	/* WaAllowUMDToModifyHDCChicken1:skl,bxt,kbl */
10298621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_HDC_CHICKEN1);
1030c0e85e96SFrançois Tigeot 	if (ret)
1031c0e85e96SFrançois Tigeot 		return ret;
1032c0e85e96SFrançois Tigeot 
1033477eb7f9SFrançois Tigeot 	return 0;
1034477eb7f9SFrançois Tigeot }
1035477eb7f9SFrançois Tigeot 
10368621f407SFrançois Tigeot static int skl_tune_iz_hashing(struct intel_engine_cs *engine)
1037477eb7f9SFrançois Tigeot {
10388621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1039477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1040477eb7f9SFrançois Tigeot 	u8 vals[3] = { 0, 0, 0 };
1041477eb7f9SFrançois Tigeot 	unsigned int i;
1042477eb7f9SFrançois Tigeot 
1043477eb7f9SFrançois Tigeot 	for (i = 0; i < 3; i++) {
1044477eb7f9SFrançois Tigeot 		u8 ss;
1045477eb7f9SFrançois Tigeot 
1046477eb7f9SFrançois Tigeot 		/*
1047477eb7f9SFrançois Tigeot 		 * Only consider slices where one, and only one, subslice has 7
1048477eb7f9SFrançois Tigeot 		 * EUs
1049477eb7f9SFrançois Tigeot 		 */
1050aee94f86SFrançois Tigeot 		if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
1051477eb7f9SFrançois Tigeot 			continue;
1052477eb7f9SFrançois Tigeot 
1053477eb7f9SFrançois Tigeot 		/*
1054477eb7f9SFrançois Tigeot 		 * subslice_7eu[i] != 0 (because of the check above) and
1055477eb7f9SFrançois Tigeot 		 * ss_max == 4 (maximum number of subslices possible per slice)
1056477eb7f9SFrançois Tigeot 		 *
1057477eb7f9SFrançois Tigeot 		 * ->    0 <= ss <= 3;
1058477eb7f9SFrançois Tigeot 		 */
1059477eb7f9SFrançois Tigeot 		ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
1060477eb7f9SFrançois Tigeot 		vals[i] = 3 - ss;
1061477eb7f9SFrançois Tigeot 	}
1062477eb7f9SFrançois Tigeot 
1063477eb7f9SFrançois Tigeot 	if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0)
1064477eb7f9SFrançois Tigeot 		return 0;
1065477eb7f9SFrançois Tigeot 
1066477eb7f9SFrançois Tigeot 	/* Tune IZ hashing. See intel_device_info_runtime_init() */
1067477eb7f9SFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
1068477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(2) |
1069477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(1) |
1070477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(0),
1071477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(2, vals[2]) |
1072477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(1, vals[1]) |
1073477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(0, vals[0]));
1074477eb7f9SFrançois Tigeot 
1075477eb7f9SFrançois Tigeot 	return 0;
1076477eb7f9SFrançois Tigeot }
1077477eb7f9SFrançois Tigeot 
10788621f407SFrançois Tigeot static int skl_init_workarounds(struct intel_engine_cs *engine)
1079477eb7f9SFrançois Tigeot {
1080352ff8bdSFrançois Tigeot 	int ret;
10818621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1082477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1083477eb7f9SFrançois Tigeot 
10848621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
1085352ff8bdSFrançois Tigeot 	if (ret)
1086352ff8bdSFrançois Tigeot 		return ret;
1087352ff8bdSFrançois Tigeot 
1088c0e85e96SFrançois Tigeot 	/*
1089c0e85e96SFrançois Tigeot 	 * Actual WA is to disable percontext preemption granularity control
1090c0e85e96SFrançois Tigeot 	 * until D0 which is the default case so this is equivalent to
1091c0e85e96SFrançois Tigeot 	 * !WaDisablePerCtxtPreemptionGranularityControl:skl
1092c0e85e96SFrançois Tigeot 	 */
1093c0e85e96SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_E0, REVID_FOREVER)) {
1094c0e85e96SFrançois Tigeot 		I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
1095c0e85e96SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
1096c0e85e96SFrançois Tigeot 	}
1097c0e85e96SFrançois Tigeot 
1098aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
1099352ff8bdSFrançois Tigeot 		/* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
1100352ff8bdSFrançois Tigeot 		I915_WRITE(FF_SLICE_CS_CHICKEN2,
1101352ff8bdSFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
1102352ff8bdSFrançois Tigeot 	}
1103352ff8bdSFrançois Tigeot 
1104352ff8bdSFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
1105352ff8bdSFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
1106352ff8bdSFrançois Tigeot 	 */
1107aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_E0))
1108352ff8bdSFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:skl */
1109352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
1110352ff8bdSFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
1111352ff8bdSFrançois Tigeot 
1112352ff8bdSFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:skl */
1113aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER)) {
1114352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
1115352ff8bdSFrançois Tigeot 					   GEN9_GAPS_TSV_CREDIT_DISABLE));
1116352ff8bdSFrançois Tigeot 	}
1117477eb7f9SFrançois Tigeot 
1118477eb7f9SFrançois Tigeot 	/* WaDisablePowerCompilerClockGating:skl */
1119aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_B0, SKL_REVID_B0))
1120477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(HIZ_CHICKEN,
1121477eb7f9SFrançois Tigeot 				  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
1122477eb7f9SFrançois Tigeot 
1123a05eeebfSFrançois Tigeot 	/* WaBarrierPerformanceFixDisable:skl */
1124aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0))
1125a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
1126a05eeebfSFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE |
1127a05eeebfSFrançois Tigeot 				  HDC_BARRIER_PERFORMANCE_DISABLE);
1128a05eeebfSFrançois Tigeot 
1129a05eeebfSFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:skl */
1130aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_F0))
1131a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(
1132a05eeebfSFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
1133a05eeebfSFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
1134a05eeebfSFrançois Tigeot 
11358621f407SFrançois Tigeot 	/* WaDisableGafsUnitClkGating:skl */
11368621f407SFrançois Tigeot 	WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
11378621f407SFrançois Tigeot 
11388621f407SFrançois Tigeot 	/* WaInPlaceDecompressionHang:skl */
11398621f407SFrançois Tigeot 	if (IS_SKL_REVID(dev_priv, SKL_REVID_H0, REVID_FOREVER))
11408621f407SFrançois Tigeot 		WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
11418621f407SFrançois Tigeot 			   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
11428621f407SFrançois Tigeot 
1143c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:skl */
11448621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
1145c0e85e96SFrançois Tigeot 	if (ret)
1146c0e85e96SFrançois Tigeot 		return ret;
1147c0e85e96SFrançois Tigeot 
11488621f407SFrançois Tigeot 	return skl_tune_iz_hashing(engine);
1149477eb7f9SFrançois Tigeot }
1150477eb7f9SFrançois Tigeot 
11518621f407SFrançois Tigeot static int bxt_init_workarounds(struct intel_engine_cs *engine)
115219c468b4SFrançois Tigeot {
1153352ff8bdSFrançois Tigeot 	int ret;
11548621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
115519c468b4SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
115619c468b4SFrançois Tigeot 
11578621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
1158352ff8bdSFrançois Tigeot 	if (ret)
1159352ff8bdSFrançois Tigeot 		return ret;
1160352ff8bdSFrançois Tigeot 
1161352ff8bdSFrançois Tigeot 	/* WaStoreMultiplePTEenable:bxt */
1162352ff8bdSFrançois Tigeot 	/* This is a requirement according to Hardware specification */
1163aee94f86SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
1164352ff8bdSFrançois Tigeot 		I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
1165352ff8bdSFrançois Tigeot 
1166352ff8bdSFrançois Tigeot 	/* WaSetClckGatingDisableMedia:bxt */
1167aee94f86SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
1168352ff8bdSFrançois Tigeot 		I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
1169352ff8bdSFrançois Tigeot 					    ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
1170352ff8bdSFrançois Tigeot 	}
117119c468b4SFrançois Tigeot 
117219c468b4SFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bxt */
117319c468b4SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
117419c468b4SFrançois Tigeot 			  STALL_DOP_GATING_DISABLE);
117519c468b4SFrançois Tigeot 
117619c468b4SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:bxt */
1177aee94f86SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) {
117819c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(
117919c468b4SFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
118019c468b4SFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
118119c468b4SFrançois Tigeot 	}
118219c468b4SFrançois Tigeot 
1183c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt */
1184c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForInstancedDraw:bxt */
1185c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemtionForInstanceId:bxt */
1186c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:bxt */
1187c0e85e96SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
11888621f407SFrançois Tigeot 		ret = wa_ring_whitelist_reg(engine, GEN9_CS_DEBUG_MODE1);
1189c0e85e96SFrançois Tigeot 		if (ret)
1190c0e85e96SFrançois Tigeot 			return ret;
1191c0e85e96SFrançois Tigeot 
11928621f407SFrançois Tigeot 		ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
1193c0e85e96SFrançois Tigeot 		if (ret)
1194c0e85e96SFrançois Tigeot 			return ret;
1195c0e85e96SFrançois Tigeot 	}
1196c0e85e96SFrançois Tigeot 
11978621f407SFrançois Tigeot 	/* WaInsertDummyPushConstPs:bxt */
11988621f407SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_B0))
11998621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
12008621f407SFrançois Tigeot 				  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
12018621f407SFrançois Tigeot 
12028621f407SFrançois Tigeot 	/* WaInPlaceDecompressionHang:bxt */
12038621f407SFrançois Tigeot 	if (IS_BXT_REVID(dev_priv, BXT_REVID_C0, REVID_FOREVER))
12048621f407SFrançois Tigeot 		WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
12058621f407SFrançois Tigeot 			   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
12068621f407SFrançois Tigeot 
120719c468b4SFrançois Tigeot 	return 0;
120819c468b4SFrançois Tigeot }
120919c468b4SFrançois Tigeot 
12108621f407SFrançois Tigeot static int kbl_init_workarounds(struct intel_engine_cs *engine)
12112c9916cdSFrançois Tigeot {
12128621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
12138621f407SFrançois Tigeot 	int ret;
12148621f407SFrançois Tigeot 
12158621f407SFrançois Tigeot 	ret = gen9_init_workarounds(engine);
12168621f407SFrançois Tigeot 	if (ret)
12178621f407SFrançois Tigeot 		return ret;
12188621f407SFrançois Tigeot 
12198621f407SFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:kbl */
12208621f407SFrançois Tigeot 	I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
12218621f407SFrançois Tigeot 				   GEN9_GAPS_TSV_CREDIT_DISABLE));
12228621f407SFrançois Tigeot 
12238621f407SFrançois Tigeot 	/* WaDisableDynamicCreditSharing:kbl */
12248621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
12258621f407SFrançois Tigeot 		WA_SET_BIT(GAMT_CHKN_BIT_REG,
12268621f407SFrançois Tigeot 			   GAMT_CHKN_DISABLE_DYNAMIC_CREDIT_SHARING);
12278621f407SFrançois Tigeot 
12288621f407SFrançois Tigeot 	/* WaDisableFenceDestinationToSLM:kbl (pre-prod) */
12298621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, KBL_REVID_A0, KBL_REVID_A0))
12308621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
12318621f407SFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE);
12328621f407SFrançois Tigeot 
12338621f407SFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
12348621f407SFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
12358621f407SFrançois Tigeot 	 */
12368621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
12378621f407SFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:kbl */
12388621f407SFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
12398621f407SFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
12408621f407SFrançois Tigeot 
12418621f407SFrançois Tigeot 	/* WaInsertDummyPushConstPs:kbl */
12428621f407SFrançois Tigeot 	if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
12438621f407SFrançois Tigeot 		WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
12448621f407SFrançois Tigeot 				  GEN8_SBE_DISABLE_REPLAY_BUF_OPTIMIZATION);
12458621f407SFrançois Tigeot 
12468621f407SFrançois Tigeot 	/* WaDisableGafsUnitClkGating:kbl */
12478621f407SFrançois Tigeot 	WA_SET_BIT(GEN7_UCGCTL4, GEN8_EU_GAUNIT_CLOCK_GATE_DISABLE);
12488621f407SFrançois Tigeot 
12498621f407SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:kbl */
12508621f407SFrançois Tigeot 	WA_SET_BIT_MASKED(
12518621f407SFrançois Tigeot 		GEN7_HALF_SLICE_CHICKEN1,
12528621f407SFrançois Tigeot 		GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
12538621f407SFrançois Tigeot 
12548621f407SFrançois Tigeot 	/* WaInPlaceDecompressionHang:kbl */
12558621f407SFrançois Tigeot 	WA_SET_BIT(GEN9_GAMT_ECO_REG_RW_IA,
12568621f407SFrançois Tigeot 		   GAMT_ECO_ENABLE_IN_PLACE_DECOMPRESS);
12578621f407SFrançois Tigeot 
12588621f407SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:kbl */
12598621f407SFrançois Tigeot 	ret = wa_ring_whitelist_reg(engine, GEN8_L3SQCREG4);
12608621f407SFrançois Tigeot 	if (ret)
12618621f407SFrançois Tigeot 		return ret;
12628621f407SFrançois Tigeot 
12638621f407SFrançois Tigeot 	return 0;
12648621f407SFrançois Tigeot }
12658621f407SFrançois Tigeot 
12668621f407SFrançois Tigeot int init_workarounds_ring(struct intel_engine_cs *engine)
12678621f407SFrançois Tigeot {
12688621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
12692c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
12702c9916cdSFrançois Tigeot 
12718621f407SFrançois Tigeot 	WARN_ON(engine->id != RCS);
12722c9916cdSFrançois Tigeot 
12732c9916cdSFrançois Tigeot 	dev_priv->workarounds.count = 0;
1274c0e85e96SFrançois Tigeot 	dev_priv->workarounds.hw_whitelist_count[RCS] = 0;
12752c9916cdSFrançois Tigeot 
12762c9916cdSFrançois Tigeot 	if (IS_BROADWELL(dev))
12778621f407SFrançois Tigeot 		return bdw_init_workarounds(engine);
12782c9916cdSFrançois Tigeot 
12792c9916cdSFrançois Tigeot 	if (IS_CHERRYVIEW(dev))
12808621f407SFrançois Tigeot 		return chv_init_workarounds(engine);
12811b13d190SFrançois Tigeot 
1282477eb7f9SFrançois Tigeot 	if (IS_SKYLAKE(dev))
12838621f407SFrançois Tigeot 		return skl_init_workarounds(engine);
128419c468b4SFrançois Tigeot 
128519c468b4SFrançois Tigeot 	if (IS_BROXTON(dev))
12868621f407SFrançois Tigeot 		return bxt_init_workarounds(engine);
12878621f407SFrançois Tigeot 
12888621f407SFrançois Tigeot 	if (IS_KABYLAKE(dev_priv))
12898621f407SFrançois Tigeot 		return kbl_init_workarounds(engine);
1290477eb7f9SFrançois Tigeot 
12911b13d190SFrançois Tigeot 	return 0;
12921b13d190SFrançois Tigeot }
12931b13d190SFrançois Tigeot 
12948621f407SFrançois Tigeot static int init_render_ring(struct intel_engine_cs *engine)
1295e3adcf8fSFrançois Tigeot {
12968621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1297e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
12988621f407SFrançois Tigeot 	int ret = init_ring_common(engine);
129924edb884SFrançois Tigeot 	if (ret)
130024edb884SFrançois Tigeot 		return ret;
1301e3adcf8fSFrançois Tigeot 
1302ba55f2f5SFrançois Tigeot 	/* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */
1303ba55f2f5SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4 && INTEL_INFO(dev)->gen < 7)
1304f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
1305f4e1c372SFrançois Tigeot 
1306f4e1c372SFrançois Tigeot 	/* We need to disable the AsyncFlip performance optimisations in order
1307f4e1c372SFrançois Tigeot 	 * to use MI_WAIT_FOR_EVENT within the CS. It should already be
1308f4e1c372SFrançois Tigeot 	 * programmed to '1' on all products.
13095d0b1887SFrançois Tigeot 	 *
1310a05eeebfSFrançois Tigeot 	 * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
1311f4e1c372SFrançois Tigeot 	 */
1312a05eeebfSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8)
1313f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
1314f4e1c372SFrançois Tigeot 
1315f4e1c372SFrançois Tigeot 	/* Required for the hardware to program scanline values for waiting */
1316ba55f2f5SFrançois Tigeot 	/* WaEnableFlushTlbInvalidationMode:snb */
1317f4e1c372SFrançois Tigeot 	if (INTEL_INFO(dev)->gen == 6)
1318f4e1c372SFrançois Tigeot 		I915_WRITE(GFX_MODE,
1319ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT));
1320f4e1c372SFrançois Tigeot 
1321ba55f2f5SFrançois Tigeot 	/* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */
1322e3adcf8fSFrançois Tigeot 	if (IS_GEN7(dev))
1323e3adcf8fSFrançois Tigeot 		I915_WRITE(GFX_MODE_GEN7,
1324ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
1325f4e1c372SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
1326e3adcf8fSFrançois Tigeot 
1327e3adcf8fSFrançois Tigeot 	if (IS_GEN6(dev)) {
1328e3adcf8fSFrançois Tigeot 		/* From the Sandybridge PRM, volume 1 part 3, page 24:
1329e3adcf8fSFrançois Tigeot 		 * "If this bit is set, STCunit will have LRA as replacement
1330e3adcf8fSFrançois Tigeot 		 *  policy. [...] This bit must be reset.  LRA replacement
1331e3adcf8fSFrançois Tigeot 		 *  policy is not supported."
1332e3adcf8fSFrançois Tigeot 		 */
1333e3adcf8fSFrançois Tigeot 		I915_WRITE(CACHE_MODE_0,
1334f4e1c372SFrançois Tigeot 			   _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
1335e3adcf8fSFrançois Tigeot 	}
1336e3adcf8fSFrançois Tigeot 
1337a05eeebfSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8)
1338f4e1c372SFrançois Tigeot 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
1339f4e1c372SFrançois Tigeot 
13409edbd4a0SFrançois Tigeot 	if (HAS_L3_DPF(dev))
13418621f407SFrançois Tigeot 		I915_WRITE_IMR(engine, ~GT_PARITY_ERROR(dev));
1342e3adcf8fSFrançois Tigeot 
13438621f407SFrançois Tigeot 	return init_workarounds_ring(engine);
1344e3adcf8fSFrançois Tigeot }
1345e3adcf8fSFrançois Tigeot 
13468621f407SFrançois Tigeot static void render_ring_cleanup(struct intel_engine_cs *engine)
1347e3adcf8fSFrançois Tigeot {
13488621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
134924edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
135024edb884SFrançois Tigeot 
135124edb884SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
135224edb884SFrançois Tigeot 		i915_gem_object_ggtt_unpin(dev_priv->semaphore_obj);
135324edb884SFrançois Tigeot 		drm_gem_object_unreference(&dev_priv->semaphore_obj->base);
135424edb884SFrançois Tigeot 		dev_priv->semaphore_obj = NULL;
135524edb884SFrançois Tigeot 	}
1356b5c29a34SFrançois Tigeot 
13578621f407SFrançois Tigeot 	intel_fini_pipe_control(engine);
1358e3adcf8fSFrançois Tigeot }
1359e3adcf8fSFrançois Tigeot 
1360a05eeebfSFrançois Tigeot static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req,
136124edb884SFrançois Tigeot 			   unsigned int num_dwords)
136224edb884SFrançois Tigeot {
136324edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 8
13648621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
136524edb884SFrançois Tigeot 	struct drm_device *dev = signaller->dev;
136624edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
136724edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
13688621f407SFrançois Tigeot 	enum intel_engine_id id;
13698621f407SFrançois Tigeot 	int ret, num_rings;
137024edb884SFrançois Tigeot 
137124edb884SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
137224edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
137324edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
137424edb884SFrançois Tigeot 
1375a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
137624edb884SFrançois Tigeot 	if (ret)
137724edb884SFrançois Tigeot 		return ret;
137824edb884SFrançois Tigeot 
13798621f407SFrançois Tigeot 	for_each_engine_id(waiter, dev_priv, id) {
13802c9916cdSFrançois Tigeot 		u32 seqno;
13818621f407SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
138224edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
138324edb884SFrançois Tigeot 			continue;
138424edb884SFrançois Tigeot 
1385a05eeebfSFrançois Tigeot 		seqno = i915_gem_request_get_seqno(signaller_req);
138624edb884SFrançois Tigeot 		intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
138724edb884SFrançois Tigeot 		intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
138824edb884SFrançois Tigeot 					   PIPE_CONTROL_QW_WRITE |
138924edb884SFrançois Tigeot 					   PIPE_CONTROL_FLUSH_ENABLE);
139024edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset));
139124edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
13922c9916cdSFrançois Tigeot 		intel_ring_emit(signaller, seqno);
139324edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
139424edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
13958621f407SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->hw_id));
139624edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
139724edb884SFrançois Tigeot 	}
139824edb884SFrançois Tigeot 
139924edb884SFrançois Tigeot 	return 0;
140024edb884SFrançois Tigeot }
140124edb884SFrançois Tigeot 
1402a05eeebfSFrançois Tigeot static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req,
140324edb884SFrançois Tigeot 			   unsigned int num_dwords)
140424edb884SFrançois Tigeot {
140524edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 6
14068621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
140724edb884SFrançois Tigeot 	struct drm_device *dev = signaller->dev;
140824edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
140924edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
14108621f407SFrançois Tigeot 	enum intel_engine_id id;
14118621f407SFrançois Tigeot 	int ret, num_rings;
141224edb884SFrançois Tigeot 
141324edb884SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
141424edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
141524edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
141624edb884SFrançois Tigeot 
1417a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
141824edb884SFrançois Tigeot 	if (ret)
141924edb884SFrançois Tigeot 		return ret;
142024edb884SFrançois Tigeot 
14218621f407SFrançois Tigeot 	for_each_engine_id(waiter, dev_priv, id) {
14222c9916cdSFrançois Tigeot 		u32 seqno;
14238621f407SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[id];
142424edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
142524edb884SFrançois Tigeot 			continue;
142624edb884SFrançois Tigeot 
1427a05eeebfSFrançois Tigeot 		seqno = i915_gem_request_get_seqno(signaller_req);
142824edb884SFrançois Tigeot 		intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
142924edb884SFrançois Tigeot 					   MI_FLUSH_DW_OP_STOREDW);
143024edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
143124edb884SFrançois Tigeot 					   MI_FLUSH_DW_USE_GTT);
143224edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
14332c9916cdSFrançois Tigeot 		intel_ring_emit(signaller, seqno);
143424edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
14358621f407SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->hw_id));
143624edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
143724edb884SFrançois Tigeot 	}
143824edb884SFrançois Tigeot 
143924edb884SFrançois Tigeot 	return 0;
144024edb884SFrançois Tigeot }
144124edb884SFrançois Tigeot 
1442a05eeebfSFrançois Tigeot static int gen6_signal(struct drm_i915_gem_request *signaller_req,
1443ba55f2f5SFrançois Tigeot 		       unsigned int num_dwords)
1444e3adcf8fSFrançois Tigeot {
14458621f407SFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->engine;
1446ba55f2f5SFrançois Tigeot 	struct drm_device *dev = signaller->dev;
1447ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1448ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *useless;
14498621f407SFrançois Tigeot 	enum intel_engine_id id;
14508621f407SFrançois Tigeot 	int ret, num_rings;
1451ba55f2f5SFrançois Tigeot 
145224edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 3
145324edb884SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
145424edb884SFrançois Tigeot 	num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2);
145524edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
1456ba55f2f5SFrançois Tigeot 
1457a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
1458ba55f2f5SFrançois Tigeot 	if (ret)
1459ba55f2f5SFrançois Tigeot 		return ret;
1460ba55f2f5SFrançois Tigeot 
14618621f407SFrançois Tigeot 	for_each_engine_id(useless, dev_priv, id) {
14628621f407SFrançois Tigeot 		i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[id];
1463aee94f86SFrançois Tigeot 
1464aee94f86SFrançois Tigeot 		if (i915_mmio_reg_valid(mbox_reg)) {
1465a05eeebfSFrançois Tigeot 			u32 seqno = i915_gem_request_get_seqno(signaller_req);
1466aee94f86SFrançois Tigeot 
1467ba55f2f5SFrançois Tigeot 			intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
1468aee94f86SFrançois Tigeot 			intel_ring_emit_reg(signaller, mbox_reg);
14692c9916cdSFrançois Tigeot 			intel_ring_emit(signaller, seqno);
1470ba55f2f5SFrançois Tigeot 		}
1471ba55f2f5SFrançois Tigeot 	}
1472ba55f2f5SFrançois Tigeot 
147324edb884SFrançois Tigeot 	/* If num_dwords was rounded, make sure the tail pointer is correct */
147424edb884SFrançois Tigeot 	if (num_rings % 2 == 0)
147524edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_NOOP);
147624edb884SFrançois Tigeot 
1477ba55f2f5SFrançois Tigeot 	return 0;
1478e3adcf8fSFrançois Tigeot }
1479e3adcf8fSFrançois Tigeot 
1480e3adcf8fSFrançois Tigeot /**
1481e3adcf8fSFrançois Tigeot  * gen6_add_request - Update the semaphore mailbox registers
1482e3adcf8fSFrançois Tigeot  *
1483a05eeebfSFrançois Tigeot  * @request - request to write to the ring
1484e3adcf8fSFrançois Tigeot  *
1485e3adcf8fSFrançois Tigeot  * Update the mailbox registers in the *other* rings with the current seqno.
1486e3adcf8fSFrançois Tigeot  * This acts like a signal in the canonical semaphore.
1487e3adcf8fSFrançois Tigeot  */
1488e3adcf8fSFrançois Tigeot static int
1489a05eeebfSFrançois Tigeot gen6_add_request(struct drm_i915_gem_request *req)
1490e3adcf8fSFrançois Tigeot {
14918621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1492ba55f2f5SFrançois Tigeot 	int ret;
1493e3adcf8fSFrançois Tigeot 
14948621f407SFrançois Tigeot 	if (engine->semaphore.signal)
14958621f407SFrançois Tigeot 		ret = engine->semaphore.signal(req, 4);
149624edb884SFrançois Tigeot 	else
1497a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 4);
149824edb884SFrançois Tigeot 
14999edbd4a0SFrançois Tigeot 	if (ret)
15009edbd4a0SFrançois Tigeot 		return ret;
15019edbd4a0SFrançois Tigeot 
15028621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
15038621f407SFrançois Tigeot 	intel_ring_emit(engine,
15048621f407SFrançois Tigeot 			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
15058621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
15068621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
15078621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1508e3adcf8fSFrançois Tigeot 
1509e3adcf8fSFrançois Tigeot 	return 0;
1510e3adcf8fSFrançois Tigeot }
1511e3adcf8fSFrançois Tigeot 
1512a2fdbec6SFrançois Tigeot static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev,
1513a2fdbec6SFrançois Tigeot 					      u32 seqno)
1514a2fdbec6SFrançois Tigeot {
1515a2fdbec6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1516a2fdbec6SFrançois Tigeot 	return dev_priv->last_seqno < seqno;
1517a2fdbec6SFrançois Tigeot }
1518a2fdbec6SFrançois Tigeot 
1519e3adcf8fSFrançois Tigeot /**
1520e3adcf8fSFrançois Tigeot  * intel_ring_sync - sync the waiter to the signaller on seqno
1521e3adcf8fSFrançois Tigeot  *
1522e3adcf8fSFrançois Tigeot  * @waiter - ring that is waiting
1523e3adcf8fSFrançois Tigeot  * @signaller - ring which has, or will signal
1524e3adcf8fSFrançois Tigeot  * @seqno - seqno which the waiter will block on
1525e3adcf8fSFrançois Tigeot  */
152624edb884SFrançois Tigeot 
152724edb884SFrançois Tigeot static int
1528a05eeebfSFrançois Tigeot gen8_ring_sync(struct drm_i915_gem_request *waiter_req,
152924edb884SFrançois Tigeot 	       struct intel_engine_cs *signaller,
153024edb884SFrançois Tigeot 	       u32 seqno)
153124edb884SFrançois Tigeot {
15328621f407SFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->engine;
153324edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = waiter->dev->dev_private;
153424edb884SFrançois Tigeot 	int ret;
153524edb884SFrançois Tigeot 
1536a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
153724edb884SFrançois Tigeot 	if (ret)
153824edb884SFrançois Tigeot 		return ret;
153924edb884SFrançois Tigeot 
154024edb884SFrançois Tigeot 	intel_ring_emit(waiter, MI_SEMAPHORE_WAIT |
154124edb884SFrançois Tigeot 				MI_SEMAPHORE_GLOBAL_GTT |
154224edb884SFrançois Tigeot 				MI_SEMAPHORE_POLL |
154324edb884SFrançois Tigeot 				MI_SEMAPHORE_SAD_GTE_SDD);
154424edb884SFrançois Tigeot 	intel_ring_emit(waiter, seqno);
154524edb884SFrançois Tigeot 	intel_ring_emit(waiter,
154624edb884SFrançois Tigeot 			lower_32_bits(GEN8_WAIT_OFFSET(waiter, signaller->id)));
154724edb884SFrançois Tigeot 	intel_ring_emit(waiter,
154824edb884SFrançois Tigeot 			upper_32_bits(GEN8_WAIT_OFFSET(waiter, signaller->id)));
154924edb884SFrançois Tigeot 	intel_ring_advance(waiter);
155024edb884SFrançois Tigeot 	return 0;
155124edb884SFrançois Tigeot }
155224edb884SFrançois Tigeot 
1553e3adcf8fSFrançois Tigeot static int
1554a05eeebfSFrançois Tigeot gen6_ring_sync(struct drm_i915_gem_request *waiter_req,
1555ba55f2f5SFrançois Tigeot 	       struct intel_engine_cs *signaller,
1556e3adcf8fSFrançois Tigeot 	       u32 seqno)
1557e3adcf8fSFrançois Tigeot {
15588621f407SFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->engine;
1559e3adcf8fSFrançois Tigeot 	u32 dw1 = MI_SEMAPHORE_MBOX |
1560e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_COMPARE |
1561e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_REGISTER;
1562ba55f2f5SFrançois Tigeot 	u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id];
1563ba55f2f5SFrançois Tigeot 	int ret;
1564e3adcf8fSFrançois Tigeot 
1565686a02f1SFrançois Tigeot 	/* Throughout all of the GEM code, seqno passed implies our current
1566686a02f1SFrançois Tigeot 	 * seqno is >= the last seqno executed. However for hardware the
1567686a02f1SFrançois Tigeot 	 * comparison is strictly greater than.
1568686a02f1SFrançois Tigeot 	 */
1569686a02f1SFrançois Tigeot 	seqno -= 1;
1570686a02f1SFrançois Tigeot 
1571ba55f2f5SFrançois Tigeot 	WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
1572686a02f1SFrançois Tigeot 
1573a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
1574e3adcf8fSFrançois Tigeot 	if (ret)
1575e3adcf8fSFrançois Tigeot 		return ret;
1576e3adcf8fSFrançois Tigeot 
1577a2fdbec6SFrançois Tigeot 	/* If seqno wrap happened, omit the wait with no-ops */
1578a2fdbec6SFrançois Tigeot 	if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) {
1579ba55f2f5SFrançois Tigeot 		intel_ring_emit(waiter, dw1 | wait_mbox);
1580e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, seqno);
1581e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, 0);
1582e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1583a2fdbec6SFrançois Tigeot 	} else {
1584a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1585a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1586a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1587a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1588a2fdbec6SFrançois Tigeot 	}
1589e3adcf8fSFrançois Tigeot 	intel_ring_advance(waiter);
1590e3adcf8fSFrançois Tigeot 
1591e3adcf8fSFrançois Tigeot 	return 0;
1592e3adcf8fSFrançois Tigeot }
1593e3adcf8fSFrançois Tigeot 
1594e3adcf8fSFrançois Tigeot #define PIPE_CONTROL_FLUSH(ring__, addr__)					\
1595e3adcf8fSFrançois Tigeot do {									\
1596e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |		\
1597e3adcf8fSFrançois Tigeot 		 PIPE_CONTROL_DEPTH_STALL);				\
1598e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT);			\
1599e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, 0);							\
1600e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, 0);							\
1601e3adcf8fSFrançois Tigeot } while (0)
1602e3adcf8fSFrançois Tigeot 
1603e3adcf8fSFrançois Tigeot static int
1604a05eeebfSFrançois Tigeot pc_render_add_request(struct drm_i915_gem_request *req)
1605e3adcf8fSFrançois Tigeot {
16068621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
16078621f407SFrançois Tigeot 	u32 scratch_addr = engine->scratch.gtt_offset + 2 * CACHELINE_BYTES;
1608e3adcf8fSFrançois Tigeot 	int ret;
1609e3adcf8fSFrançois Tigeot 
1610e3adcf8fSFrançois Tigeot 	/* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently
1611e3adcf8fSFrançois Tigeot 	 * incoherent with writes to memory, i.e. completely fubar,
1612e3adcf8fSFrançois Tigeot 	 * so we need to use PIPE_NOTIFY instead.
1613e3adcf8fSFrançois Tigeot 	 *
1614e3adcf8fSFrançois Tigeot 	 * However, we also need to workaround the qword write
1615e3adcf8fSFrançois Tigeot 	 * incoherence by flushing the 6 PIPE_NOTIFY buffers out to
1616e3adcf8fSFrançois Tigeot 	 * memory before requesting an interrupt.
1617e3adcf8fSFrançois Tigeot 	 */
1618a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 32);
1619e3adcf8fSFrançois Tigeot 	if (ret)
1620e3adcf8fSFrançois Tigeot 		return ret;
1621e3adcf8fSFrançois Tigeot 
16228621f407SFrançois Tigeot 	intel_ring_emit(engine,
16238621f407SFrançois Tigeot 			GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
1624e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_WRITE_FLUSH |
1625e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
16268621f407SFrançois Tigeot 	intel_ring_emit(engine,
16278621f407SFrançois Tigeot 			engine->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
16288621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
16298621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
16308621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1631ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
16328621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1633ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16348621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1635ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16368621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1637ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16388621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1639ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
16408621f407SFrançois Tigeot 	PIPE_CONTROL_FLUSH(engine, scratch_addr);
1641b5c29a34SFrançois Tigeot 
16428621f407SFrançois Tigeot 	intel_ring_emit(engine,
16438621f407SFrançois Tigeot 			GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
1644e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_WRITE_FLUSH |
1645e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
1646e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_NOTIFY);
16478621f407SFrançois Tigeot 	intel_ring_emit(engine,
16488621f407SFrançois Tigeot 			engine->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
16498621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
16508621f407SFrançois Tigeot 	intel_ring_emit(engine, 0);
16518621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1652e3adcf8fSFrançois Tigeot 
1653e3adcf8fSFrançois Tigeot 	return 0;
1654e3adcf8fSFrançois Tigeot }
1655e3adcf8fSFrançois Tigeot 
16568621f407SFrançois Tigeot static void
16578621f407SFrançois Tigeot gen6_seqno_barrier(struct intel_engine_cs *engine)
1658e3adcf8fSFrançois Tigeot {
16598621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
16608621f407SFrançois Tigeot 
1661e3adcf8fSFrançois Tigeot 	/* Workaround to force correct ordering between irq and seqno writes on
1662e3adcf8fSFrançois Tigeot 	 * ivb (and maybe also on snb) by reading from a CS register (like
16638621f407SFrançois Tigeot 	 * ACTHD) before reading the status page.
16648621f407SFrançois Tigeot 	 *
16658621f407SFrançois Tigeot 	 * Note that this effectively stalls the read by the time it takes to
16668621f407SFrançois Tigeot 	 * do a memory transaction, which more or less ensures that the write
16678621f407SFrançois Tigeot 	 * from the GPU has sufficient time to invalidate the CPU cacheline.
16688621f407SFrançois Tigeot 	 * Alternatively we could delay the interrupt from the CS ring to give
16698621f407SFrançois Tigeot 	 * the write time to land, but that would incur a delay after every
16708621f407SFrançois Tigeot 	 * batch i.e. much more frequent than a delay when waiting for the
16718621f407SFrançois Tigeot 	 * interrupt (with the same net latency).
16728621f407SFrançois Tigeot 	 *
16738621f407SFrançois Tigeot 	 * Also note that to prevent whole machine hangs on gen7, we have to
16748621f407SFrançois Tigeot 	 * take the spinlock to guard against concurrent cacheline access.
16758621f407SFrançois Tigeot 	 */
16768621f407SFrançois Tigeot 	spin_lock_irq(&dev_priv->uncore.lock);
16778621f407SFrançois Tigeot 	POSTING_READ_FW(RING_ACTHD(engine->mmio_base));
16788621f407SFrançois Tigeot 	spin_unlock_irq(&dev_priv->uncore.lock);
1679e3adcf8fSFrançois Tigeot }
1680e3adcf8fSFrançois Tigeot 
1681b030f26bSFrançois Tigeot static u32
16828621f407SFrançois Tigeot ring_get_seqno(struct intel_engine_cs *engine)
1683e3adcf8fSFrançois Tigeot {
16848621f407SFrançois Tigeot 	return intel_read_status_page(engine, I915_GEM_HWS_INDEX);
1685e3adcf8fSFrançois Tigeot }
1686e3adcf8fSFrançois Tigeot 
1687a2fdbec6SFrançois Tigeot static void
16888621f407SFrançois Tigeot ring_set_seqno(struct intel_engine_cs *engine, u32 seqno)
1689a2fdbec6SFrançois Tigeot {
16908621f407SFrançois Tigeot 	intel_write_status_page(engine, I915_GEM_HWS_INDEX, seqno);
1691a2fdbec6SFrançois Tigeot }
1692a2fdbec6SFrançois Tigeot 
1693b030f26bSFrançois Tigeot static u32
16948621f407SFrançois Tigeot pc_render_get_seqno(struct intel_engine_cs *engine)
1695e3adcf8fSFrançois Tigeot {
16968621f407SFrançois Tigeot 	return engine->scratch.cpu_page[0];
1697e3adcf8fSFrançois Tigeot }
1698e3adcf8fSFrançois Tigeot 
1699a2fdbec6SFrançois Tigeot static void
17008621f407SFrançois Tigeot pc_render_set_seqno(struct intel_engine_cs *engine, u32 seqno)
1701a2fdbec6SFrançois Tigeot {
17028621f407SFrançois Tigeot 	engine->scratch.cpu_page[0] = seqno;
1703a2fdbec6SFrançois Tigeot }
1704a2fdbec6SFrançois Tigeot 
1705e3adcf8fSFrançois Tigeot static bool
17068621f407SFrançois Tigeot gen5_ring_get_irq(struct intel_engine_cs *engine)
1707e3adcf8fSFrançois Tigeot {
17088621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1709ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17105e269720SFrançois Tigeot 	unsigned long flags;
1711e3adcf8fSFrançois Tigeot 
17122c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
1713e3adcf8fSFrançois Tigeot 		return false;
1714e3adcf8fSFrançois Tigeot 
17155e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17168621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0)
17178621f407SFrançois Tigeot 		gen5_enable_gt_irq(dev_priv, engine->irq_enable_mask);
17185e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1719e3adcf8fSFrançois Tigeot 
1720e3adcf8fSFrançois Tigeot 	return true;
1721e3adcf8fSFrançois Tigeot }
1722e3adcf8fSFrançois Tigeot 
1723e3adcf8fSFrançois Tigeot static void
17248621f407SFrançois Tigeot gen5_ring_put_irq(struct intel_engine_cs *engine)
1725e3adcf8fSFrançois Tigeot {
17268621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1727ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17285e269720SFrançois Tigeot 	unsigned long flags;
1729e3adcf8fSFrançois Tigeot 
17305e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17318621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0)
17328621f407SFrançois Tigeot 		gen5_disable_gt_irq(dev_priv, engine->irq_enable_mask);
17335e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1734686a02f1SFrançois Tigeot }
1735686a02f1SFrançois Tigeot 
1736686a02f1SFrançois Tigeot static bool
17378621f407SFrançois Tigeot i9xx_ring_get_irq(struct intel_engine_cs *engine)
1738686a02f1SFrançois Tigeot {
17398621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1740ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17415e269720SFrançois Tigeot 	unsigned long flags;
1742686a02f1SFrançois Tigeot 
17432c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
1744686a02f1SFrançois Tigeot 		return false;
1745686a02f1SFrançois Tigeot 
17465e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17478621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
17488621f407SFrançois Tigeot 		dev_priv->irq_mask &= ~engine->irq_enable_mask;
1749686a02f1SFrançois Tigeot 		I915_WRITE(IMR, dev_priv->irq_mask);
1750686a02f1SFrançois Tigeot 		POSTING_READ(IMR);
1751686a02f1SFrançois Tigeot 	}
17525e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1753686a02f1SFrançois Tigeot 
1754686a02f1SFrançois Tigeot 	return true;
1755686a02f1SFrançois Tigeot }
1756686a02f1SFrançois Tigeot 
1757686a02f1SFrançois Tigeot static void
17588621f407SFrançois Tigeot i9xx_ring_put_irq(struct intel_engine_cs *engine)
1759686a02f1SFrançois Tigeot {
17608621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1761ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17625e269720SFrançois Tigeot 	unsigned long flags;
1763686a02f1SFrançois Tigeot 
17645e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17658621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
17668621f407SFrançois Tigeot 		dev_priv->irq_mask |= engine->irq_enable_mask;
1767686a02f1SFrançois Tigeot 		I915_WRITE(IMR, dev_priv->irq_mask);
1768686a02f1SFrançois Tigeot 		POSTING_READ(IMR);
1769686a02f1SFrançois Tigeot 	}
17705e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1771686a02f1SFrançois Tigeot }
1772686a02f1SFrançois Tigeot 
1773686a02f1SFrançois Tigeot static bool
17748621f407SFrançois Tigeot i8xx_ring_get_irq(struct intel_engine_cs *engine)
1775686a02f1SFrançois Tigeot {
17768621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1777ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17785e269720SFrançois Tigeot 	unsigned long flags;
1779686a02f1SFrançois Tigeot 
17802c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
1781686a02f1SFrançois Tigeot 		return false;
1782686a02f1SFrançois Tigeot 
17835e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17848621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
17858621f407SFrançois Tigeot 		dev_priv->irq_mask &= ~engine->irq_enable_mask;
1786686a02f1SFrançois Tigeot 		I915_WRITE16(IMR, dev_priv->irq_mask);
1787686a02f1SFrançois Tigeot 		POSTING_READ16(IMR);
1788686a02f1SFrançois Tigeot 	}
17895e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1790686a02f1SFrançois Tigeot 
1791686a02f1SFrançois Tigeot 	return true;
1792686a02f1SFrançois Tigeot }
1793686a02f1SFrançois Tigeot 
1794686a02f1SFrançois Tigeot static void
17958621f407SFrançois Tigeot i8xx_ring_put_irq(struct intel_engine_cs *engine)
1796686a02f1SFrançois Tigeot {
17978621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1798ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17995e269720SFrançois Tigeot 	unsigned long flags;
1800686a02f1SFrançois Tigeot 
18015e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18028621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
18038621f407SFrançois Tigeot 		dev_priv->irq_mask |= engine->irq_enable_mask;
1804686a02f1SFrançois Tigeot 		I915_WRITE16(IMR, dev_priv->irq_mask);
1805686a02f1SFrançois Tigeot 		POSTING_READ16(IMR);
1806e3adcf8fSFrançois Tigeot 	}
18075e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1808e3adcf8fSFrançois Tigeot }
1809e3adcf8fSFrançois Tigeot 
1810e3adcf8fSFrançois Tigeot static int
1811a05eeebfSFrançois Tigeot bsd_ring_flush(struct drm_i915_gem_request *req,
1812b5c29a34SFrançois Tigeot 	       u32     invalidate_domains,
1813b5c29a34SFrançois Tigeot 	       u32     flush_domains)
1814e3adcf8fSFrançois Tigeot {
18158621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1816e3adcf8fSFrançois Tigeot 	int ret;
1817e3adcf8fSFrançois Tigeot 
1818a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1819e3adcf8fSFrançois Tigeot 	if (ret)
1820e3adcf8fSFrançois Tigeot 		return ret;
1821e3adcf8fSFrançois Tigeot 
18228621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_FLUSH);
18238621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
18248621f407SFrançois Tigeot 	intel_ring_advance(engine);
1825e3adcf8fSFrançois Tigeot 	return 0;
1826e3adcf8fSFrançois Tigeot }
1827e3adcf8fSFrançois Tigeot 
1828e3adcf8fSFrançois Tigeot static int
1829a05eeebfSFrançois Tigeot i9xx_add_request(struct drm_i915_gem_request *req)
1830e3adcf8fSFrançois Tigeot {
18318621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1832e3adcf8fSFrançois Tigeot 	int ret;
1833e3adcf8fSFrançois Tigeot 
1834a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
1835e3adcf8fSFrançois Tigeot 	if (ret)
1836e3adcf8fSFrançois Tigeot 		return ret;
1837e3adcf8fSFrançois Tigeot 
18388621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_STORE_DWORD_INDEX);
18398621f407SFrançois Tigeot 	intel_ring_emit(engine,
18408621f407SFrançois Tigeot 			I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
18418621f407SFrançois Tigeot 	intel_ring_emit(engine, i915_gem_request_get_seqno(req));
18428621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_USER_INTERRUPT);
18438621f407SFrançois Tigeot 	__intel_ring_advance(engine);
1844e3adcf8fSFrançois Tigeot 
1845e3adcf8fSFrançois Tigeot 	return 0;
1846e3adcf8fSFrançois Tigeot }
1847e3adcf8fSFrançois Tigeot 
1848e3adcf8fSFrançois Tigeot static bool
18498621f407SFrançois Tigeot gen6_ring_get_irq(struct intel_engine_cs *engine)
1850e3adcf8fSFrançois Tigeot {
18518621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1852ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
18535e269720SFrançois Tigeot 	unsigned long flags;
1854e3adcf8fSFrançois Tigeot 
18552c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
1856e3adcf8fSFrançois Tigeot 		return false;
1857e3adcf8fSFrançois Tigeot 
18585e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18598621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
18608621f407SFrançois Tigeot 		if (HAS_L3_DPF(dev) && engine->id == RCS)
18618621f407SFrançois Tigeot 			I915_WRITE_IMR(engine,
18628621f407SFrançois Tigeot 				       ~(engine->irq_enable_mask |
18639edbd4a0SFrançois Tigeot 					 GT_PARITY_ERROR(dev)));
1864686a02f1SFrançois Tigeot 		else
18658621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
18668621f407SFrançois Tigeot 		gen5_enable_gt_irq(dev_priv, engine->irq_enable_mask);
1867e3adcf8fSFrançois Tigeot 	}
18685e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1869e3adcf8fSFrançois Tigeot 
1870e3adcf8fSFrançois Tigeot 	return true;
1871e3adcf8fSFrançois Tigeot }
1872e3adcf8fSFrançois Tigeot 
1873e3adcf8fSFrançois Tigeot static void
18748621f407SFrançois Tigeot gen6_ring_put_irq(struct intel_engine_cs *engine)
1875e3adcf8fSFrançois Tigeot {
18768621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
1877ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
18785e269720SFrançois Tigeot 	unsigned long flags;
1879e3adcf8fSFrançois Tigeot 
18805e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18818621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
18828621f407SFrançois Tigeot 		if (HAS_L3_DPF(dev) && engine->id == RCS)
18838621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~GT_PARITY_ERROR(dev));
1884686a02f1SFrançois Tigeot 		else
18858621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~0);
18868621f407SFrançois Tigeot 		gen5_disable_gt_irq(dev_priv, engine->irq_enable_mask);
1887e3adcf8fSFrançois Tigeot 	}
18885e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1889e3adcf8fSFrançois Tigeot }
1890e3adcf8fSFrançois Tigeot 
18915d0b1887SFrançois Tigeot static bool
18928621f407SFrançois Tigeot hsw_vebox_get_irq(struct intel_engine_cs *engine)
18935d0b1887SFrançois Tigeot {
18948621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
18955d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
18965e269720SFrançois Tigeot 	unsigned long flags;
18975d0b1887SFrançois Tigeot 
18982c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
18995d0b1887SFrançois Tigeot 		return false;
19005d0b1887SFrançois Tigeot 
19015e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19028621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
19038621f407SFrançois Tigeot 		I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
19048621f407SFrançois Tigeot 		gen6_enable_pm_irq(dev_priv, engine->irq_enable_mask);
19055d0b1887SFrançois Tigeot 	}
19065e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19075d0b1887SFrançois Tigeot 
19085d0b1887SFrançois Tigeot 	return true;
19095d0b1887SFrançois Tigeot }
19105d0b1887SFrançois Tigeot 
19115d0b1887SFrançois Tigeot static void
19128621f407SFrançois Tigeot hsw_vebox_put_irq(struct intel_engine_cs *engine)
19135d0b1887SFrançois Tigeot {
19148621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
19155d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
19165e269720SFrançois Tigeot 	unsigned long flags;
19175d0b1887SFrançois Tigeot 
19185e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19198621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
19208621f407SFrançois Tigeot 		I915_WRITE_IMR(engine, ~0);
19218621f407SFrançois Tigeot 		gen6_disable_pm_irq(dev_priv, engine->irq_enable_mask);
19225d0b1887SFrançois Tigeot 	}
19235e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19249edbd4a0SFrançois Tigeot }
19259edbd4a0SFrançois Tigeot 
19269edbd4a0SFrançois Tigeot static bool
19278621f407SFrançois Tigeot gen8_ring_get_irq(struct intel_engine_cs *engine)
19289edbd4a0SFrançois Tigeot {
19298621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
19309edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
19315e269720SFrançois Tigeot 	unsigned long flags;
19329edbd4a0SFrançois Tigeot 
19332c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
19349edbd4a0SFrançois Tigeot 		return false;
19359edbd4a0SFrançois Tigeot 
19365e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19378621f407SFrançois Tigeot 	if (engine->irq_refcount++ == 0) {
19388621f407SFrançois Tigeot 		if (HAS_L3_DPF(dev) && engine->id == RCS) {
19398621f407SFrançois Tigeot 			I915_WRITE_IMR(engine,
19408621f407SFrançois Tigeot 				       ~(engine->irq_enable_mask |
19419edbd4a0SFrançois Tigeot 					 GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
19429edbd4a0SFrançois Tigeot 		} else {
19438621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~engine->irq_enable_mask);
19449edbd4a0SFrançois Tigeot 		}
19458621f407SFrançois Tigeot 		POSTING_READ(RING_IMR(engine->mmio_base));
19469edbd4a0SFrançois Tigeot 	}
19475e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19489edbd4a0SFrançois Tigeot 
19499edbd4a0SFrançois Tigeot 	return true;
19509edbd4a0SFrançois Tigeot }
19519edbd4a0SFrançois Tigeot 
19529edbd4a0SFrançois Tigeot static void
19538621f407SFrançois Tigeot gen8_ring_put_irq(struct intel_engine_cs *engine)
19549edbd4a0SFrançois Tigeot {
19558621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
19569edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
19575e269720SFrançois Tigeot 	unsigned long flags;
19589edbd4a0SFrançois Tigeot 
19595e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
19608621f407SFrançois Tigeot 	if (--engine->irq_refcount == 0) {
19618621f407SFrançois Tigeot 		if (HAS_L3_DPF(dev) && engine->id == RCS) {
19628621f407SFrançois Tigeot 			I915_WRITE_IMR(engine,
19639edbd4a0SFrançois Tigeot 				       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
19649edbd4a0SFrançois Tigeot 		} else {
19658621f407SFrançois Tigeot 			I915_WRITE_IMR(engine, ~0);
19669edbd4a0SFrançois Tigeot 		}
19678621f407SFrançois Tigeot 		POSTING_READ(RING_IMR(engine->mmio_base));
19689edbd4a0SFrançois Tigeot 	}
19695e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
19705d0b1887SFrançois Tigeot }
19715d0b1887SFrançois Tigeot 
1972e3adcf8fSFrançois Tigeot static int
1973a05eeebfSFrançois Tigeot i965_dispatch_execbuffer(struct drm_i915_gem_request *req,
1974ba55f2f5SFrançois Tigeot 			 u64 offset, u32 length,
1975477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1976e3adcf8fSFrançois Tigeot {
19778621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
1978e3adcf8fSFrançois Tigeot 	int ret;
1979e3adcf8fSFrançois Tigeot 
1980a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1981e3adcf8fSFrançois Tigeot 	if (ret)
1982e3adcf8fSFrançois Tigeot 		return ret;
1983e3adcf8fSFrançois Tigeot 
19848621f407SFrançois Tigeot 	intel_ring_emit(engine,
1985686a02f1SFrançois Tigeot 			MI_BATCH_BUFFER_START |
1986b5c29a34SFrançois Tigeot 			MI_BATCH_GTT |
1987477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
1988477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
19898621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
19908621f407SFrançois Tigeot 	intel_ring_advance(engine);
1991e3adcf8fSFrançois Tigeot 
1992e3adcf8fSFrançois Tigeot 	return 0;
1993e3adcf8fSFrançois Tigeot }
1994e3adcf8fSFrançois Tigeot 
1995b5c29a34SFrançois Tigeot /* Just userspace ABI convention to limit the wa batch bo to a resonable size */
1996b5c29a34SFrançois Tigeot #define I830_BATCH_LIMIT (256*1024)
199724edb884SFrançois Tigeot #define I830_TLB_ENTRIES (2)
199824edb884SFrançois Tigeot #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
1999e3adcf8fSFrançois Tigeot static int
2000a05eeebfSFrançois Tigeot i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
2001ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
2002477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
2003e3adcf8fSFrançois Tigeot {
20048621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
20058621f407SFrançois Tigeot 	u32 cs_offset = engine->scratch.gtt_offset;
2006e3adcf8fSFrançois Tigeot 	int ret;
2007e3adcf8fSFrançois Tigeot 
2008a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
200924edb884SFrançois Tigeot 	if (ret)
201024edb884SFrançois Tigeot 		return ret;
201124edb884SFrançois Tigeot 
201224edb884SFrançois Tigeot 	/* Evict the invalid PTE TLBs */
20138621f407SFrançois Tigeot 	intel_ring_emit(engine, COLOR_BLT_CMD | BLT_WRITE_RGBA);
20148621f407SFrançois Tigeot 	intel_ring_emit(engine, BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | 4096);
20158621f407SFrançois Tigeot 	intel_ring_emit(engine, I830_TLB_ENTRIES << 16 | 4); /* load each page */
20168621f407SFrançois Tigeot 	intel_ring_emit(engine, cs_offset);
20178621f407SFrançois Tigeot 	intel_ring_emit(engine, 0xdeadbeef);
20188621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
20198621f407SFrançois Tigeot 	intel_ring_advance(engine);
202024edb884SFrançois Tigeot 
2021477eb7f9SFrançois Tigeot 	if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
202224edb884SFrançois Tigeot 		if (len > I830_BATCH_LIMIT)
202324edb884SFrançois Tigeot 			return -ENOSPC;
202424edb884SFrançois Tigeot 
2025a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 6 + 2);
202624edb884SFrançois Tigeot 		if (ret)
202724edb884SFrançois Tigeot 			return ret;
202824edb884SFrançois Tigeot 
202924edb884SFrançois Tigeot 		/* Blit the batch (which has now all relocs applied) to the
203024edb884SFrançois Tigeot 		 * stable batch scratch bo area (so that the CS never
203124edb884SFrançois Tigeot 		 * stumbles over its tlb invalidation bug) ...
203224edb884SFrançois Tigeot 		 */
20338621f407SFrançois Tigeot 		intel_ring_emit(engine, SRC_COPY_BLT_CMD | BLT_WRITE_RGBA);
20348621f407SFrançois Tigeot 		intel_ring_emit(engine,
20358621f407SFrançois Tigeot 				BLT_DEPTH_32 | BLT_ROP_SRC_COPY | 4096);
20368621f407SFrançois Tigeot 		intel_ring_emit(engine, DIV_ROUND_UP(len, 4096) << 16 | 4096);
20378621f407SFrançois Tigeot 		intel_ring_emit(engine, cs_offset);
20388621f407SFrançois Tigeot 		intel_ring_emit(engine, 4096);
20398621f407SFrançois Tigeot 		intel_ring_emit(engine, offset);
204024edb884SFrançois Tigeot 
20418621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_FLUSH);
20428621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
20438621f407SFrançois Tigeot 		intel_ring_advance(engine);
204424edb884SFrançois Tigeot 
204524edb884SFrançois Tigeot 		/* ... and execute it. */
204624edb884SFrançois Tigeot 		offset = cs_offset;
204724edb884SFrançois Tigeot 	}
204824edb884SFrançois Tigeot 
2049c0e85e96SFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2050e3adcf8fSFrançois Tigeot 	if (ret)
2051e3adcf8fSFrançois Tigeot 		return ret;
2052e3adcf8fSFrançois Tigeot 
20538621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
20548621f407SFrançois Tigeot 	intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
2055477eb7f9SFrançois Tigeot 					  0 : MI_BATCH_NON_SECURE));
20568621f407SFrançois Tigeot 	intel_ring_advance(engine);
2057686a02f1SFrançois Tigeot 
2058686a02f1SFrançois Tigeot 	return 0;
2059686a02f1SFrançois Tigeot }
2060686a02f1SFrançois Tigeot 
2061686a02f1SFrançois Tigeot static int
2062a05eeebfSFrançois Tigeot i915_dispatch_execbuffer(struct drm_i915_gem_request *req,
2063ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
2064477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
2065686a02f1SFrançois Tigeot {
20668621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2067686a02f1SFrançois Tigeot 	int ret;
2068686a02f1SFrançois Tigeot 
2069a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2070e3adcf8fSFrançois Tigeot 	if (ret)
2071e3adcf8fSFrançois Tigeot 		return ret;
2072e3adcf8fSFrançois Tigeot 
20738621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
20748621f407SFrançois Tigeot 	intel_ring_emit(engine, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
2075477eb7f9SFrançois Tigeot 					  0 : MI_BATCH_NON_SECURE));
20768621f407SFrançois Tigeot 	intel_ring_advance(engine);
2077e3adcf8fSFrançois Tigeot 
2078e3adcf8fSFrançois Tigeot 	return 0;
2079e3adcf8fSFrançois Tigeot }
2080e3adcf8fSFrançois Tigeot 
20818621f407SFrançois Tigeot static void cleanup_phys_status_page(struct intel_engine_cs *engine)
2082c0e85e96SFrançois Tigeot {
20838621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(engine->dev);
2084c0e85e96SFrançois Tigeot 
2085c0e85e96SFrançois Tigeot 	if (!dev_priv->status_page_dmah)
2086c0e85e96SFrançois Tigeot 		return;
2087c0e85e96SFrançois Tigeot 
20888621f407SFrançois Tigeot 	drm_pci_free(engine->dev, dev_priv->status_page_dmah);
20898621f407SFrançois Tigeot 	engine->status_page.page_addr = NULL;
2090c0e85e96SFrançois Tigeot }
2091c0e85e96SFrançois Tigeot 
20928621f407SFrançois Tigeot static void cleanup_status_page(struct intel_engine_cs *engine)
2093e3adcf8fSFrançois Tigeot {
2094e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
2095e3adcf8fSFrançois Tigeot 
20968621f407SFrançois Tigeot 	obj = engine->status_page.obj;
2097e3adcf8fSFrançois Tigeot 	if (obj == NULL)
2098e3adcf8fSFrançois Tigeot 		return;
2099e3adcf8fSFrançois Tigeot 
21007ec9f8e5SFrançois Tigeot 	kunmap(sg_page(obj->pages->sgl));
2101ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
2102e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
21038621f407SFrançois Tigeot 	engine->status_page.obj = NULL;
2104e3adcf8fSFrançois Tigeot }
2105e3adcf8fSFrançois Tigeot 
21068621f407SFrançois Tigeot static int init_status_page(struct intel_engine_cs *engine)
2107e3adcf8fSFrançois Tigeot {
21088621f407SFrançois Tigeot 	struct drm_i915_gem_object *obj = engine->status_page.obj;
2109ba55f2f5SFrançois Tigeot 
2110c0e85e96SFrançois Tigeot 	if (obj == NULL) {
211124edb884SFrançois Tigeot 		unsigned flags;
2112e3adcf8fSFrançois Tigeot 		int ret;
2113e3adcf8fSFrançois Tigeot 
21148621f407SFrançois Tigeot 		obj = i915_gem_alloc_object(engine->dev, 4096);
2115e3adcf8fSFrançois Tigeot 		if (obj == NULL) {
2116e3adcf8fSFrançois Tigeot 			DRM_ERROR("Failed to allocate status page\n");
2117ba55f2f5SFrançois Tigeot 			return -ENOMEM;
2118e3adcf8fSFrançois Tigeot 		}
2119e3adcf8fSFrançois Tigeot 
2120ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
2121ba55f2f5SFrançois Tigeot 		if (ret)
2122e3adcf8fSFrançois Tigeot 			goto err_unref;
2123ba55f2f5SFrançois Tigeot 
212424edb884SFrançois Tigeot 		flags = 0;
21258621f407SFrançois Tigeot 		if (!HAS_LLC(engine->dev))
212624edb884SFrançois Tigeot 			/* On g33, we cannot place HWS above 256MiB, so
212724edb884SFrançois Tigeot 			 * restrict its pinning to the low mappable arena.
212824edb884SFrançois Tigeot 			 * Though this restriction is not documented for
212924edb884SFrançois Tigeot 			 * gen4, gen5, or byt, they also behave similarly
213024edb884SFrançois Tigeot 			 * and hang if the HWS is placed at the top of the
213124edb884SFrançois Tigeot 			 * GTT. To generalise, it appears that all !llc
213224edb884SFrançois Tigeot 			 * platforms have issues with us placing the HWS
213324edb884SFrançois Tigeot 			 * above the mappable region (even though we never
213424edb884SFrançois Tigeot 			 * actualy map it).
213524edb884SFrançois Tigeot 			 */
213624edb884SFrançois Tigeot 			flags |= PIN_MAPPABLE;
213724edb884SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 4096, flags);
2138ba55f2f5SFrançois Tigeot 		if (ret) {
2139ba55f2f5SFrançois Tigeot err_unref:
2140ba55f2f5SFrançois Tigeot 			drm_gem_object_unreference(&obj->base);
2141ba55f2f5SFrançois Tigeot 			return ret;
2142ba55f2f5SFrançois Tigeot 		}
2143ba55f2f5SFrançois Tigeot 
21448621f407SFrançois Tigeot 		engine->status_page.obj = obj;
2145e3adcf8fSFrançois Tigeot 	}
2146e3adcf8fSFrançois Tigeot 
21478621f407SFrançois Tigeot 	engine->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
21488621f407SFrançois Tigeot 	engine->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
21498621f407SFrançois Tigeot 	memset(engine->status_page.page_addr, 0, PAGE_SIZE);
2150e3adcf8fSFrançois Tigeot 
2151b5c29a34SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
21528621f407SFrançois Tigeot 			engine->name, engine->status_page.gfx_addr);
2153e3adcf8fSFrançois Tigeot 
2154e3adcf8fSFrançois Tigeot 	return 0;
2155e3adcf8fSFrançois Tigeot }
2156e3adcf8fSFrançois Tigeot 
21578621f407SFrançois Tigeot static int init_phys_status_page(struct intel_engine_cs *engine)
2158686a02f1SFrançois Tigeot {
21598621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
2160686a02f1SFrançois Tigeot 
2161686a02f1SFrançois Tigeot 	if (!dev_priv->status_page_dmah) {
2162686a02f1SFrançois Tigeot 		dev_priv->status_page_dmah =
21638621f407SFrançois Tigeot 			drm_pci_alloc(engine->dev, PAGE_SIZE, PAGE_SIZE);
2164686a02f1SFrançois Tigeot 		if (!dev_priv->status_page_dmah)
2165686a02f1SFrançois Tigeot 			return -ENOMEM;
2166686a02f1SFrançois Tigeot 	}
2167686a02f1SFrançois Tigeot 
21688621f407SFrançois Tigeot 	engine->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
21698621f407SFrançois Tigeot 	memset(engine->status_page.page_addr, 0, PAGE_SIZE);
2170686a02f1SFrançois Tigeot 
2171686a02f1SFrançois Tigeot 	return 0;
2172686a02f1SFrançois Tigeot }
2173686a02f1SFrançois Tigeot 
21742c9916cdSFrançois Tigeot void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
21752c9916cdSFrançois Tigeot {
2176aee94f86SFrançois Tigeot 	if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
21778621f407SFrançois Tigeot 		i915_gem_object_unpin_map(ringbuf->obj);
2178aee94f86SFrançois Tigeot 	else
217924409b39SFrançois Tigeot 		iounmap(ringbuf->virtual_start);
21802c9916cdSFrançois Tigeot 	ringbuf->virtual_start = NULL;
2181c0e85e96SFrançois Tigeot 	ringbuf->vma = NULL;
21822c9916cdSFrançois Tigeot 	i915_gem_object_ggtt_unpin(ringbuf->obj);
21832c9916cdSFrançois Tigeot }
21842c9916cdSFrançois Tigeot 
21852c9916cdSFrançois Tigeot int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
21862c9916cdSFrançois Tigeot 				     struct intel_ringbuffer *ringbuf)
21872c9916cdSFrançois Tigeot {
21882c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
21898621f407SFrançois Tigeot 	struct i915_ggtt *ggtt = &dev_priv->ggtt;
21902c9916cdSFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
2191c0e85e96SFrançois Tigeot 	/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
2192c0e85e96SFrançois Tigeot 	unsigned flags = PIN_OFFSET_BIAS | 4096;
21938621f407SFrançois Tigeot 	void *addr;
21942c9916cdSFrançois Tigeot 	int ret;
21952c9916cdSFrançois Tigeot 
2196aee94f86SFrançois Tigeot 	if (HAS_LLC(dev_priv) && !obj->stolen) {
2197c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, flags);
2198aee94f86SFrançois Tigeot 		if (ret)
2199aee94f86SFrançois Tigeot 			return ret;
2200aee94f86SFrançois Tigeot 
2201aee94f86SFrançois Tigeot 		ret = i915_gem_object_set_to_cpu_domain(obj, true);
22028621f407SFrançois Tigeot 		if (ret)
22038621f407SFrançois Tigeot 			goto err_unpin;
2204aee94f86SFrançois Tigeot 
22058621f407SFrançois Tigeot 		addr = i915_gem_object_pin_map(obj);
22068621f407SFrançois Tigeot 		if (IS_ERR(addr)) {
22078621f407SFrançois Tigeot 			ret = PTR_ERR(addr);
22088621f407SFrançois Tigeot 			goto err_unpin;
2209aee94f86SFrançois Tigeot 		}
2210aee94f86SFrançois Tigeot 	} else {
2211c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
2212c0e85e96SFrançois Tigeot 					    flags | PIN_MAPPABLE);
22132c9916cdSFrançois Tigeot 		if (ret)
22142c9916cdSFrançois Tigeot 			return ret;
22152c9916cdSFrançois Tigeot 
22162c9916cdSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(obj, true);
22178621f407SFrançois Tigeot 		if (ret)
22188621f407SFrançois Tigeot 			goto err_unpin;
22192c9916cdSFrançois Tigeot 
2220c0e85e96SFrançois Tigeot 		/* Access through the GTT requires the device to be awake. */
2221c0e85e96SFrançois Tigeot 		assert_rpm_wakelock_held(dev_priv);
2222c0e85e96SFrançois Tigeot 
22238621f407SFrançois Tigeot 		addr = ioremap_wc(ggtt->mappable_base +
22242c9916cdSFrançois Tigeot 				  i915_gem_obj_ggtt_offset(obj), ringbuf->size);
22258621f407SFrançois Tigeot 		if (addr == NULL) {
22268621f407SFrançois Tigeot 			ret = -ENOMEM;
22278621f407SFrançois Tigeot 			goto err_unpin;
22282c9916cdSFrançois Tigeot 		}
2229aee94f86SFrançois Tigeot 	}
22302c9916cdSFrançois Tigeot 
22318621f407SFrançois Tigeot 	ringbuf->virtual_start = addr;
2232c0e85e96SFrançois Tigeot 	ringbuf->vma = i915_gem_obj_to_ggtt(obj);
22332c9916cdSFrançois Tigeot 	return 0;
22348621f407SFrançois Tigeot 
22358621f407SFrançois Tigeot err_unpin:
22368621f407SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
22378621f407SFrançois Tigeot 	return ret;
22382c9916cdSFrançois Tigeot }
22392c9916cdSFrançois Tigeot 
2240352ff8bdSFrançois Tigeot static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
2241e3adcf8fSFrançois Tigeot {
224224edb884SFrançois Tigeot 	drm_gem_object_unreference(&ringbuf->obj->base);
224324edb884SFrançois Tigeot 	ringbuf->obj = NULL;
224424edb884SFrançois Tigeot }
224524edb884SFrançois Tigeot 
2246352ff8bdSFrançois Tigeot static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
224724edb884SFrançois Tigeot 				      struct intel_ringbuffer *ringbuf)
224824edb884SFrançois Tigeot {
2249e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
2250e3adcf8fSFrançois Tigeot 
2251a2fdbec6SFrançois Tigeot 	obj = NULL;
2252a2fdbec6SFrançois Tigeot 	if (!HAS_LLC(dev))
2253ba55f2f5SFrançois Tigeot 		obj = i915_gem_object_create_stolen(dev, ringbuf->size);
2254a2fdbec6SFrançois Tigeot 	if (obj == NULL)
2255ba55f2f5SFrançois Tigeot 		obj = i915_gem_alloc_object(dev, ringbuf->size);
2256ba55f2f5SFrançois Tigeot 	if (obj == NULL)
2257ba55f2f5SFrançois Tigeot 		return -ENOMEM;
2258e3adcf8fSFrançois Tigeot 
225924edb884SFrançois Tigeot 	/* mark ring buffers as read-only from GPU side by default */
226024edb884SFrançois Tigeot 	obj->gt_ro = 1;
226124edb884SFrançois Tigeot 
2262ba55f2f5SFrançois Tigeot 	ringbuf->obj = obj;
2263ba55f2f5SFrançois Tigeot 
22642c9916cdSFrançois Tigeot 	return 0;
2265ba55f2f5SFrançois Tigeot }
2266ba55f2f5SFrançois Tigeot 
2267352ff8bdSFrançois Tigeot struct intel_ringbuffer *
2268352ff8bdSFrançois Tigeot intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
2269352ff8bdSFrançois Tigeot {
2270352ff8bdSFrançois Tigeot 	struct intel_ringbuffer *ring;
2271352ff8bdSFrançois Tigeot 	int ret;
2272352ff8bdSFrançois Tigeot 
2273352ff8bdSFrançois Tigeot 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
2274aee94f86SFrançois Tigeot 	if (ring == NULL) {
2275aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
2276aee94f86SFrançois Tigeot 				 engine->name);
2277352ff8bdSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
2278aee94f86SFrançois Tigeot 	}
2279352ff8bdSFrançois Tigeot 
22808621f407SFrançois Tigeot 	ring->engine = engine;
2281aee94f86SFrançois Tigeot 	list_add(&ring->link, &engine->buffers);
2282352ff8bdSFrançois Tigeot 
2283352ff8bdSFrançois Tigeot 	ring->size = size;
2284352ff8bdSFrançois Tigeot 	/* Workaround an erratum on the i830 which causes a hang if
2285352ff8bdSFrançois Tigeot 	 * the TAIL pointer points to within the last 2 cachelines
2286352ff8bdSFrançois Tigeot 	 * of the buffer.
2287352ff8bdSFrançois Tigeot 	 */
2288352ff8bdSFrançois Tigeot 	ring->effective_size = size;
2289352ff8bdSFrançois Tigeot 	if (IS_I830(engine->dev) || IS_845G(engine->dev))
2290352ff8bdSFrançois Tigeot 		ring->effective_size -= 2 * CACHELINE_BYTES;
2291352ff8bdSFrançois Tigeot 
2292352ff8bdSFrançois Tigeot 	ring->last_retired_head = -1;
2293352ff8bdSFrançois Tigeot 	intel_ring_update_space(ring);
2294352ff8bdSFrançois Tigeot 
2295352ff8bdSFrançois Tigeot 	ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
2296352ff8bdSFrançois Tigeot 	if (ret) {
2297aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
2298352ff8bdSFrançois Tigeot 				 engine->name, ret);
2299aee94f86SFrançois Tigeot 		list_del(&ring->link);
2300352ff8bdSFrançois Tigeot 		kfree(ring);
2301352ff8bdSFrançois Tigeot 		return ERR_PTR(ret);
2302352ff8bdSFrançois Tigeot 	}
2303352ff8bdSFrançois Tigeot 
2304352ff8bdSFrançois Tigeot 	return ring;
2305352ff8bdSFrançois Tigeot }
2306352ff8bdSFrançois Tigeot 
2307352ff8bdSFrançois Tigeot void
2308352ff8bdSFrançois Tigeot intel_ringbuffer_free(struct intel_ringbuffer *ring)
2309352ff8bdSFrançois Tigeot {
2310352ff8bdSFrançois Tigeot 	intel_destroy_ringbuffer_obj(ring);
2311aee94f86SFrançois Tigeot 	list_del(&ring->link);
2312352ff8bdSFrançois Tigeot 	kfree(ring);
2313352ff8bdSFrançois Tigeot }
2314352ff8bdSFrançois Tigeot 
2315ba55f2f5SFrançois Tigeot static int intel_init_ring_buffer(struct drm_device *dev,
23168621f407SFrançois Tigeot 				  struct intel_engine_cs *engine)
2317ba55f2f5SFrançois Tigeot {
23182c9916cdSFrançois Tigeot 	struct intel_ringbuffer *ringbuf;
2319ba55f2f5SFrançois Tigeot 	int ret;
2320ba55f2f5SFrançois Tigeot 
23218621f407SFrançois Tigeot 	WARN_ON(engine->buffer);
23222c9916cdSFrançois Tigeot 
23238621f407SFrançois Tigeot 	engine->dev = dev;
23248621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->active_list);
23258621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->request_list);
23268621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->execlist_queue);
23278621f407SFrançois Tigeot 	INIT_LIST_HEAD(&engine->buffers);
23288621f407SFrançois Tigeot 	i915_gem_batch_pool_init(dev, &engine->batch_pool);
23298621f407SFrançois Tigeot 	memset(engine->semaphore.sync_seqno, 0,
23308621f407SFrançois Tigeot 	       sizeof(engine->semaphore.sync_seqno));
2331ba55f2f5SFrançois Tigeot 
23328621f407SFrançois Tigeot 	init_waitqueue_head(&engine->irq_queue);
2333ba55f2f5SFrançois Tigeot 
23348621f407SFrançois Tigeot 	ringbuf = intel_engine_create_ringbuffer(engine, 32 * PAGE_SIZE);
2335aee94f86SFrançois Tigeot 	if (IS_ERR(ringbuf)) {
2336aee94f86SFrançois Tigeot 		ret = PTR_ERR(ringbuf);
2337aee94f86SFrançois Tigeot 		goto error;
2338aee94f86SFrançois Tigeot 	}
23398621f407SFrançois Tigeot 	engine->buffer = ringbuf;
2340352ff8bdSFrançois Tigeot 
2341ba55f2f5SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev)) {
23428621f407SFrançois Tigeot 		ret = init_status_page(engine);
2343e3adcf8fSFrançois Tigeot 		if (ret)
2344ba55f2f5SFrançois Tigeot 			goto error;
2345ba55f2f5SFrançois Tigeot 	} else {
23468621f407SFrançois Tigeot 		WARN_ON(engine->id != RCS);
23478621f407SFrançois Tigeot 		ret = init_phys_status_page(engine);
2348ba55f2f5SFrançois Tigeot 		if (ret)
2349ba55f2f5SFrançois Tigeot 			goto error;
2350ba55f2f5SFrançois Tigeot 	}
2351ba55f2f5SFrançois Tigeot 
23522c9916cdSFrançois Tigeot 	ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
23532c9916cdSFrançois Tigeot 	if (ret) {
23542c9916cdSFrançois Tigeot 		DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
23558621f407SFrançois Tigeot 				engine->name, ret);
23562c9916cdSFrançois Tigeot 		intel_destroy_ringbuffer_obj(ringbuf);
2357ba55f2f5SFrançois Tigeot 		goto error;
2358ba55f2f5SFrançois Tigeot 	}
2359e3adcf8fSFrançois Tigeot 
23608621f407SFrançois Tigeot 	ret = i915_cmd_parser_init_ring(engine);
2361ba55f2f5SFrançois Tigeot 	if (ret)
2362ba55f2f5SFrançois Tigeot 		goto error;
2363ba55f2f5SFrançois Tigeot 
2364e3adcf8fSFrançois Tigeot 	return 0;
2365e3adcf8fSFrançois Tigeot 
2366ba55f2f5SFrançois Tigeot error:
23678621f407SFrançois Tigeot 	intel_cleanup_engine(engine);
2368e3adcf8fSFrançois Tigeot 	return ret;
2369e3adcf8fSFrançois Tigeot }
2370e3adcf8fSFrançois Tigeot 
23718621f407SFrançois Tigeot void intel_cleanup_engine(struct intel_engine_cs *engine)
2372e3adcf8fSFrançois Tigeot {
23732c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv;
2374e3adcf8fSFrançois Tigeot 
23758621f407SFrançois Tigeot 	if (!intel_engine_initialized(engine))
2376e3adcf8fSFrançois Tigeot 		return;
2377e3adcf8fSFrançois Tigeot 
23788621f407SFrançois Tigeot 	dev_priv = to_i915(engine->dev);
23792c9916cdSFrançois Tigeot 
23808621f407SFrançois Tigeot 	if (engine->buffer) {
23818621f407SFrançois Tigeot 		intel_stop_engine(engine);
23828621f407SFrançois Tigeot 		WARN_ON(!IS_GEN2(engine->dev) && (I915_READ_MODE(engine) & MODE_IDLE) == 0);
2383b030f26bSFrançois Tigeot 
23848621f407SFrançois Tigeot 		intel_unpin_ringbuffer_obj(engine->buffer);
23858621f407SFrançois Tigeot 		intel_ringbuffer_free(engine->buffer);
23868621f407SFrançois Tigeot 		engine->buffer = NULL;
2387aee94f86SFrançois Tigeot 	}
2388e3adcf8fSFrançois Tigeot 
23898621f407SFrançois Tigeot 	if (engine->cleanup)
23908621f407SFrançois Tigeot 		engine->cleanup(engine);
2391e3adcf8fSFrançois Tigeot 
23928621f407SFrançois Tigeot 	if (I915_NEED_GFX_HWS(engine->dev)) {
23938621f407SFrançois Tigeot 		cleanup_status_page(engine);
2394c0e85e96SFrançois Tigeot 	} else {
23958621f407SFrançois Tigeot 		WARN_ON(engine->id != RCS);
23968621f407SFrançois Tigeot 		cleanup_phys_status_page(engine);
2397c0e85e96SFrançois Tigeot 	}
2398ba55f2f5SFrançois Tigeot 
23998621f407SFrançois Tigeot 	i915_cmd_parser_fini_ring(engine);
24008621f407SFrançois Tigeot 	i915_gem_batch_pool_fini(&engine->batch_pool);
24018621f407SFrançois Tigeot 	engine->dev = NULL;
2402e3adcf8fSFrançois Tigeot }
2403e3adcf8fSFrançois Tigeot 
24048621f407SFrançois Tigeot int intel_engine_idle(struct intel_engine_cs *engine)
2405b030f26bSFrançois Tigeot {
24062c9916cdSFrançois Tigeot 	struct drm_i915_gem_request *req;
2407b5c29a34SFrançois Tigeot 
2408b5c29a34SFrançois Tigeot 	/* Wait upon the last request to be completed */
24098621f407SFrançois Tigeot 	if (list_empty(&engine->request_list))
2410b5c29a34SFrançois Tigeot 		return 0;
2411b5c29a34SFrançois Tigeot 
24128621f407SFrançois Tigeot 	req = list_entry(engine->request_list.prev,
2413b5c29a34SFrançois Tigeot 			 struct drm_i915_gem_request,
24142c9916cdSFrançois Tigeot 			 list);
2415b5c29a34SFrançois Tigeot 
241619c468b4SFrançois Tigeot 	/* Make sure we do not trigger any retires */
241719c468b4SFrançois Tigeot 	return __i915_wait_request(req,
24188621f407SFrançois Tigeot 				   req->i915->mm.interruptible,
241919c468b4SFrançois Tigeot 				   NULL, NULL);
2420b5c29a34SFrançois Tigeot }
2421b5c29a34SFrançois Tigeot 
242219c468b4SFrançois Tigeot int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
2423b5c29a34SFrançois Tigeot {
24248621f407SFrançois Tigeot 	request->ringbuf = request->engine->buffer;
24252c9916cdSFrançois Tigeot 	return 0;
24269edbd4a0SFrançois Tigeot }
24279edbd4a0SFrançois Tigeot 
2428a05eeebfSFrançois Tigeot int intel_ring_reserve_space(struct drm_i915_gem_request *request)
2429a2fdbec6SFrançois Tigeot {
2430a05eeebfSFrançois Tigeot 	/*
2431a05eeebfSFrançois Tigeot 	 * The first call merely notes the reserve request and is common for
2432a05eeebfSFrançois Tigeot 	 * all back ends. The subsequent localised _begin() call actually
2433a05eeebfSFrançois Tigeot 	 * ensures that the reservation is available. Without the begin, if
2434a05eeebfSFrançois Tigeot 	 * the request creator immediately submitted the request without
2435a05eeebfSFrançois Tigeot 	 * adding any commands to it then there might not actually be
2436a05eeebfSFrançois Tigeot 	 * sufficient room for the submission commands.
2437a05eeebfSFrançois Tigeot 	 */
2438a05eeebfSFrançois Tigeot 	intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST);
2439a2fdbec6SFrançois Tigeot 
2440a05eeebfSFrançois Tigeot 	return intel_ring_begin(request, 0);
2441a2fdbec6SFrançois Tigeot }
2442a2fdbec6SFrançois Tigeot 
2443a05eeebfSFrançois Tigeot void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size)
2444a05eeebfSFrançois Tigeot {
24458621f407SFrançois Tigeot 	GEM_BUG_ON(ringbuf->reserved_size);
2446a05eeebfSFrançois Tigeot 	ringbuf->reserved_size = size;
2447a05eeebfSFrançois Tigeot }
2448a05eeebfSFrançois Tigeot 
2449a05eeebfSFrançois Tigeot void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf)
2450a05eeebfSFrançois Tigeot {
24518621f407SFrançois Tigeot 	GEM_BUG_ON(!ringbuf->reserved_size);
2452a05eeebfSFrançois Tigeot 	ringbuf->reserved_size   = 0;
2453a05eeebfSFrançois Tigeot }
2454a05eeebfSFrançois Tigeot 
2455a05eeebfSFrançois Tigeot void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf)
2456a05eeebfSFrançois Tigeot {
24578621f407SFrançois Tigeot 	GEM_BUG_ON(!ringbuf->reserved_size);
24588621f407SFrançois Tigeot 	ringbuf->reserved_size   = 0;
2459a05eeebfSFrançois Tigeot }
2460a05eeebfSFrançois Tigeot 
2461a05eeebfSFrançois Tigeot void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf)
2462a05eeebfSFrançois Tigeot {
24638621f407SFrançois Tigeot 	GEM_BUG_ON(ringbuf->reserved_size);
2464a05eeebfSFrançois Tigeot }
2465a05eeebfSFrançois Tigeot 
24668621f407SFrançois Tigeot static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
2467a05eeebfSFrançois Tigeot {
24688621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = req->ringbuf;
24698621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
24708621f407SFrançois Tigeot 	struct drm_i915_gem_request *target;
24718621f407SFrançois Tigeot 
24728621f407SFrançois Tigeot 	intel_ring_update_space(ringbuf);
24738621f407SFrançois Tigeot 	if (ringbuf->space >= bytes)
24748621f407SFrançois Tigeot 		return 0;
24758621f407SFrançois Tigeot 
24768621f407SFrançois Tigeot 	/*
24778621f407SFrançois Tigeot 	 * Space is reserved in the ringbuffer for finalising the request,
24788621f407SFrançois Tigeot 	 * as that cannot be allowed to fail. During request finalisation,
24798621f407SFrançois Tigeot 	 * reserved_space is set to 0 to stop the overallocation and the
24808621f407SFrançois Tigeot 	 * assumption is that then we never need to wait (which has the
24818621f407SFrançois Tigeot 	 * risk of failing with EINTR).
24828621f407SFrançois Tigeot 	 *
24838621f407SFrançois Tigeot 	 * See also i915_gem_request_alloc() and i915_add_request().
24848621f407SFrançois Tigeot 	 */
24858621f407SFrançois Tigeot 	GEM_BUG_ON(!ringbuf->reserved_size);
24868621f407SFrançois Tigeot 
24878621f407SFrançois Tigeot 	list_for_each_entry(target, &engine->request_list, list) {
24888621f407SFrançois Tigeot 		unsigned space;
24898621f407SFrançois Tigeot 
24908621f407SFrançois Tigeot 		/*
24918621f407SFrançois Tigeot 		 * The request queue is per-engine, so can contain requests
24928621f407SFrançois Tigeot 		 * from multiple ringbuffers. Here, we must ignore any that
24938621f407SFrançois Tigeot 		 * aren't from the ringbuffer we're considering.
24948621f407SFrançois Tigeot 		 */
24958621f407SFrançois Tigeot 		if (target->ringbuf != ringbuf)
24968621f407SFrançois Tigeot 			continue;
24978621f407SFrançois Tigeot 
24988621f407SFrançois Tigeot 		/* Would completion of this request free enough space? */
24998621f407SFrançois Tigeot 		space = __intel_ring_space(target->postfix, ringbuf->tail,
25008621f407SFrançois Tigeot 					   ringbuf->size);
25018621f407SFrançois Tigeot 		if (space >= bytes)
25028621f407SFrançois Tigeot 			break;
25038621f407SFrançois Tigeot 	}
25048621f407SFrançois Tigeot 
25058621f407SFrançois Tigeot 	if (WARN_ON(&target->list == &engine->request_list))
25068621f407SFrançois Tigeot 		return -ENOSPC;
25078621f407SFrançois Tigeot 
25088621f407SFrançois Tigeot 	return i915_wait_request(target);
25098621f407SFrançois Tigeot }
25108621f407SFrançois Tigeot 
25118621f407SFrançois Tigeot int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords)
25128621f407SFrançois Tigeot {
25138621f407SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = req->ringbuf;
2514a05eeebfSFrançois Tigeot 	int remain_actual = ringbuf->size - ringbuf->tail;
25158621f407SFrançois Tigeot 	int remain_usable = ringbuf->effective_size - ringbuf->tail;
25168621f407SFrançois Tigeot 	int bytes = num_dwords * sizeof(u32);
25178621f407SFrançois Tigeot 	int total_bytes, wait_bytes;
2518a05eeebfSFrançois Tigeot 	bool need_wrap = false;
2519a05eeebfSFrançois Tigeot 
2520a05eeebfSFrançois Tigeot 	total_bytes = bytes + ringbuf->reserved_size;
2521a05eeebfSFrançois Tigeot 
2522a05eeebfSFrançois Tigeot 	if (unlikely(bytes > remain_usable)) {
2523a05eeebfSFrançois Tigeot 		/*
2524a05eeebfSFrançois Tigeot 		 * Not enough space for the basic request. So need to flush
2525a05eeebfSFrançois Tigeot 		 * out the remainder and then wait for base + reserved.
2526a05eeebfSFrançois Tigeot 		 */
2527a05eeebfSFrançois Tigeot 		wait_bytes = remain_actual + total_bytes;
2528a05eeebfSFrançois Tigeot 		need_wrap = true;
25298621f407SFrançois Tigeot 	} else if (unlikely(total_bytes > remain_usable)) {
2530a05eeebfSFrançois Tigeot 		/*
2531a05eeebfSFrançois Tigeot 		 * The base request will fit but the reserved space
25328621f407SFrançois Tigeot 		 * falls off the end. So we don't need an immediate wrap
2533c0e85e96SFrançois Tigeot 		 * and only need to effectively wait for the reserved
2534c0e85e96SFrançois Tigeot 		 * size space from the start of ringbuffer.
2535a05eeebfSFrançois Tigeot 		 */
2536a05eeebfSFrançois Tigeot 		wait_bytes = remain_actual + ringbuf->reserved_size;
25378621f407SFrançois Tigeot 	} else {
2538a05eeebfSFrançois Tigeot 		/* No wrapping required, just waiting. */
2539a05eeebfSFrançois Tigeot 		wait_bytes = total_bytes;
2540a05eeebfSFrançois Tigeot 	}
2541a05eeebfSFrançois Tigeot 
25428621f407SFrançois Tigeot 	if (wait_bytes > ringbuf->space) {
25438621f407SFrançois Tigeot 		int ret = wait_for_space(req, wait_bytes);
2544a2fdbec6SFrançois Tigeot 		if (unlikely(ret))
2545a2fdbec6SFrançois Tigeot 			return ret;
2546a05eeebfSFrançois Tigeot 
25478621f407SFrançois Tigeot 		intel_ring_update_space(ringbuf);
25488621f407SFrançois Tigeot 		if (unlikely(ringbuf->space < wait_bytes))
25498621f407SFrançois Tigeot 			return -EAGAIN;
2550a2fdbec6SFrançois Tigeot 	}
2551a2fdbec6SFrançois Tigeot 
25528621f407SFrançois Tigeot 	if (unlikely(need_wrap)) {
25538621f407SFrançois Tigeot 		GEM_BUG_ON(remain_actual > ringbuf->space);
25548621f407SFrançois Tigeot 		GEM_BUG_ON(ringbuf->tail + remain_actual > ringbuf->size);
25558621f407SFrançois Tigeot 
25568621f407SFrançois Tigeot 		/* Fill the tail with MI_NOOP */
25578621f407SFrançois Tigeot 		memset(ringbuf->virtual_start + ringbuf->tail,
25588621f407SFrançois Tigeot 		       0, remain_actual);
25598621f407SFrançois Tigeot 		ringbuf->tail = 0;
25608621f407SFrançois Tigeot 		ringbuf->space -= remain_actual;
2561a2fdbec6SFrançois Tigeot 	}
2562a2fdbec6SFrançois Tigeot 
25638621f407SFrançois Tigeot 	ringbuf->space -= bytes;
25648621f407SFrançois Tigeot 	GEM_BUG_ON(ringbuf->space < 0);
25659edbd4a0SFrançois Tigeot 	return 0;
25669edbd4a0SFrançois Tigeot }
25679edbd4a0SFrançois Tigeot 
25689edbd4a0SFrançois Tigeot /* Align the ring tail to a cacheline boundary */
2569a05eeebfSFrançois Tigeot int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
25709edbd4a0SFrançois Tigeot {
25718621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
25728621f407SFrançois Tigeot 	int num_dwords = (engine->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
25739edbd4a0SFrançois Tigeot 	int ret;
25749edbd4a0SFrançois Tigeot 
25759edbd4a0SFrançois Tigeot 	if (num_dwords == 0)
25769edbd4a0SFrançois Tigeot 		return 0;
25779edbd4a0SFrançois Tigeot 
2578ba55f2f5SFrançois Tigeot 	num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords;
2579a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, num_dwords);
25809edbd4a0SFrançois Tigeot 	if (ret)
25819edbd4a0SFrançois Tigeot 		return ret;
25829edbd4a0SFrançois Tigeot 
25839edbd4a0SFrançois Tigeot 	while (num_dwords--)
25848621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
25859edbd4a0SFrançois Tigeot 
25868621f407SFrançois Tigeot 	intel_ring_advance(engine);
25879edbd4a0SFrançois Tigeot 
25889edbd4a0SFrançois Tigeot 	return 0;
2589e3adcf8fSFrançois Tigeot }
2590e3adcf8fSFrançois Tigeot 
25918621f407SFrançois Tigeot void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno)
2592a2fdbec6SFrançois Tigeot {
25938621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(engine->dev);
2594a2fdbec6SFrançois Tigeot 
25958621f407SFrançois Tigeot 	/* Our semaphore implementation is strictly monotonic (i.e. we proceed
25968621f407SFrançois Tigeot 	 * so long as the semaphore value in the register/page is greater
25978621f407SFrançois Tigeot 	 * than the sync value), so whenever we reset the seqno,
25988621f407SFrançois Tigeot 	 * so long as we reset the tracking semaphore value to 0, it will
25998621f407SFrançois Tigeot 	 * always be before the next request's seqno. If we don't reset
26008621f407SFrançois Tigeot 	 * the semaphore value, then when the seqno moves backwards all
26018621f407SFrançois Tigeot 	 * future waits will complete instantly (causing rendering corruption).
26028621f407SFrançois Tigeot 	 */
26038621f407SFrançois Tigeot 	if (INTEL_INFO(dev_priv)->gen == 6 || INTEL_INFO(dev_priv)->gen == 7) {
26048621f407SFrançois Tigeot 		I915_WRITE(RING_SYNC_0(engine->mmio_base), 0);
26058621f407SFrançois Tigeot 		I915_WRITE(RING_SYNC_1(engine->mmio_base), 0);
26068621f407SFrançois Tigeot 		if (HAS_VEBOX(dev_priv))
26078621f407SFrançois Tigeot 			I915_WRITE(RING_SYNC_2(engine->mmio_base), 0);
26088621f407SFrançois Tigeot 	}
26098621f407SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
26108621f407SFrançois Tigeot 		struct drm_i915_gem_object *obj = dev_priv->semaphore_obj;
2611*f0bba3d1SFrançois Tigeot 		struct page *page = i915_gem_object_get_dirty_page(obj, 0);
26128621f407SFrançois Tigeot 		char *semaphores = kmap(page);
26138621f407SFrançois Tigeot 		memset(semaphores + GEN8_SEMAPHORE_OFFSET(engine->id, 0),
26148621f407SFrançois Tigeot 		       0, I915_NUM_ENGINES * gen8_semaphore_seqno_size);
26158621f407SFrançois Tigeot 		kunmap(page);
26168621f407SFrançois Tigeot 	}
26178621f407SFrançois Tigeot 	memset(engine->semaphore.sync_seqno, 0,
26188621f407SFrançois Tigeot 	       sizeof(engine->semaphore.sync_seqno));
26198621f407SFrançois Tigeot 
26208621f407SFrançois Tigeot 	engine->set_seqno(engine, seqno);
26218621f407SFrançois Tigeot 	engine->last_submitted_seqno = seqno;
26228621f407SFrançois Tigeot 
26238621f407SFrançois Tigeot 	engine->hangcheck.seqno = seqno;
2624e3adcf8fSFrançois Tigeot }
2625e3adcf8fSFrançois Tigeot 
26268621f407SFrançois Tigeot static void gen6_bsd_ring_write_tail(struct intel_engine_cs *engine,
2627f4e1c372SFrançois Tigeot 				     u32 value)
2628e3adcf8fSFrançois Tigeot {
26298621f407SFrançois Tigeot 	struct drm_i915_private *dev_priv = engine->dev->dev_private;
2630e3adcf8fSFrançois Tigeot 
2631e3adcf8fSFrançois Tigeot        /* Every tail move must follow the sequence below */
2632f4e1c372SFrançois Tigeot 
2633f4e1c372SFrançois Tigeot 	/* Disable notification that the ring is IDLE. The GT
2634f4e1c372SFrançois Tigeot 	 * will then assume that it is busy and bring it out of rc6.
2635f4e1c372SFrançois Tigeot 	 */
2636e3adcf8fSFrançois Tigeot 	I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
2637f4e1c372SFrançois Tigeot 		   _MASKED_BIT_ENABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2638e3adcf8fSFrançois Tigeot 
2639f4e1c372SFrançois Tigeot 	/* Clear the context id. Here be magic! */
2640f4e1c372SFrançois Tigeot 	I915_WRITE64(GEN6_BSD_RNCID, 0x0);
2641e3adcf8fSFrançois Tigeot 
2642f4e1c372SFrançois Tigeot 	/* Wait for the ring not to be idle, i.e. for it to wake up. */
2643f4e1c372SFrançois Tigeot 	if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
2644f4e1c372SFrançois Tigeot 		      GEN6_BSD_SLEEP_INDICATOR) == 0,
2645f4e1c372SFrançois Tigeot 		     50))
2646f4e1c372SFrançois Tigeot 		DRM_ERROR("timed out waiting for the BSD ring to wake up\n");
2647f4e1c372SFrançois Tigeot 
2648f4e1c372SFrançois Tigeot 	/* Now that the ring is fully powered up, update the tail */
26498621f407SFrançois Tigeot 	I915_WRITE_TAIL(engine, value);
26508621f407SFrançois Tigeot 	POSTING_READ(RING_TAIL(engine->mmio_base));
2651f4e1c372SFrançois Tigeot 
2652f4e1c372SFrançois Tigeot 	/* Let the ring send IDLE messages to the GT again,
2653f4e1c372SFrançois Tigeot 	 * and so let it sleep to conserve power when idle.
2654f4e1c372SFrançois Tigeot 	 */
2655e3adcf8fSFrançois Tigeot 	I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
2656f4e1c372SFrançois Tigeot 		   _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2657e3adcf8fSFrançois Tigeot }
2658e3adcf8fSFrançois Tigeot 
2659a05eeebfSFrançois Tigeot static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req,
2660b5c29a34SFrançois Tigeot 			       u32 invalidate, u32 flush)
2661e3adcf8fSFrançois Tigeot {
26628621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2663e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2664e3adcf8fSFrançois Tigeot 	int ret;
2665e3adcf8fSFrançois Tigeot 
2666a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2667e3adcf8fSFrançois Tigeot 	if (ret)
2668e3adcf8fSFrançois Tigeot 		return ret;
2669e3adcf8fSFrançois Tigeot 
2670e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
26718621f407SFrançois Tigeot 	if (INTEL_INFO(engine->dev)->gen >= 8)
26729edbd4a0SFrançois Tigeot 		cmd += 1;
26732c9916cdSFrançois Tigeot 
26742c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
26752c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
26762c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
26772c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
26782c9916cdSFrançois Tigeot 	 */
26792c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
26802c9916cdSFrançois Tigeot 
2681b5c29a34SFrançois Tigeot 	/*
2682b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.5 - video engine command streamer:
2683b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2684b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2685b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2686b5c29a34SFrançois Tigeot 	 */
2687e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_GPU_DOMAINS)
26882c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
26892c9916cdSFrançois Tigeot 
26908621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
26918621f407SFrançois Tigeot 	intel_ring_emit(engine,
26928621f407SFrançois Tigeot 			I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
26938621f407SFrançois Tigeot 	if (INTEL_INFO(engine->dev)->gen >= 8) {
26948621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* upper addr */
26958621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* value */
26969edbd4a0SFrançois Tigeot 	} else  {
26978621f407SFrançois Tigeot 		intel_ring_emit(engine, 0);
26988621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
26999edbd4a0SFrançois Tigeot 	}
27008621f407SFrançois Tigeot 	intel_ring_advance(engine);
27019edbd4a0SFrançois Tigeot 	return 0;
27029edbd4a0SFrançois Tigeot }
27039edbd4a0SFrançois Tigeot 
27049edbd4a0SFrançois Tigeot static int
2705a05eeebfSFrançois Tigeot gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2706ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2707477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
27089edbd4a0SFrançois Tigeot {
27098621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
27108621f407SFrançois Tigeot 	bool ppgtt = USES_PPGTT(engine->dev) &&
2711477eb7f9SFrançois Tigeot 			!(dispatch_flags & I915_DISPATCH_SECURE);
27129edbd4a0SFrançois Tigeot 	int ret;
27139edbd4a0SFrançois Tigeot 
2714a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
27159edbd4a0SFrançois Tigeot 	if (ret)
27169edbd4a0SFrançois Tigeot 		return ret;
27179edbd4a0SFrançois Tigeot 
27189edbd4a0SFrançois Tigeot 	/* FIXME(BDW): Address space and security selectors. */
27198621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) |
2720a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2721a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
27228621f407SFrançois Tigeot 	intel_ring_emit(engine, lower_32_bits(offset));
27238621f407SFrançois Tigeot 	intel_ring_emit(engine, upper_32_bits(offset));
27248621f407SFrançois Tigeot 	intel_ring_emit(engine, MI_NOOP);
27258621f407SFrançois Tigeot 	intel_ring_advance(engine);
27269edbd4a0SFrançois Tigeot 
2727e3adcf8fSFrançois Tigeot 	return 0;
2728e3adcf8fSFrançois Tigeot }
2729e3adcf8fSFrançois Tigeot 
2730e3adcf8fSFrançois Tigeot static int
2731a05eeebfSFrançois Tigeot hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2732ba55f2f5SFrançois Tigeot 			     u64 offset, u32 len,
2733477eb7f9SFrançois Tigeot 			     unsigned dispatch_flags)
2734e3adcf8fSFrançois Tigeot {
27358621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2736e3adcf8fSFrançois Tigeot 	int ret;
2737e3adcf8fSFrançois Tigeot 
2738a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2739e3adcf8fSFrançois Tigeot 	if (ret)
2740e3adcf8fSFrançois Tigeot 		return ret;
2741e3adcf8fSFrançois Tigeot 
27428621f407SFrançois Tigeot 	intel_ring_emit(engine,
27431b13d190SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2744477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2745a05eeebfSFrançois Tigeot 			 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) |
2746a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2747a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
2748b5c29a34SFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
27498621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
27508621f407SFrançois Tigeot 	intel_ring_advance(engine);
2751b5c29a34SFrançois Tigeot 
2752b5c29a34SFrançois Tigeot 	return 0;
2753b5c29a34SFrançois Tigeot }
2754b5c29a34SFrançois Tigeot 
2755b5c29a34SFrançois Tigeot static int
2756a05eeebfSFrançois Tigeot gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2757ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2758477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
2759b5c29a34SFrançois Tigeot {
27608621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
2761b5c29a34SFrançois Tigeot 	int ret;
2762b5c29a34SFrançois Tigeot 
2763a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2764b5c29a34SFrançois Tigeot 	if (ret)
2765b5c29a34SFrançois Tigeot 		return ret;
2766b5c29a34SFrançois Tigeot 
27678621f407SFrançois Tigeot 	intel_ring_emit(engine,
2768b5c29a34SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2769477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2770477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
2771e3adcf8fSFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
27728621f407SFrançois Tigeot 	intel_ring_emit(engine, offset);
27738621f407SFrançois Tigeot 	intel_ring_advance(engine);
2774e3adcf8fSFrançois Tigeot 
2775e3adcf8fSFrançois Tigeot 	return 0;
2776e3adcf8fSFrançois Tigeot }
2777e3adcf8fSFrançois Tigeot 
2778e3adcf8fSFrançois Tigeot /* Blitter support (SandyBridge+) */
2779e3adcf8fSFrançois Tigeot 
2780a05eeebfSFrançois Tigeot static int gen6_ring_flush(struct drm_i915_gem_request *req,
2781b5c29a34SFrançois Tigeot 			   u32 invalidate, u32 flush)
2782e3adcf8fSFrançois Tigeot {
27838621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
27848621f407SFrançois Tigeot 	struct drm_device *dev = engine->dev;
2785e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2786e3adcf8fSFrançois Tigeot 	int ret;
2787e3adcf8fSFrançois Tigeot 
2788a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2789e3adcf8fSFrançois Tigeot 	if (ret)
2790e3adcf8fSFrançois Tigeot 		return ret;
2791e3adcf8fSFrançois Tigeot 
2792e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
2793477eb7f9SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8)
27949edbd4a0SFrançois Tigeot 		cmd += 1;
27952c9916cdSFrançois Tigeot 
27962c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
27972c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
27982c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
27992c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
28002c9916cdSFrançois Tigeot 	 */
28012c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
28022c9916cdSFrançois Tigeot 
2803b5c29a34SFrançois Tigeot 	/*
2804b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.3 - blitter engine command streamer:
2805b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2806b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2807b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2808b5c29a34SFrançois Tigeot 	 */
2809e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_DOMAIN_RENDER)
28102c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB;
28118621f407SFrançois Tigeot 	intel_ring_emit(engine, cmd);
28128621f407SFrançois Tigeot 	intel_ring_emit(engine,
28138621f407SFrançois Tigeot 			I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
2814477eb7f9SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
28158621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* upper addr */
28168621f407SFrançois Tigeot 		intel_ring_emit(engine, 0); /* value */
28179edbd4a0SFrançois Tigeot 	} else  {
28188621f407SFrançois Tigeot 		intel_ring_emit(engine, 0);
28198621f407SFrançois Tigeot 		intel_ring_emit(engine, MI_NOOP);
28209edbd4a0SFrançois Tigeot 	}
28218621f407SFrançois Tigeot 	intel_ring_advance(engine);
28225d0b1887SFrançois Tigeot 
2823e3adcf8fSFrançois Tigeot 	return 0;
2824e3adcf8fSFrançois Tigeot }
2825e3adcf8fSFrançois Tigeot 
2826e3adcf8fSFrançois Tigeot int intel_init_render_ring_buffer(struct drm_device *dev)
2827e3adcf8fSFrançois Tigeot {
2828ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
28298621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[RCS];
283024edb884SFrançois Tigeot 	struct drm_i915_gem_object *obj;
283124edb884SFrançois Tigeot 	int ret;
2832e3adcf8fSFrançois Tigeot 
28338621f407SFrançois Tigeot 	engine->name = "render ring";
28348621f407SFrançois Tigeot 	engine->id = RCS;
28358621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_RENDER;
28368621f407SFrançois Tigeot 	engine->hw_id = 0;
28378621f407SFrançois Tigeot 	engine->mmio_base = RENDER_RING_BASE;
2838686a02f1SFrançois Tigeot 
283924edb884SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
284024edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
284124edb884SFrançois Tigeot 			obj = i915_gem_alloc_object(dev, 4096);
284224edb884SFrançois Tigeot 			if (obj == NULL) {
284324edb884SFrançois Tigeot 				DRM_ERROR("Failed to allocate semaphore bo. Disabling semaphores\n");
284424edb884SFrançois Tigeot 				i915.semaphores = 0;
284524edb884SFrançois Tigeot 			} else {
284624edb884SFrançois Tigeot 				i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
284724edb884SFrançois Tigeot 				ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_NONBLOCK);
284824edb884SFrançois Tigeot 				if (ret != 0) {
284924edb884SFrançois Tigeot 					drm_gem_object_unreference(&obj->base);
285024edb884SFrançois Tigeot 					DRM_ERROR("Failed to pin semaphore bo. Disabling semaphores\n");
285124edb884SFrançois Tigeot 					i915.semaphores = 0;
285224edb884SFrançois Tigeot 				} else
285324edb884SFrançois Tigeot 					dev_priv->semaphore_obj = obj;
285424edb884SFrançois Tigeot 			}
285524edb884SFrançois Tigeot 		}
28562c9916cdSFrançois Tigeot 
28578621f407SFrançois Tigeot 		engine->init_context = intel_rcs_ctx_init;
28588621f407SFrançois Tigeot 		engine->add_request = gen6_add_request;
28598621f407SFrançois Tigeot 		engine->flush = gen8_render_ring_flush;
28608621f407SFrançois Tigeot 		engine->irq_get = gen8_ring_get_irq;
28618621f407SFrançois Tigeot 		engine->irq_put = gen8_ring_put_irq;
28628621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
28638621f407SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
28648621f407SFrançois Tigeot 		engine->get_seqno = ring_get_seqno;
28658621f407SFrançois Tigeot 		engine->set_seqno = ring_set_seqno;
286624edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
286724edb884SFrançois Tigeot 			WARN_ON(!dev_priv->semaphore_obj);
28688621f407SFrançois Tigeot 			engine->semaphore.sync_to = gen8_ring_sync;
28698621f407SFrançois Tigeot 			engine->semaphore.signal = gen8_rcs_signal;
28708621f407SFrançois Tigeot 			GEN8_RING_SEMAPHORE_INIT(engine);
287124edb884SFrançois Tigeot 		}
287224edb884SFrançois Tigeot 	} else if (INTEL_INFO(dev)->gen >= 6) {
28738621f407SFrançois Tigeot 		engine->init_context = intel_rcs_ctx_init;
28748621f407SFrançois Tigeot 		engine->add_request = gen6_add_request;
28758621f407SFrançois Tigeot 		engine->flush = gen7_render_ring_flush;
2876b5c29a34SFrançois Tigeot 		if (INTEL_INFO(dev)->gen == 6)
28778621f407SFrançois Tigeot 			engine->flush = gen6_render_ring_flush;
28788621f407SFrançois Tigeot 		engine->irq_get = gen6_ring_get_irq;
28798621f407SFrançois Tigeot 		engine->irq_put = gen6_ring_put_irq;
28808621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
28818621f407SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
28828621f407SFrançois Tigeot 		engine->get_seqno = ring_get_seqno;
28838621f407SFrançois Tigeot 		engine->set_seqno = ring_set_seqno;
288424edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
28858621f407SFrançois Tigeot 			engine->semaphore.sync_to = gen6_ring_sync;
28868621f407SFrançois Tigeot 			engine->semaphore.signal = gen6_signal;
2887ba55f2f5SFrançois Tigeot 			/*
288824edb884SFrançois Tigeot 			 * The current semaphore is only applied on pre-gen8
288924edb884SFrançois Tigeot 			 * platform.  And there is no VCS2 ring on the pre-gen8
289024edb884SFrançois Tigeot 			 * platform. So the semaphore between RCS and VCS2 is
289124edb884SFrançois Tigeot 			 * initialized as INVALID.  Gen8 will initialize the
289224edb884SFrançois Tigeot 			 * sema between VCS2 and RCS later.
2893ba55f2f5SFrançois Tigeot 			 */
28948621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_INVALID;
28958621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_RV;
28968621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_RB;
28978621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_RVE;
28988621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
28998621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[RCS] = GEN6_NOSYNC;
29008621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VCS] = GEN6_VRSYNC;
29018621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[BCS] = GEN6_BRSYNC;
29028621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VECS] = GEN6_VERSYNC;
29038621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
290424edb884SFrançois Tigeot 		}
2905e3adcf8fSFrançois Tigeot 	} else if (IS_GEN5(dev)) {
29068621f407SFrançois Tigeot 		engine->add_request = pc_render_add_request;
29078621f407SFrançois Tigeot 		engine->flush = gen4_render_ring_flush;
29088621f407SFrançois Tigeot 		engine->get_seqno = pc_render_get_seqno;
29098621f407SFrançois Tigeot 		engine->set_seqno = pc_render_set_seqno;
29108621f407SFrançois Tigeot 		engine->irq_get = gen5_ring_get_irq;
29118621f407SFrançois Tigeot 		engine->irq_put = gen5_ring_put_irq;
29128621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT |
29135d0b1887SFrançois Tigeot 					GT_RENDER_PIPECTL_NOTIFY_INTERRUPT;
2914686a02f1SFrançois Tigeot 	} else {
29158621f407SFrançois Tigeot 		engine->add_request = i9xx_add_request;
2916686a02f1SFrançois Tigeot 		if (INTEL_INFO(dev)->gen < 4)
29178621f407SFrançois Tigeot 			engine->flush = gen2_render_ring_flush;
2918686a02f1SFrançois Tigeot 		else
29198621f407SFrançois Tigeot 			engine->flush = gen4_render_ring_flush;
29208621f407SFrançois Tigeot 		engine->get_seqno = ring_get_seqno;
29218621f407SFrançois Tigeot 		engine->set_seqno = ring_set_seqno;
2922686a02f1SFrançois Tigeot 		if (IS_GEN2(dev)) {
29238621f407SFrançois Tigeot 			engine->irq_get = i8xx_ring_get_irq;
29248621f407SFrançois Tigeot 			engine->irq_put = i8xx_ring_put_irq;
2925686a02f1SFrançois Tigeot 		} else {
29268621f407SFrançois Tigeot 			engine->irq_get = i9xx_ring_get_irq;
29278621f407SFrançois Tigeot 			engine->irq_put = i9xx_ring_put_irq;
2928e3adcf8fSFrançois Tigeot 		}
29298621f407SFrançois Tigeot 		engine->irq_enable_mask = I915_USER_INTERRUPT;
2930686a02f1SFrançois Tigeot 	}
29318621f407SFrançois Tigeot 	engine->write_tail = ring_write_tail;
293224edb884SFrançois Tigeot 
2933b5c29a34SFrançois Tigeot 	if (IS_HASWELL(dev))
29348621f407SFrançois Tigeot 		engine->dispatch_execbuffer = hsw_ring_dispatch_execbuffer;
29359edbd4a0SFrançois Tigeot 	else if (IS_GEN8(dev))
29368621f407SFrançois Tigeot 		engine->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
2937b5c29a34SFrançois Tigeot 	else if (INTEL_INFO(dev)->gen >= 6)
29388621f407SFrançois Tigeot 		engine->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
2939686a02f1SFrançois Tigeot 	else if (INTEL_INFO(dev)->gen >= 4)
29408621f407SFrançois Tigeot 		engine->dispatch_execbuffer = i965_dispatch_execbuffer;
2941686a02f1SFrançois Tigeot 	else if (IS_I830(dev) || IS_845G(dev))
29428621f407SFrançois Tigeot 		engine->dispatch_execbuffer = i830_dispatch_execbuffer;
2943686a02f1SFrançois Tigeot 	else
29448621f407SFrançois Tigeot 		engine->dispatch_execbuffer = i915_dispatch_execbuffer;
29458621f407SFrançois Tigeot 	engine->init_hw = init_render_ring;
29468621f407SFrançois Tigeot 	engine->cleanup = render_ring_cleanup;
2947e3adcf8fSFrançois Tigeot 
2948b5c29a34SFrançois Tigeot 	/* Workaround batchbuffer to combat CS tlb bug. */
2949b5c29a34SFrançois Tigeot 	if (HAS_BROKEN_CS_TLB(dev)) {
295024edb884SFrançois Tigeot 		obj = i915_gem_alloc_object(dev, I830_WA_SIZE);
2951b5c29a34SFrançois Tigeot 		if (obj == NULL) {
2952b5c29a34SFrançois Tigeot 			DRM_ERROR("Failed to allocate batch bo\n");
2953b5c29a34SFrançois Tigeot 			return -ENOMEM;
2954b5c29a34SFrançois Tigeot 		}
2955b5c29a34SFrançois Tigeot 
2956ba55f2f5SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 0, 0);
2957b5c29a34SFrançois Tigeot 		if (ret != 0) {
2958b5c29a34SFrançois Tigeot 			drm_gem_object_unreference(&obj->base);
2959b5c29a34SFrançois Tigeot 			DRM_ERROR("Failed to ping batch bo\n");
2960b5c29a34SFrançois Tigeot 			return ret;
2961b5c29a34SFrançois Tigeot 		}
2962b5c29a34SFrançois Tigeot 
29638621f407SFrançois Tigeot 		engine->scratch.obj = obj;
29648621f407SFrançois Tigeot 		engine->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
2965e3adcf8fSFrançois Tigeot 	}
2966e3adcf8fSFrançois Tigeot 
29678621f407SFrançois Tigeot 	ret = intel_init_ring_buffer(dev, engine);
2968b5c29a34SFrançois Tigeot 	if (ret)
29692c9916cdSFrançois Tigeot 		return ret;
29702c9916cdSFrançois Tigeot 
29712c9916cdSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 5) {
29728621f407SFrançois Tigeot 		ret = intel_init_pipe_control(engine);
29732c9916cdSFrançois Tigeot 		if (ret)
29742c9916cdSFrançois Tigeot 			return ret;
2975b5c29a34SFrançois Tigeot 	}
2976b5c29a34SFrançois Tigeot 
2977e3adcf8fSFrançois Tigeot 	return 0;
2978e3adcf8fSFrançois Tigeot }
2979e3adcf8fSFrançois Tigeot 
2980e3adcf8fSFrançois Tigeot int intel_init_bsd_ring_buffer(struct drm_device *dev)
2981e3adcf8fSFrançois Tigeot {
2982ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
29838621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[VCS];
2984e3adcf8fSFrançois Tigeot 
29858621f407SFrançois Tigeot 	engine->name = "bsd ring";
29868621f407SFrançois Tigeot 	engine->id = VCS;
29878621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_BSD;
29888621f407SFrançois Tigeot 	engine->hw_id = 1;
2989686a02f1SFrançois Tigeot 
29908621f407SFrançois Tigeot 	engine->write_tail = ring_write_tail;
29919edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6) {
29928621f407SFrançois Tigeot 		engine->mmio_base = GEN6_BSD_RING_BASE;
2993686a02f1SFrançois Tigeot 		/* gen6 bsd needs a special wa for tail updates */
2994686a02f1SFrançois Tigeot 		if (IS_GEN6(dev))
29958621f407SFrançois Tigeot 			engine->write_tail = gen6_bsd_ring_write_tail;
29968621f407SFrançois Tigeot 		engine->flush = gen6_bsd_ring_flush;
29978621f407SFrançois Tigeot 		engine->add_request = gen6_add_request;
29988621f407SFrançois Tigeot 		engine->irq_seqno_barrier = gen6_seqno_barrier;
29998621f407SFrançois Tigeot 		engine->get_seqno = ring_get_seqno;
30008621f407SFrançois Tigeot 		engine->set_seqno = ring_set_seqno;
30019edbd4a0SFrançois Tigeot 		if (INTEL_INFO(dev)->gen >= 8) {
30028621f407SFrançois Tigeot 			engine->irq_enable_mask =
30039edbd4a0SFrançois Tigeot 				GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
30048621f407SFrançois Tigeot 			engine->irq_get = gen8_ring_get_irq;
30058621f407SFrançois Tigeot 			engine->irq_put = gen8_ring_put_irq;
30068621f407SFrançois Tigeot 			engine->dispatch_execbuffer =
30079edbd4a0SFrançois Tigeot 				gen8_ring_dispatch_execbuffer;
300824edb884SFrançois Tigeot 			if (i915_semaphore_is_enabled(dev)) {
30098621f407SFrançois Tigeot 				engine->semaphore.sync_to = gen8_ring_sync;
30108621f407SFrançois Tigeot 				engine->semaphore.signal = gen8_xcs_signal;
30118621f407SFrançois Tigeot 				GEN8_RING_SEMAPHORE_INIT(engine);
301224edb884SFrançois Tigeot 			}
30139edbd4a0SFrançois Tigeot 		} else {
30148621f407SFrançois Tigeot 			engine->irq_enable_mask = GT_BSD_USER_INTERRUPT;
30158621f407SFrançois Tigeot 			engine->irq_get = gen6_ring_get_irq;
30168621f407SFrançois Tigeot 			engine->irq_put = gen6_ring_put_irq;
30178621f407SFrançois Tigeot 			engine->dispatch_execbuffer =
30189edbd4a0SFrançois Tigeot 				gen6_ring_dispatch_execbuffer;
301924edb884SFrançois Tigeot 			if (i915_semaphore_is_enabled(dev)) {
30208621f407SFrançois Tigeot 				engine->semaphore.sync_to = gen6_ring_sync;
30218621f407SFrançois Tigeot 				engine->semaphore.signal = gen6_signal;
30228621f407SFrançois Tigeot 				engine->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VR;
30238621f407SFrançois Tigeot 				engine->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_INVALID;
30248621f407SFrançois Tigeot 				engine->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VB;
30258621f407SFrançois Tigeot 				engine->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_VVE;
30268621f407SFrançois Tigeot 				engine->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
30278621f407SFrançois Tigeot 				engine->semaphore.mbox.signal[RCS] = GEN6_RVSYNC;
30288621f407SFrançois Tigeot 				engine->semaphore.mbox.signal[VCS] = GEN6_NOSYNC;
30298621f407SFrançois Tigeot 				engine->semaphore.mbox.signal[BCS] = GEN6_BVSYNC;
30308621f407SFrançois Tigeot 				engine->semaphore.mbox.signal[VECS] = GEN6_VEVSYNC;
30318621f407SFrançois Tigeot 				engine->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
303224edb884SFrançois Tigeot 			}
303324edb884SFrançois Tigeot 		}
3034686a02f1SFrançois Tigeot 	} else {
30358621f407SFrançois Tigeot 		engine->mmio_base = BSD_RING_BASE;
30368621f407SFrançois Tigeot 		engine->flush = bsd_ring_flush;
30378621f407SFrançois Tigeot 		engine->add_request = i9xx_add_request;
30388621f407SFrançois Tigeot 		engine->get_seqno = ring_get_seqno;
30398621f407SFrançois Tigeot 		engine->set_seqno = ring_set_seqno;
3040686a02f1SFrançois Tigeot 		if (IS_GEN5(dev)) {
30418621f407SFrançois Tigeot 			engine->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
30428621f407SFrançois Tigeot 			engine->irq_get = gen5_ring_get_irq;
30438621f407SFrançois Tigeot 			engine->irq_put = gen5_ring_put_irq;
3044686a02f1SFrançois Tigeot 		} else {
30458621f407SFrançois Tigeot 			engine->irq_enable_mask = I915_BSD_USER_INTERRUPT;
30468621f407SFrançois Tigeot 			engine->irq_get = i9xx_ring_get_irq;
30478621f407SFrançois Tigeot 			engine->irq_put = i9xx_ring_put_irq;
3048686a02f1SFrançois Tigeot 		}
30498621f407SFrançois Tigeot 		engine->dispatch_execbuffer = i965_dispatch_execbuffer;
3050686a02f1SFrançois Tigeot 	}
30518621f407SFrançois Tigeot 	engine->init_hw = init_ring_common;
3052e3adcf8fSFrançois Tigeot 
30538621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
3054e3adcf8fSFrançois Tigeot }
3055e3adcf8fSFrançois Tigeot 
3056ba55f2f5SFrançois Tigeot /**
3057477eb7f9SFrançois Tigeot  * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
3058ba55f2f5SFrançois Tigeot  */
3059ba55f2f5SFrançois Tigeot int intel_init_bsd2_ring_buffer(struct drm_device *dev)
3060ba55f2f5SFrançois Tigeot {
3061ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
30628621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[VCS2];
3063ba55f2f5SFrançois Tigeot 
30648621f407SFrançois Tigeot 	engine->name = "bsd2 ring";
30658621f407SFrançois Tigeot 	engine->id = VCS2;
30668621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_BSD;
30678621f407SFrançois Tigeot 	engine->hw_id = 4;
3068ba55f2f5SFrançois Tigeot 
30698621f407SFrançois Tigeot 	engine->write_tail = ring_write_tail;
30708621f407SFrançois Tigeot 	engine->mmio_base = GEN8_BSD2_RING_BASE;
30718621f407SFrançois Tigeot 	engine->flush = gen6_bsd_ring_flush;
30728621f407SFrançois Tigeot 	engine->add_request = gen6_add_request;
30738621f407SFrançois Tigeot 	engine->irq_seqno_barrier = gen6_seqno_barrier;
30748621f407SFrançois Tigeot 	engine->get_seqno = ring_get_seqno;
30758621f407SFrançois Tigeot 	engine->set_seqno = ring_set_seqno;
30768621f407SFrançois Tigeot 	engine->irq_enable_mask =
3077ba55f2f5SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
30788621f407SFrançois Tigeot 	engine->irq_get = gen8_ring_get_irq;
30798621f407SFrançois Tigeot 	engine->irq_put = gen8_ring_put_irq;
30808621f407SFrançois Tigeot 	engine->dispatch_execbuffer =
3081ba55f2f5SFrançois Tigeot 			gen8_ring_dispatch_execbuffer;
308224edb884SFrançois Tigeot 	if (i915_semaphore_is_enabled(dev)) {
30838621f407SFrançois Tigeot 		engine->semaphore.sync_to = gen8_ring_sync;
30848621f407SFrançois Tigeot 		engine->semaphore.signal = gen8_xcs_signal;
30858621f407SFrançois Tigeot 		GEN8_RING_SEMAPHORE_INIT(engine);
308624edb884SFrançois Tigeot 	}
30878621f407SFrançois Tigeot 	engine->init_hw = init_ring_common;
3088ba55f2f5SFrançois Tigeot 
30898621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
3090ba55f2f5SFrançois Tigeot }
3091ba55f2f5SFrançois Tigeot 
3092e3adcf8fSFrançois Tigeot int intel_init_blt_ring_buffer(struct drm_device *dev)
3093e3adcf8fSFrançois Tigeot {
3094ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
30958621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[BCS];
3096e3adcf8fSFrançois Tigeot 
30978621f407SFrançois Tigeot 	engine->name = "blitter ring";
30988621f407SFrançois Tigeot 	engine->id = BCS;
30998621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_BLT;
31008621f407SFrançois Tigeot 	engine->hw_id = 2;
3101686a02f1SFrançois Tigeot 
31028621f407SFrançois Tigeot 	engine->mmio_base = BLT_RING_BASE;
31038621f407SFrançois Tigeot 	engine->write_tail = ring_write_tail;
31048621f407SFrançois Tigeot 	engine->flush = gen6_ring_flush;
31058621f407SFrançois Tigeot 	engine->add_request = gen6_add_request;
31068621f407SFrançois Tigeot 	engine->irq_seqno_barrier = gen6_seqno_barrier;
31078621f407SFrançois Tigeot 	engine->get_seqno = ring_get_seqno;
31088621f407SFrançois Tigeot 	engine->set_seqno = ring_set_seqno;
31099edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
31108621f407SFrançois Tigeot 		engine->irq_enable_mask =
31119edbd4a0SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
31128621f407SFrançois Tigeot 		engine->irq_get = gen8_ring_get_irq;
31138621f407SFrançois Tigeot 		engine->irq_put = gen8_ring_put_irq;
31148621f407SFrançois Tigeot 		engine->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
311524edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
31168621f407SFrançois Tigeot 			engine->semaphore.sync_to = gen8_ring_sync;
31178621f407SFrançois Tigeot 			engine->semaphore.signal = gen8_xcs_signal;
31188621f407SFrançois Tigeot 			GEN8_RING_SEMAPHORE_INIT(engine);
311924edb884SFrançois Tigeot 		}
31209edbd4a0SFrançois Tigeot 	} else {
31218621f407SFrançois Tigeot 		engine->irq_enable_mask = GT_BLT_USER_INTERRUPT;
31228621f407SFrançois Tigeot 		engine->irq_get = gen6_ring_get_irq;
31238621f407SFrançois Tigeot 		engine->irq_put = gen6_ring_put_irq;
31248621f407SFrançois Tigeot 		engine->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
312524edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
31268621f407SFrançois Tigeot 			engine->semaphore.signal = gen6_signal;
31278621f407SFrançois Tigeot 			engine->semaphore.sync_to = gen6_ring_sync;
3128ba55f2f5SFrançois Tigeot 			/*
312924edb884SFrançois Tigeot 			 * The current semaphore is only applied on pre-gen8
313024edb884SFrançois Tigeot 			 * platform.  And there is no VCS2 ring on the pre-gen8
313124edb884SFrançois Tigeot 			 * platform. So the semaphore between BCS and VCS2 is
313224edb884SFrançois Tigeot 			 * initialized as INVALID.  Gen8 will initialize the
313324edb884SFrançois Tigeot 			 * sema between BCS and VCS2 later.
3134ba55f2f5SFrançois Tigeot 			 */
31358621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_BR;
31368621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_BV;
31378621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_INVALID;
31388621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_BVE;
31398621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
31408621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[RCS] = GEN6_RBSYNC;
31418621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VCS] = GEN6_VBSYNC;
31428621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[BCS] = GEN6_NOSYNC;
31438621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VECS] = GEN6_VEBSYNC;
31448621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
314524edb884SFrançois Tigeot 		}
314624edb884SFrançois Tigeot 	}
31478621f407SFrançois Tigeot 	engine->init_hw = init_ring_common;
31485d0b1887SFrançois Tigeot 
31498621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
31505d0b1887SFrançois Tigeot }
31515d0b1887SFrançois Tigeot 
31525d0b1887SFrançois Tigeot int intel_init_vebox_ring_buffer(struct drm_device *dev)
31535d0b1887SFrançois Tigeot {
3154ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
31558621f407SFrançois Tigeot 	struct intel_engine_cs *engine = &dev_priv->engine[VECS];
31565d0b1887SFrançois Tigeot 
31578621f407SFrançois Tigeot 	engine->name = "video enhancement ring";
31588621f407SFrançois Tigeot 	engine->id = VECS;
31598621f407SFrançois Tigeot 	engine->exec_id = I915_EXEC_VEBOX;
31608621f407SFrançois Tigeot 	engine->hw_id = 3;
31615d0b1887SFrançois Tigeot 
31628621f407SFrançois Tigeot 	engine->mmio_base = VEBOX_RING_BASE;
31638621f407SFrançois Tigeot 	engine->write_tail = ring_write_tail;
31648621f407SFrançois Tigeot 	engine->flush = gen6_ring_flush;
31658621f407SFrançois Tigeot 	engine->add_request = gen6_add_request;
31668621f407SFrançois Tigeot 	engine->irq_seqno_barrier = gen6_seqno_barrier;
31678621f407SFrançois Tigeot 	engine->get_seqno = ring_get_seqno;
31688621f407SFrançois Tigeot 	engine->set_seqno = ring_set_seqno;
31699edbd4a0SFrançois Tigeot 
31709edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
31718621f407SFrançois Tigeot 		engine->irq_enable_mask =
31729edbd4a0SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
31738621f407SFrançois Tigeot 		engine->irq_get = gen8_ring_get_irq;
31748621f407SFrançois Tigeot 		engine->irq_put = gen8_ring_put_irq;
31758621f407SFrançois Tigeot 		engine->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
317624edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
31778621f407SFrançois Tigeot 			engine->semaphore.sync_to = gen8_ring_sync;
31788621f407SFrançois Tigeot 			engine->semaphore.signal = gen8_xcs_signal;
31798621f407SFrançois Tigeot 			GEN8_RING_SEMAPHORE_INIT(engine);
318024edb884SFrançois Tigeot 		}
31819edbd4a0SFrançois Tigeot 	} else {
31828621f407SFrançois Tigeot 		engine->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
31838621f407SFrançois Tigeot 		engine->irq_get = hsw_vebox_get_irq;
31848621f407SFrançois Tigeot 		engine->irq_put = hsw_vebox_put_irq;
31858621f407SFrançois Tigeot 		engine->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
318624edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
31878621f407SFrançois Tigeot 			engine->semaphore.sync_to = gen6_ring_sync;
31888621f407SFrançois Tigeot 			engine->semaphore.signal = gen6_signal;
31898621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VER;
31908621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_VEV;
31918621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VEB;
31928621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_INVALID;
31938621f407SFrançois Tigeot 			engine->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
31948621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[RCS] = GEN6_RVESYNC;
31958621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VCS] = GEN6_VVESYNC;
31968621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[BCS] = GEN6_BVESYNC;
31978621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VECS] = GEN6_NOSYNC;
31988621f407SFrançois Tigeot 			engine->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
319924edb884SFrançois Tigeot 		}
320024edb884SFrançois Tigeot 	}
32018621f407SFrançois Tigeot 	engine->init_hw = init_ring_common;
3202e3adcf8fSFrançois Tigeot 
32038621f407SFrançois Tigeot 	return intel_init_ring_buffer(dev, engine);
3204e3adcf8fSFrançois Tigeot }
3205b030f26bSFrançois Tigeot 
3206b030f26bSFrançois Tigeot int
3207a05eeebfSFrançois Tigeot intel_ring_flush_all_caches(struct drm_i915_gem_request *req)
3208b030f26bSFrançois Tigeot {
32098621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
3210b030f26bSFrançois Tigeot 	int ret;
3211b030f26bSFrançois Tigeot 
32128621f407SFrançois Tigeot 	if (!engine->gpu_caches_dirty)
3213b030f26bSFrançois Tigeot 		return 0;
3214b030f26bSFrançois Tigeot 
32158621f407SFrançois Tigeot 	ret = engine->flush(req, 0, I915_GEM_GPU_DOMAINS);
3216b030f26bSFrançois Tigeot 	if (ret)
3217b030f26bSFrançois Tigeot 		return ret;
3218b030f26bSFrançois Tigeot 
3219a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS);
3220a2fdbec6SFrançois Tigeot 
32218621f407SFrançois Tigeot 	engine->gpu_caches_dirty = false;
3222b030f26bSFrançois Tigeot 	return 0;
3223b030f26bSFrançois Tigeot }
3224b030f26bSFrançois Tigeot 
3225b030f26bSFrançois Tigeot int
3226a05eeebfSFrançois Tigeot intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
3227b030f26bSFrançois Tigeot {
32288621f407SFrançois Tigeot 	struct intel_engine_cs *engine = req->engine;
3229b030f26bSFrançois Tigeot 	uint32_t flush_domains;
3230b030f26bSFrançois Tigeot 	int ret;
3231b030f26bSFrançois Tigeot 
3232b030f26bSFrançois Tigeot 	flush_domains = 0;
32338621f407SFrançois Tigeot 	if (engine->gpu_caches_dirty)
3234b030f26bSFrançois Tigeot 		flush_domains = I915_GEM_GPU_DOMAINS;
3235b030f26bSFrançois Tigeot 
32368621f407SFrançois Tigeot 	ret = engine->flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
3237b030f26bSFrançois Tigeot 	if (ret)
3238b030f26bSFrançois Tigeot 		return ret;
3239b030f26bSFrançois Tigeot 
3240a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
3241a2fdbec6SFrançois Tigeot 
32428621f407SFrançois Tigeot 	engine->gpu_caches_dirty = false;
3243b030f26bSFrançois Tigeot 	return 0;
3244b030f26bSFrançois Tigeot }
3245ba55f2f5SFrançois Tigeot 
3246ba55f2f5SFrançois Tigeot void
32478621f407SFrançois Tigeot intel_stop_engine(struct intel_engine_cs *engine)
3248ba55f2f5SFrançois Tigeot {
3249ba55f2f5SFrançois Tigeot 	int ret;
3250ba55f2f5SFrançois Tigeot 
32518621f407SFrançois Tigeot 	if (!intel_engine_initialized(engine))
3252ba55f2f5SFrançois Tigeot 		return;
3253ba55f2f5SFrançois Tigeot 
32548621f407SFrançois Tigeot 	ret = intel_engine_idle(engine);
32558621f407SFrançois Tigeot 	if (ret)
3256ba55f2f5SFrançois Tigeot 		DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
32578621f407SFrançois Tigeot 			  engine->name, ret);
3258ba55f2f5SFrançois Tigeot 
32598621f407SFrançois Tigeot 	stop_ring(engine);
3260ba55f2f5SFrançois Tigeot }
3261