xref: /dflybsd-src/sys/dev/drm/i915/intel_ringbuffer.c (revision c0e85e96994c944a12cb708e4676eac8a306d23a)
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 
561b13d190SFrançois Tigeot int intel_ring_space(struct intel_ringbuffer *ringbuf)
57ba55f2f5SFrançois Tigeot {
582c9916cdSFrançois Tigeot 	intel_ring_update_space(ringbuf);
592c9916cdSFrançois Tigeot 	return ringbuf->space;
60ba55f2f5SFrançois Tigeot }
61ba55f2f5SFrançois Tigeot 
621b13d190SFrançois Tigeot bool intel_ring_stopped(struct intel_engine_cs *ring)
639edbd4a0SFrançois Tigeot {
649edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
65ba55f2f5SFrançois Tigeot 	return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring);
66ba55f2f5SFrançois Tigeot }
679edbd4a0SFrançois Tigeot 
68a05eeebfSFrançois Tigeot static void __intel_ring_advance(struct intel_engine_cs *ring)
69ba55f2f5SFrançois Tigeot {
70ba55f2f5SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = ring->buffer;
71ba55f2f5SFrançois Tigeot 	ringbuf->tail &= ringbuf->size - 1;
72ba55f2f5SFrançois Tigeot 	if (intel_ring_stopped(ring))
739edbd4a0SFrançois Tigeot 		return;
74ba55f2f5SFrançois Tigeot 	ring->write_tail(ring, ringbuf->tail);
759edbd4a0SFrançois Tigeot }
769edbd4a0SFrançois Tigeot 
77e3adcf8fSFrançois Tigeot static int
78a05eeebfSFrançois Tigeot gen2_render_ring_flush(struct drm_i915_gem_request *req,
79686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
80686a02f1SFrançois Tigeot 		       u32	flush_domains)
81686a02f1SFrançois Tigeot {
82a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
83686a02f1SFrançois Tigeot 	u32 cmd;
84686a02f1SFrançois Tigeot 	int ret;
85686a02f1SFrançois Tigeot 
86686a02f1SFrançois Tigeot 	cmd = MI_FLUSH;
87686a02f1SFrançois Tigeot 	if (((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER) == 0)
88686a02f1SFrançois Tigeot 		cmd |= MI_NO_WRITE_FLUSH;
89686a02f1SFrançois Tigeot 
90686a02f1SFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
91686a02f1SFrançois Tigeot 		cmd |= MI_READ_FLUSH;
92686a02f1SFrançois Tigeot 
93a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
94686a02f1SFrançois Tigeot 	if (ret)
95686a02f1SFrançois Tigeot 		return ret;
96686a02f1SFrançois Tigeot 
97686a02f1SFrançois Tigeot 	intel_ring_emit(ring, cmd);
98686a02f1SFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
99686a02f1SFrançois Tigeot 	intel_ring_advance(ring);
100686a02f1SFrançois Tigeot 
101686a02f1SFrançois Tigeot 	return 0;
102686a02f1SFrançois Tigeot }
103686a02f1SFrançois Tigeot 
104686a02f1SFrançois Tigeot static int
105a05eeebfSFrançois Tigeot gen4_render_ring_flush(struct drm_i915_gem_request *req,
106686a02f1SFrançois Tigeot 		       u32	invalidate_domains,
107686a02f1SFrançois Tigeot 		       u32	flush_domains)
108e3adcf8fSFrançois Tigeot {
109a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
110e3adcf8fSFrançois Tigeot 	struct drm_device *dev = ring->dev;
111686a02f1SFrançois Tigeot 	u32 cmd;
112e3adcf8fSFrançois Tigeot 	int ret;
113e3adcf8fSFrançois Tigeot 
114e3adcf8fSFrançois Tigeot 	/*
115e3adcf8fSFrançois Tigeot 	 * read/write caches:
116e3adcf8fSFrançois Tigeot 	 *
117e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER is always invalidated, but is
118e3adcf8fSFrançois Tigeot 	 * only flushed if MI_NO_WRITE_FLUSH is unset.  On 965, it is
119e3adcf8fSFrançois Tigeot 	 * also flushed at 2d versus 3d pipeline switches.
120e3adcf8fSFrançois Tigeot 	 *
121e3adcf8fSFrançois Tigeot 	 * read-only caches:
122e3adcf8fSFrançois Tigeot 	 *
123e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
124e3adcf8fSFrançois Tigeot 	 * MI_READ_FLUSH is set, and is always flushed on 965.
125e3adcf8fSFrançois Tigeot 	 *
126e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_COMMAND may not exist?
127e3adcf8fSFrançois Tigeot 	 *
128e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
129e3adcf8fSFrançois Tigeot 	 * invalidated when MI_EXE_FLUSH is set.
130e3adcf8fSFrançois Tigeot 	 *
131e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
132e3adcf8fSFrançois Tigeot 	 * invalidated with every MI_FLUSH.
133e3adcf8fSFrançois Tigeot 	 *
134e3adcf8fSFrançois Tigeot 	 * TLBs:
135e3adcf8fSFrançois Tigeot 	 *
136e3adcf8fSFrançois Tigeot 	 * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
137e3adcf8fSFrançois Tigeot 	 * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
138e3adcf8fSFrançois Tigeot 	 * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
139e3adcf8fSFrançois Tigeot 	 * are flushed at any MI_FLUSH.
140e3adcf8fSFrançois Tigeot 	 */
141e3adcf8fSFrançois Tigeot 
142e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
143686a02f1SFrançois Tigeot 	if ((invalidate_domains|flush_domains) & I915_GEM_DOMAIN_RENDER)
144e3adcf8fSFrançois Tigeot 		cmd &= ~MI_NO_WRITE_FLUSH;
145e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
146e3adcf8fSFrançois Tigeot 		cmd |= MI_EXE_FLUSH;
147e3adcf8fSFrançois Tigeot 
148e3adcf8fSFrançois Tigeot 	if (invalidate_domains & I915_GEM_DOMAIN_COMMAND &&
149e3adcf8fSFrançois Tigeot 	    (IS_G4X(dev) || IS_GEN5(dev)))
150e3adcf8fSFrançois Tigeot 		cmd |= MI_INVALIDATE_ISP;
151e3adcf8fSFrançois Tigeot 
152a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
153e3adcf8fSFrançois Tigeot 	if (ret)
154e3adcf8fSFrançois Tigeot 		return ret;
155e3adcf8fSFrançois Tigeot 
156e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, cmd);
157e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
158e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
159e3adcf8fSFrançois Tigeot 
160e3adcf8fSFrançois Tigeot 	return 0;
161e3adcf8fSFrançois Tigeot }
162e3adcf8fSFrançois Tigeot 
163e3adcf8fSFrançois Tigeot /**
164e3adcf8fSFrançois Tigeot  * Emits a PIPE_CONTROL with a non-zero post-sync operation, for
165e3adcf8fSFrançois Tigeot  * implementing two workarounds on gen6.  From section 1.4.7.1
166e3adcf8fSFrançois Tigeot  * "PIPE_CONTROL" of the Sandy Bridge PRM volume 2 part 1:
167e3adcf8fSFrançois Tigeot  *
168e3adcf8fSFrançois Tigeot  * [DevSNB-C+{W/A}] Before any depth stall flush (including those
169e3adcf8fSFrançois Tigeot  * produced by non-pipelined state commands), software needs to first
170e3adcf8fSFrançois Tigeot  * send a PIPE_CONTROL with no bits set except Post-Sync Operation !=
171e3adcf8fSFrançois Tigeot  * 0.
172e3adcf8fSFrançois Tigeot  *
173e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Before a PIPE_CONTROL with Write Cache Flush Enable
174e3adcf8fSFrançois Tigeot  * =1, a PIPE_CONTROL with any non-zero post-sync-op is required.
175e3adcf8fSFrançois Tigeot  *
176e3adcf8fSFrançois Tigeot  * And the workaround for these two requires this workaround first:
177e3adcf8fSFrançois Tigeot  *
178e3adcf8fSFrançois Tigeot  * [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
179e3adcf8fSFrançois Tigeot  * BEFORE the pipe-control with a post-sync op and no write-cache
180e3adcf8fSFrançois Tigeot  * flushes.
181e3adcf8fSFrançois Tigeot  *
182e3adcf8fSFrançois Tigeot  * And this last workaround is tricky because of the requirements on
183e3adcf8fSFrançois Tigeot  * that bit.  From section 1.4.7.2.3 "Stall" of the Sandy Bridge PRM
184e3adcf8fSFrançois Tigeot  * volume 2 part 1:
185e3adcf8fSFrançois Tigeot  *
186e3adcf8fSFrançois Tigeot  *     "1 of the following must also be set:
187e3adcf8fSFrançois Tigeot  *      - Render Target Cache Flush Enable ([12] of DW1)
188e3adcf8fSFrançois Tigeot  *      - Depth Cache Flush Enable ([0] of DW1)
189e3adcf8fSFrançois Tigeot  *      - Stall at Pixel Scoreboard ([1] of DW1)
190e3adcf8fSFrançois Tigeot  *      - Depth Stall ([13] of DW1)
191e3adcf8fSFrançois Tigeot  *      - Post-Sync Operation ([13] of DW1)
192e3adcf8fSFrançois Tigeot  *      - Notify Enable ([8] of DW1)"
193e3adcf8fSFrançois Tigeot  *
194e3adcf8fSFrançois Tigeot  * The cache flushes require the workaround flush that triggered this
195e3adcf8fSFrançois Tigeot  * one, so we can't use it.  Depth stall would trigger the same.
196e3adcf8fSFrançois Tigeot  * Post-sync nonzero is what triggered this second workaround, so we
197e3adcf8fSFrançois Tigeot  * can't use that one either.  Notify enable is IRQs, which aren't
198e3adcf8fSFrançois Tigeot  * really our business.  That leaves only stall at scoreboard.
199e3adcf8fSFrançois Tigeot  */
200e3adcf8fSFrançois Tigeot static int
201a05eeebfSFrançois Tigeot intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req)
202e3adcf8fSFrançois Tigeot {
203a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
204ba55f2f5SFrançois Tigeot 	u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
205e3adcf8fSFrançois Tigeot 	int ret;
206e3adcf8fSFrançois Tigeot 
207a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
208e3adcf8fSFrançois Tigeot 	if (ret)
209e3adcf8fSFrançois Tigeot 		return ret;
210e3adcf8fSFrançois Tigeot 
211e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(5));
212e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, PIPE_CONTROL_CS_STALL |
213e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_STALL_AT_SCOREBOARD);
214e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
215e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, 0); /* low dword */
216e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, 0); /* high dword */
217e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
218e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
219e3adcf8fSFrançois Tigeot 
220a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
221e3adcf8fSFrançois Tigeot 	if (ret)
222e3adcf8fSFrançois Tigeot 		return ret;
223e3adcf8fSFrançois Tigeot 
224e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(5));
225e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, PIPE_CONTROL_QW_WRITE);
226e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT); /* address */
227e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, 0);
228e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, 0);
229e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
230e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
231e3adcf8fSFrançois Tigeot 
232e3adcf8fSFrançois Tigeot 	return 0;
233e3adcf8fSFrançois Tigeot }
234e3adcf8fSFrançois Tigeot 
235e3adcf8fSFrançois Tigeot static int
236a05eeebfSFrançois Tigeot gen6_render_ring_flush(struct drm_i915_gem_request *req,
237e3adcf8fSFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
238e3adcf8fSFrançois Tigeot {
239a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
240e3adcf8fSFrançois Tigeot 	u32 flags = 0;
241ba55f2f5SFrançois Tigeot 	u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
242e3adcf8fSFrançois Tigeot 	int ret;
243e3adcf8fSFrançois Tigeot 
244e3adcf8fSFrançois Tigeot 	/* Force SNB workarounds for PIPE_CONTROL flushes */
245a05eeebfSFrançois Tigeot 	ret = intel_emit_post_sync_nonzero_flush(req);
246686a02f1SFrançois Tigeot 	if (ret)
247686a02f1SFrançois Tigeot 		return ret;
248e3adcf8fSFrançois Tigeot 
249e3adcf8fSFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
250e3adcf8fSFrançois Tigeot 	 * number of bits based on the write domains has little performance
251e3adcf8fSFrançois Tigeot 	 * impact.
252e3adcf8fSFrançois Tigeot 	 */
253b5c29a34SFrançois Tigeot 	if (flush_domains) {
254e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
255b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
256b5c29a34SFrançois Tigeot 		/*
257b5c29a34SFrançois Tigeot 		 * Ensure that any following seqno writes only happen
258b5c29a34SFrançois Tigeot 		 * when the render cache is indeed flushed.
259b5c29a34SFrançois Tigeot 		 */
260b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CS_STALL;
261b5c29a34SFrançois Tigeot 	}
262b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
263686a02f1SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
264e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
265e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
266e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
267e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
268e3adcf8fSFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
269686a02f1SFrançois Tigeot 		/*
270b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
271686a02f1SFrançois Tigeot 		 */
272b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL;
273b5c29a34SFrançois Tigeot 	}
274e3adcf8fSFrançois Tigeot 
275a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
276e3adcf8fSFrançois Tigeot 	if (ret)
277e3adcf8fSFrançois Tigeot 		return ret;
278e3adcf8fSFrançois Tigeot 
279b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
280e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, flags);
281e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
282b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, 0);
283b5c29a34SFrançois Tigeot 	intel_ring_advance(ring);
284b5c29a34SFrançois Tigeot 
285b5c29a34SFrançois Tigeot 	return 0;
286b5c29a34SFrançois Tigeot }
287b5c29a34SFrançois Tigeot 
288b5c29a34SFrançois Tigeot static int
289a05eeebfSFrançois Tigeot gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req)
290b5c29a34SFrançois Tigeot {
291a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
292b5c29a34SFrançois Tigeot 	int ret;
293b5c29a34SFrançois Tigeot 
294a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
295b5c29a34SFrançois Tigeot 	if (ret)
296b5c29a34SFrançois Tigeot 		return ret;
297b5c29a34SFrançois Tigeot 
298b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
299b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, PIPE_CONTROL_CS_STALL |
300b5c29a34SFrançois Tigeot 			      PIPE_CONTROL_STALL_AT_SCOREBOARD);
301b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, 0);
302b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, 0);
303b5c29a34SFrançois Tigeot 	intel_ring_advance(ring);
304b5c29a34SFrançois Tigeot 
305b5c29a34SFrançois Tigeot 	return 0;
306b5c29a34SFrançois Tigeot }
307b5c29a34SFrançois Tigeot 
308b5c29a34SFrançois Tigeot static int
309a05eeebfSFrançois Tigeot gen7_render_ring_flush(struct drm_i915_gem_request *req,
310b5c29a34SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
311b5c29a34SFrançois Tigeot {
312a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
313b5c29a34SFrançois Tigeot 	u32 flags = 0;
314ba55f2f5SFrançois Tigeot 	u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
315b5c29a34SFrançois Tigeot 	int ret;
316b5c29a34SFrançois Tigeot 
317b5c29a34SFrançois Tigeot 	/*
318b5c29a34SFrançois Tigeot 	 * Ensure that any following seqno writes only happen when the render
319b5c29a34SFrançois Tigeot 	 * cache is indeed flushed.
320b5c29a34SFrançois Tigeot 	 *
321b5c29a34SFrançois Tigeot 	 * Workaround: 4th PIPE_CONTROL command (except the ones with only
322b5c29a34SFrançois Tigeot 	 * read-cache invalidate bits set) must have the CS_STALL bit set. We
323b5c29a34SFrançois Tigeot 	 * don't try to be clever and just set it unconditionally.
324b5c29a34SFrançois Tigeot 	 */
325b5c29a34SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
326b5c29a34SFrançois Tigeot 
327b5c29a34SFrançois Tigeot 	/* Just flush everything.  Experiments have shown that reducing the
328b5c29a34SFrançois Tigeot 	 * number of bits based on the write domains has little performance
329b5c29a34SFrançois Tigeot 	 * impact.
330b5c29a34SFrançois Tigeot 	 */
331b5c29a34SFrançois Tigeot 	if (flush_domains) {
332b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
333b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
334aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
335b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
336b5c29a34SFrançois Tigeot 	}
337b5c29a34SFrançois Tigeot 	if (invalidate_domains) {
338b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
339b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
340b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
341b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
342b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
343b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
3442c9916cdSFrançois Tigeot 		flags |= PIPE_CONTROL_MEDIA_STATE_CLEAR;
345b5c29a34SFrançois Tigeot 		/*
346b5c29a34SFrançois Tigeot 		 * TLB invalidate requires a post-sync write.
347b5c29a34SFrançois Tigeot 		 */
348b5c29a34SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
349a2fdbec6SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
350b5c29a34SFrançois Tigeot 
3510dbf0ea8SMatthew Dillon 		flags |= PIPE_CONTROL_STALL_AT_SCOREBOARD;
3520dbf0ea8SMatthew Dillon 
353b5c29a34SFrançois Tigeot 		/* Workaround: we must issue a pipe_control with CS-stall bit
354b5c29a34SFrançois Tigeot 		 * set before a pipe_control command that has the state cache
355b5c29a34SFrançois Tigeot 		 * invalidate bit set. */
356a05eeebfSFrançois Tigeot 		gen7_render_ring_cs_stall_wa(req);
357b5c29a34SFrançois Tigeot 	}
358b5c29a34SFrançois Tigeot 
359a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
360b5c29a34SFrançois Tigeot 	if (ret)
361b5c29a34SFrançois Tigeot 		return ret;
362b5c29a34SFrançois Tigeot 
363b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
364b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, flags);
365a2fdbec6SFrançois Tigeot 	intel_ring_emit(ring, scratch_addr);
366b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, 0);
367e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
368e3adcf8fSFrançois Tigeot 
369e3adcf8fSFrançois Tigeot 	return 0;
370e3adcf8fSFrançois Tigeot }
371e3adcf8fSFrançois Tigeot 
3729edbd4a0SFrançois Tigeot static int
373a05eeebfSFrançois Tigeot gen8_emit_pipe_control(struct drm_i915_gem_request *req,
37424edb884SFrançois Tigeot 		       u32 flags, u32 scratch_addr)
37524edb884SFrançois Tigeot {
376a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
37724edb884SFrançois Tigeot 	int ret;
37824edb884SFrançois Tigeot 
379a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
38024edb884SFrançois Tigeot 	if (ret)
38124edb884SFrançois Tigeot 		return ret;
38224edb884SFrançois Tigeot 
38324edb884SFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(6));
38424edb884SFrançois Tigeot 	intel_ring_emit(ring, flags);
38524edb884SFrançois Tigeot 	intel_ring_emit(ring, scratch_addr);
38624edb884SFrançois Tigeot 	intel_ring_emit(ring, 0);
38724edb884SFrançois Tigeot 	intel_ring_emit(ring, 0);
38824edb884SFrançois Tigeot 	intel_ring_emit(ring, 0);
38924edb884SFrançois Tigeot 	intel_ring_advance(ring);
39024edb884SFrançois Tigeot 
39124edb884SFrançois Tigeot 	return 0;
39224edb884SFrançois Tigeot }
39324edb884SFrançois Tigeot 
39424edb884SFrançois Tigeot static int
395a05eeebfSFrançois Tigeot gen8_render_ring_flush(struct drm_i915_gem_request *req,
3969edbd4a0SFrançois Tigeot 		       u32 invalidate_domains, u32 flush_domains)
3979edbd4a0SFrançois Tigeot {
3989edbd4a0SFrançois Tigeot 	u32 flags = 0;
399a05eeebfSFrançois Tigeot 	u32 scratch_addr = req->ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
4009edbd4a0SFrançois Tigeot 	int ret;
4019edbd4a0SFrançois Tigeot 
4029edbd4a0SFrançois Tigeot 	flags |= PIPE_CONTROL_CS_STALL;
4039edbd4a0SFrançois Tigeot 
4049edbd4a0SFrançois Tigeot 	if (flush_domains) {
4059edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
4069edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
407aee94f86SFrançois Tigeot 		flags |= PIPE_CONTROL_DC_FLUSH_ENABLE;
408b49c8cf9SFrançois Tigeot 		flags |= PIPE_CONTROL_FLUSH_ENABLE;
4099edbd4a0SFrançois Tigeot 	}
4109edbd4a0SFrançois Tigeot 	if (invalidate_domains) {
4119edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TLB_INVALIDATE;
4129edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
4139edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
4149edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
4159edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
4169edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
4179edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_QW_WRITE;
4189edbd4a0SFrançois Tigeot 		flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
4199edbd4a0SFrançois Tigeot 
42024edb884SFrançois Tigeot 		/* WaCsStallBeforeStateCacheInvalidate:bdw,chv */
421a05eeebfSFrançois Tigeot 		ret = gen8_emit_pipe_control(req,
42224edb884SFrançois Tigeot 					     PIPE_CONTROL_CS_STALL |
42324edb884SFrançois Tigeot 					     PIPE_CONTROL_STALL_AT_SCOREBOARD,
42424edb884SFrançois Tigeot 					     0);
4259edbd4a0SFrançois Tigeot 		if (ret)
4269edbd4a0SFrançois Tigeot 			return ret;
42724edb884SFrançois Tigeot 	}
4289edbd4a0SFrançois Tigeot 
429a05eeebfSFrançois Tigeot 	return gen8_emit_pipe_control(req, flags, scratch_addr);
4309edbd4a0SFrançois Tigeot }
4319edbd4a0SFrançois Tigeot 
432ba55f2f5SFrançois Tigeot static void ring_write_tail(struct intel_engine_cs *ring,
433b5c29a34SFrançois Tigeot 			    u32 value)
434e3adcf8fSFrançois Tigeot {
435ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
436e3adcf8fSFrançois Tigeot 	I915_WRITE_TAIL(ring, value);
437e3adcf8fSFrançois Tigeot }
438e3adcf8fSFrançois Tigeot 
439ba55f2f5SFrançois Tigeot u64 intel_ring_get_active_head(struct intel_engine_cs *ring)
440e3adcf8fSFrançois Tigeot {
441ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
442ba55f2f5SFrançois Tigeot 	u64 acthd;
443e3adcf8fSFrançois Tigeot 
444ba55f2f5SFrançois Tigeot 	if (INTEL_INFO(ring->dev)->gen >= 8)
445ba55f2f5SFrançois Tigeot 		acthd = I915_READ64_2x32(RING_ACTHD(ring->mmio_base),
446ba55f2f5SFrançois Tigeot 					 RING_ACTHD_UDW(ring->mmio_base));
447ba55f2f5SFrançois Tigeot 	else if (INTEL_INFO(ring->dev)->gen >= 4)
448ba55f2f5SFrançois Tigeot 		acthd = I915_READ(RING_ACTHD(ring->mmio_base));
449ba55f2f5SFrançois Tigeot 	else
450ba55f2f5SFrançois Tigeot 		acthd = I915_READ(ACTHD);
451ba55f2f5SFrançois Tigeot 
452ba55f2f5SFrançois Tigeot 	return acthd;
453e3adcf8fSFrançois Tigeot }
454e3adcf8fSFrançois Tigeot 
455ba55f2f5SFrançois Tigeot static void ring_setup_phys_status_page(struct intel_engine_cs *ring)
4565d0b1887SFrançois Tigeot {
4575d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
4585d0b1887SFrançois Tigeot 	u32 addr;
4595d0b1887SFrançois Tigeot 
4605d0b1887SFrançois Tigeot 	addr = dev_priv->status_page_dmah->busaddr;
4615d0b1887SFrançois Tigeot 	if (INTEL_INFO(ring->dev)->gen >= 4)
4625d0b1887SFrançois Tigeot 		addr |= (dev_priv->status_page_dmah->busaddr >> 28) & 0xf0;
4635d0b1887SFrançois Tigeot 	I915_WRITE(HWS_PGA, addr);
4645d0b1887SFrançois Tigeot }
4655d0b1887SFrançois Tigeot 
466477eb7f9SFrançois Tigeot static void intel_ring_setup_status_page(struct intel_engine_cs *ring)
467477eb7f9SFrançois Tigeot {
468477eb7f9SFrançois Tigeot 	struct drm_device *dev = ring->dev;
469477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
470aee94f86SFrançois Tigeot 	i915_reg_t mmio;
471477eb7f9SFrançois Tigeot 
472477eb7f9SFrançois Tigeot 	/* The ring status page addresses are no longer next to the rest of
473477eb7f9SFrançois Tigeot 	 * the ring registers as of gen7.
474477eb7f9SFrançois Tigeot 	 */
475477eb7f9SFrançois Tigeot 	if (IS_GEN7(dev)) {
476477eb7f9SFrançois Tigeot 		switch (ring->id) {
477477eb7f9SFrançois Tigeot 		case RCS:
478477eb7f9SFrançois Tigeot 			mmio = RENDER_HWS_PGA_GEN7;
479477eb7f9SFrançois Tigeot 			break;
480477eb7f9SFrançois Tigeot 		case BCS:
481477eb7f9SFrançois Tigeot 			mmio = BLT_HWS_PGA_GEN7;
482477eb7f9SFrançois Tigeot 			break;
483477eb7f9SFrançois Tigeot 		/*
484477eb7f9SFrançois Tigeot 		 * VCS2 actually doesn't exist on Gen7. Only shut up
485477eb7f9SFrançois Tigeot 		 * gcc switch check warning
486477eb7f9SFrançois Tigeot 		 */
487477eb7f9SFrançois Tigeot 		case VCS2:
488477eb7f9SFrançois Tigeot 		case VCS:
489477eb7f9SFrançois Tigeot 			mmio = BSD_HWS_PGA_GEN7;
490477eb7f9SFrançois Tigeot 			break;
491477eb7f9SFrançois Tigeot 		case VECS:
492477eb7f9SFrançois Tigeot 			mmio = VEBOX_HWS_PGA_GEN7;
493477eb7f9SFrançois Tigeot 			break;
494477eb7f9SFrançois Tigeot 		}
495477eb7f9SFrançois Tigeot 	} else if (IS_GEN6(ring->dev)) {
496477eb7f9SFrançois Tigeot 		mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
497477eb7f9SFrançois Tigeot 	} else {
498477eb7f9SFrançois Tigeot 		/* XXX: gen8 returns to sanity */
499477eb7f9SFrançois Tigeot 		mmio = RING_HWS_PGA(ring->mmio_base);
500477eb7f9SFrançois Tigeot 	}
501477eb7f9SFrançois Tigeot 
502477eb7f9SFrançois Tigeot 	I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
503477eb7f9SFrançois Tigeot 	POSTING_READ(mmio);
504477eb7f9SFrançois Tigeot 
505477eb7f9SFrançois Tigeot 	/*
506477eb7f9SFrançois Tigeot 	 * Flush the TLB for this page
507477eb7f9SFrançois Tigeot 	 *
508477eb7f9SFrançois Tigeot 	 * FIXME: These two bits have disappeared on gen8, so a question
509477eb7f9SFrançois Tigeot 	 * arises: do we still need this and if so how should we go about
510477eb7f9SFrançois Tigeot 	 * invalidating the TLB?
511477eb7f9SFrançois Tigeot 	 */
512477eb7f9SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
513aee94f86SFrançois Tigeot 		i915_reg_t reg = RING_INSTPM(ring->mmio_base);
514477eb7f9SFrançois Tigeot 
515477eb7f9SFrançois Tigeot 		/* ring should be idle before issuing a sync flush*/
516477eb7f9SFrançois Tigeot 		WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
517477eb7f9SFrançois Tigeot 
518477eb7f9SFrançois Tigeot 		I915_WRITE(reg,
519477eb7f9SFrançois Tigeot 			   _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
520477eb7f9SFrançois Tigeot 					      INSTPM_SYNC_FLUSH));
521477eb7f9SFrançois Tigeot 		if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0,
522477eb7f9SFrançois Tigeot 			     1000))
523477eb7f9SFrançois Tigeot 			DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n",
524477eb7f9SFrançois Tigeot 				  ring->name);
525477eb7f9SFrançois Tigeot 	}
526477eb7f9SFrançois Tigeot }
527477eb7f9SFrançois Tigeot 
528ba55f2f5SFrançois Tigeot static bool stop_ring(struct intel_engine_cs *ring)
529e3adcf8fSFrançois Tigeot {
530ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(ring->dev);
531e3adcf8fSFrançois Tigeot 
532ba55f2f5SFrançois Tigeot 	if (!IS_GEN2(ring->dev)) {
533ba55f2f5SFrançois Tigeot 		I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
5341b13d190SFrançois Tigeot 		if (wait_for((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
535ba55f2f5SFrançois Tigeot 			DRM_ERROR("%s : timed out trying to stop ring\n", ring->name);
5361b13d190SFrançois Tigeot 			/* Sometimes we observe that the idle flag is not
5371b13d190SFrançois Tigeot 			 * set even though the ring is empty. So double
5381b13d190SFrançois Tigeot 			 * check before giving up.
5391b13d190SFrançois Tigeot 			 */
5401b13d190SFrançois Tigeot 			if (I915_READ_HEAD(ring) != I915_READ_TAIL(ring))
541ba55f2f5SFrançois Tigeot 				return false;
542ba55f2f5SFrançois Tigeot 		}
543ba55f2f5SFrançois Tigeot 	}
544686a02f1SFrançois Tigeot 
545e3adcf8fSFrançois Tigeot 	I915_WRITE_CTL(ring, 0);
546e3adcf8fSFrançois Tigeot 	I915_WRITE_HEAD(ring, 0);
547e3adcf8fSFrançois Tigeot 	ring->write_tail(ring, 0);
548e3adcf8fSFrançois Tigeot 
549ba55f2f5SFrançois Tigeot 	if (!IS_GEN2(ring->dev)) {
550ba55f2f5SFrançois Tigeot 		(void)I915_READ_CTL(ring);
551ba55f2f5SFrançois Tigeot 		I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
552ba55f2f5SFrançois Tigeot 	}
553e3adcf8fSFrançois Tigeot 
554ba55f2f5SFrançois Tigeot 	return (I915_READ_HEAD(ring) & HEAD_ADDR) == 0;
555ba55f2f5SFrançois Tigeot }
556ba55f2f5SFrançois Tigeot 
557ba55f2f5SFrançois Tigeot static int init_ring_common(struct intel_engine_cs *ring)
558ba55f2f5SFrançois Tigeot {
559ba55f2f5SFrançois Tigeot 	struct drm_device *dev = ring->dev;
560ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
561ba55f2f5SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = ring->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 
567ba55f2f5SFrançois Tigeot 	if (!stop_ring(ring)) {
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",
571e3adcf8fSFrançois Tigeot 			      ring->name,
572e3adcf8fSFrançois Tigeot 			      I915_READ_CTL(ring),
573e3adcf8fSFrançois Tigeot 			      I915_READ_HEAD(ring),
574e3adcf8fSFrançois Tigeot 			      I915_READ_TAIL(ring),
575e3adcf8fSFrançois Tigeot 			      I915_READ_START(ring));
576e3adcf8fSFrançois Tigeot 
577ba55f2f5SFrançois Tigeot 		if (!stop_ring(ring)) {
578e3adcf8fSFrançois Tigeot 			DRM_ERROR("failed to set %s head to zero "
579e3adcf8fSFrançois Tigeot 				  "ctl %08x head %08x tail %08x start %08x\n",
580e3adcf8fSFrançois Tigeot 				  ring->name,
581e3adcf8fSFrançois Tigeot 				  I915_READ_CTL(ring),
582e3adcf8fSFrançois Tigeot 				  I915_READ_HEAD(ring),
583e3adcf8fSFrançois Tigeot 				  I915_READ_TAIL(ring),
584e3adcf8fSFrançois Tigeot 				  I915_READ_START(ring));
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))
591ba55f2f5SFrançois Tigeot 		intel_ring_setup_status_page(ring);
592ba55f2f5SFrançois Tigeot 	else
593ba55f2f5SFrançois Tigeot 		ring_setup_phys_status_page(ring);
594ba55f2f5SFrançois Tigeot 
5950f370975SMatthew Dillon 	/* Enforce ordering by reading HEAD register back */
5960f370975SMatthew Dillon 	I915_READ_HEAD(ring);
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. */
602ba55f2f5SFrançois Tigeot 	I915_WRITE_START(ring, i915_gem_obj_ggtt_offset(obj));
6031b13d190SFrançois Tigeot 
6041b13d190SFrançois Tigeot 	/* WaClearRingBufHeadRegAtInit:ctg,elk */
6051b13d190SFrançois Tigeot 	if (I915_READ_HEAD(ring))
6061b13d190SFrançois Tigeot 		DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
6071b13d190SFrançois Tigeot 			  ring->name, I915_READ_HEAD(ring));
6081b13d190SFrançois Tigeot 	I915_WRITE_HEAD(ring, 0);
6091b13d190SFrançois Tigeot 	(void)I915_READ_HEAD(ring);
6101b13d190SFrançois Tigeot 
611ba55f2f5SFrançois Tigeot 	I915_WRITE_CTL(ring,
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 */
616ba55f2f5SFrançois Tigeot 	if (wait_for((I915_READ_CTL(ring) & RING_VALID) != 0 &&
617ba55f2f5SFrançois Tigeot 		     I915_READ_START(ring) == i915_gem_obj_ggtt_offset(obj) &&
618ba55f2f5SFrançois Tigeot 		     (I915_READ_HEAD(ring) & 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",
621ba55f2f5SFrançois Tigeot 			  ring->name,
622ba55f2f5SFrançois Tigeot 			  I915_READ_CTL(ring), I915_READ_CTL(ring) & RING_VALID,
623ba55f2f5SFrançois Tigeot 			  I915_READ_HEAD(ring), I915_READ_TAIL(ring),
624ba55f2f5SFrançois Tigeot 			  I915_READ_START(ring), (unsigned long)i915_gem_obj_ggtt_offset(obj));
625ba55f2f5SFrançois Tigeot 		ret = -EIO;
626ba55f2f5SFrançois Tigeot 		goto out;
627ba55f2f5SFrançois Tigeot 	}
628e3adcf8fSFrançois Tigeot 
6292c9916cdSFrançois Tigeot 	ringbuf->last_retired_head = -1;
630ba55f2f5SFrançois Tigeot 	ringbuf->head = I915_READ_HEAD(ring);
631ba55f2f5SFrançois Tigeot 	ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
6322c9916cdSFrançois Tigeot 	intel_ring_update_space(ringbuf);
633e3adcf8fSFrançois Tigeot 
6345d0b1887SFrançois Tigeot 	memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
6355d0b1887SFrançois Tigeot 
636686a02f1SFrançois Tigeot out:
6372c9916cdSFrançois Tigeot 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
638686a02f1SFrançois Tigeot 
639686a02f1SFrançois Tigeot 	return ret;
640e3adcf8fSFrançois Tigeot }
641e3adcf8fSFrançois Tigeot 
6421b13d190SFrançois Tigeot void
6431b13d190SFrançois Tigeot intel_fini_pipe_control(struct intel_engine_cs *ring)
6441b13d190SFrançois Tigeot {
6451b13d190SFrançois Tigeot 	struct drm_device *dev = ring->dev;
6461b13d190SFrançois Tigeot 
6471b13d190SFrançois Tigeot 	if (ring->scratch.obj == NULL)
6481b13d190SFrançois Tigeot 		return;
6491b13d190SFrançois Tigeot 
6501b13d190SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 5) {
6517ec9f8e5SFrançois Tigeot 		kunmap(sg_page(ring->scratch.obj->pages->sgl));
6521b13d190SFrançois Tigeot 		i915_gem_object_ggtt_unpin(ring->scratch.obj);
6531b13d190SFrançois Tigeot 	}
6541b13d190SFrançois Tigeot 
6551b13d190SFrançois Tigeot 	drm_gem_object_unreference(&ring->scratch.obj->base);
6561b13d190SFrançois Tigeot 	ring->scratch.obj = NULL;
6571b13d190SFrançois Tigeot }
6581b13d190SFrançois Tigeot 
6591b13d190SFrançois Tigeot int
6601b13d190SFrançois Tigeot intel_init_pipe_control(struct intel_engine_cs *ring)
661e3adcf8fSFrançois Tigeot {
662e3adcf8fSFrançois Tigeot 	int ret;
663e3adcf8fSFrançois Tigeot 
6642c9916cdSFrançois Tigeot 	WARN_ON(ring->scratch.obj);
665e3adcf8fSFrançois Tigeot 
6669edbd4a0SFrançois Tigeot 	ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096);
6679edbd4a0SFrançois Tigeot 	if (ring->scratch.obj == NULL) {
668e3adcf8fSFrançois Tigeot 		DRM_ERROR("Failed to allocate seqno page\n");
669e3adcf8fSFrançois Tigeot 		ret = -ENOMEM;
670e3adcf8fSFrançois Tigeot 		goto err;
671e3adcf8fSFrançois Tigeot 	}
672e3adcf8fSFrançois Tigeot 
673ba55f2f5SFrançois Tigeot 	ret = i915_gem_object_set_cache_level(ring->scratch.obj, I915_CACHE_LLC);
674ba55f2f5SFrançois Tigeot 	if (ret)
675ba55f2f5SFrançois Tigeot 		goto err_unref;
676e3adcf8fSFrançois Tigeot 
677ba55f2f5SFrançois Tigeot 	ret = i915_gem_obj_ggtt_pin(ring->scratch.obj, 4096, 0);
678e3adcf8fSFrançois Tigeot 	if (ret)
679e3adcf8fSFrançois Tigeot 		goto err_unref;
680e3adcf8fSFrançois Tigeot 
6819edbd4a0SFrançois Tigeot 	ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(ring->scratch.obj);
6827ec9f8e5SFrançois Tigeot 	ring->scratch.cpu_page = kmap(sg_page(ring->scratch.obj->pages->sgl));
6839edbd4a0SFrançois Tigeot 	if (ring->scratch.cpu_page == NULL) {
6845d0b1887SFrançois Tigeot 		ret = -ENOMEM;
685e3adcf8fSFrançois Tigeot 		goto err_unpin;
6865d0b1887SFrançois Tigeot 	}
687a2fdbec6SFrançois Tigeot 
688a2fdbec6SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
6899edbd4a0SFrançois Tigeot 			 ring->name, ring->scratch.gtt_offset);
690e3adcf8fSFrançois Tigeot 	return 0;
691e3adcf8fSFrançois Tigeot 
692e3adcf8fSFrançois Tigeot err_unpin:
693ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(ring->scratch.obj);
694e3adcf8fSFrançois Tigeot err_unref:
6959edbd4a0SFrançois Tigeot 	drm_gem_object_unreference(&ring->scratch.obj->base);
696e3adcf8fSFrançois Tigeot err:
697e3adcf8fSFrançois Tigeot 	return ret;
698e3adcf8fSFrançois Tigeot }
699e3adcf8fSFrançois Tigeot 
700a05eeebfSFrançois Tigeot static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
7011b13d190SFrançois Tigeot {
7022c9916cdSFrançois Tigeot 	int ret, i;
703a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
7041b13d190SFrançois Tigeot 	struct drm_device *dev = ring->dev;
7051b13d190SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
7062c9916cdSFrançois Tigeot 	struct i915_workarounds *w = &dev_priv->workarounds;
7071b13d190SFrançois Tigeot 
708352ff8bdSFrançois Tigeot 	if (w->count == 0)
7092c9916cdSFrançois Tigeot 		return 0;
7101b13d190SFrançois Tigeot 
7112c9916cdSFrançois Tigeot 	ring->gpu_caches_dirty = true;
712a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7131b13d190SFrançois Tigeot 	if (ret)
7141b13d190SFrançois Tigeot 		return ret;
7151b13d190SFrançois Tigeot 
716a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, (w->count * 2 + 2));
7172c9916cdSFrançois Tigeot 	if (ret)
7182c9916cdSFrançois Tigeot 		return ret;
7192c9916cdSFrançois Tigeot 
7202c9916cdSFrançois Tigeot 	intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count));
7212c9916cdSFrançois Tigeot 	for (i = 0; i < w->count; i++) {
722aee94f86SFrançois Tigeot 		intel_ring_emit_reg(ring, w->reg[i].addr);
7232c9916cdSFrançois Tigeot 		intel_ring_emit(ring, w->reg[i].value);
7242c9916cdSFrançois Tigeot 	}
7252c9916cdSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
7262c9916cdSFrançois Tigeot 
7272c9916cdSFrançois Tigeot 	intel_ring_advance(ring);
7282c9916cdSFrançois Tigeot 
7292c9916cdSFrançois Tigeot 	ring->gpu_caches_dirty = true;
730a05eeebfSFrançois Tigeot 	ret = intel_ring_flush_all_caches(req);
7312c9916cdSFrançois Tigeot 	if (ret)
7322c9916cdSFrançois Tigeot 		return ret;
7332c9916cdSFrançois Tigeot 
7342c9916cdSFrançois Tigeot 	DRM_DEBUG_DRIVER("Number of Workarounds emitted: %d\n", w->count);
7352c9916cdSFrançois Tigeot 
7362c9916cdSFrançois Tigeot 	return 0;
7372c9916cdSFrançois Tigeot }
7382c9916cdSFrançois Tigeot 
739a05eeebfSFrançois Tigeot static int intel_rcs_ctx_init(struct drm_i915_gem_request *req)
7402c9916cdSFrançois Tigeot {
7412c9916cdSFrançois Tigeot 	int ret;
7422c9916cdSFrançois Tigeot 
743a05eeebfSFrançois Tigeot 	ret = intel_ring_workarounds_emit(req);
7442c9916cdSFrançois Tigeot 	if (ret != 0)
7452c9916cdSFrançois Tigeot 		return ret;
7462c9916cdSFrançois Tigeot 
747a05eeebfSFrançois Tigeot 	ret = i915_gem_render_state_init(req);
7482c9916cdSFrançois Tigeot 	if (ret)
7492c9916cdSFrançois Tigeot 		return ret;
750*c0e85e96SFrançois Tigeot 
751*c0e85e96SFrançois Tigeot 	return 0;
7522c9916cdSFrançois Tigeot }
7532c9916cdSFrançois Tigeot 
7542c9916cdSFrançois Tigeot static int wa_add(struct drm_i915_private *dev_priv,
755aee94f86SFrançois Tigeot 		  i915_reg_t addr,
756aee94f86SFrançois Tigeot 		  const u32 mask, const u32 val)
7572c9916cdSFrançois Tigeot {
7582c9916cdSFrançois Tigeot 	const u32 idx = dev_priv->workarounds.count;
7592c9916cdSFrançois Tigeot 
7602c9916cdSFrançois Tigeot 	if (WARN_ON(idx >= I915_MAX_WA_REGS))
7612c9916cdSFrançois Tigeot 		return -ENOSPC;
7622c9916cdSFrançois Tigeot 
7632c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].addr = addr;
7642c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].value = val;
7652c9916cdSFrançois Tigeot 	dev_priv->workarounds.reg[idx].mask = mask;
7662c9916cdSFrançois Tigeot 
7672c9916cdSFrançois Tigeot 	dev_priv->workarounds.count++;
7682c9916cdSFrançois Tigeot 
7692c9916cdSFrançois Tigeot 	return 0;
7702c9916cdSFrançois Tigeot }
7712c9916cdSFrançois Tigeot 
772a05eeebfSFrançois Tigeot #define WA_REG(addr, mask, val) do { \
7732c9916cdSFrançois Tigeot 		const int r = wa_add(dev_priv, (addr), (mask), (val)); \
7742c9916cdSFrançois Tigeot 		if (r) \
7752c9916cdSFrançois Tigeot 			return r; \
776a05eeebfSFrançois Tigeot 	} while (0)
7772c9916cdSFrançois Tigeot 
7782c9916cdSFrançois Tigeot #define WA_SET_BIT_MASKED(addr, mask) \
7792c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_ENABLE(mask))
7802c9916cdSFrançois Tigeot 
7812c9916cdSFrançois Tigeot #define WA_CLR_BIT_MASKED(addr, mask) \
7822c9916cdSFrançois Tigeot 	WA_REG(addr, (mask), _MASKED_BIT_DISABLE(mask))
7832c9916cdSFrançois Tigeot 
7842c9916cdSFrançois Tigeot #define WA_SET_FIELD_MASKED(addr, mask, value) \
7852c9916cdSFrançois Tigeot 	WA_REG(addr, mask, _MASKED_FIELD(mask, value))
7862c9916cdSFrançois Tigeot 
7872c9916cdSFrançois Tigeot #define WA_SET_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) | (mask))
7882c9916cdSFrançois Tigeot #define WA_CLR_BIT(addr, mask) WA_REG(addr, mask, I915_READ(addr) & ~(mask))
7892c9916cdSFrançois Tigeot 
7902c9916cdSFrançois Tigeot #define WA_WRITE(addr, val) WA_REG(addr, 0xffffffff, val)
7912c9916cdSFrançois Tigeot 
792*c0e85e96SFrançois Tigeot static int wa_ring_whitelist_reg(struct intel_engine_cs *ring, i915_reg_t reg)
793*c0e85e96SFrançois Tigeot {
794*c0e85e96SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
795*c0e85e96SFrançois Tigeot 	struct i915_workarounds *wa = &dev_priv->workarounds;
796*c0e85e96SFrançois Tigeot 	const uint32_t index = wa->hw_whitelist_count[ring->id];
797*c0e85e96SFrançois Tigeot 
798*c0e85e96SFrançois Tigeot 	if (WARN_ON(index >= RING_MAX_NONPRIV_SLOTS))
799*c0e85e96SFrançois Tigeot 		return -EINVAL;
800*c0e85e96SFrançois Tigeot 
801*c0e85e96SFrançois Tigeot 	WA_WRITE(RING_FORCE_TO_NONPRIV(ring->mmio_base, index),
802*c0e85e96SFrançois Tigeot 		 i915_mmio_reg_offset(reg));
803*c0e85e96SFrançois Tigeot 	wa->hw_whitelist_count[ring->id]++;
804*c0e85e96SFrançois Tigeot 
805*c0e85e96SFrançois Tigeot 	return 0;
806*c0e85e96SFrançois Tigeot }
807*c0e85e96SFrançois Tigeot 
808352ff8bdSFrançois Tigeot static int gen8_init_workarounds(struct intel_engine_cs *ring)
8092c9916cdSFrançois Tigeot {
8102c9916cdSFrançois Tigeot 	struct drm_device *dev = ring->dev;
8112c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
8122c9916cdSFrançois Tigeot 
813a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING);
814a05eeebfSFrançois Tigeot 
815352ff8bdSFrançois Tigeot 	/* WaDisableAsyncFlipPerfMode:bdw,chv */
816a05eeebfSFrançois Tigeot 	WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE);
817a05eeebfSFrançois Tigeot 
818352ff8bdSFrançois Tigeot 	/* WaDisablePartialInstShootdown:bdw,chv */
8192c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
820352ff8bdSFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
8211b13d190SFrançois Tigeot 
8221b13d190SFrançois Tigeot 	/* Use Force Non-Coherent whenever executing a 3D context. This is a
8231b13d190SFrançois Tigeot 	 * workaround for for a possible hang in the unlikely event a TLB
8241b13d190SFrançois Tigeot 	 * invalidation occurs during a PSD flush.
8251b13d190SFrançois Tigeot 	 */
826352ff8bdSFrançois Tigeot 	/* WaForceEnableNonCoherent:bdw,chv */
827352ff8bdSFrançois Tigeot 	/* WaHdcDisableFetchWhenMasked:bdw,chv */
8282c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
8292c9916cdSFrançois Tigeot 			  HDC_DONOT_FETCH_MEM_WHEN_MASKED |
830352ff8bdSFrançois Tigeot 			  HDC_FORCE_NON_COHERENT);
8312c9916cdSFrançois Tigeot 
8322c9916cdSFrançois Tigeot 	/* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
8332c9916cdSFrançois Tigeot 	 * "The Hierarchical Z RAW Stall Optimization allows non-overlapping
8342c9916cdSFrançois Tigeot 	 *  polygons in the same 8x4 pixel/sample area to be processed without
8352c9916cdSFrançois Tigeot 	 *  stalling waiting for the earlier ones to write to Hierarchical Z
8362c9916cdSFrançois Tigeot 	 *  buffer."
8372c9916cdSFrançois Tigeot 	 *
838352ff8bdSFrançois Tigeot 	 * This optimization is off by default for BDW and CHV; turn it on.
8392c9916cdSFrançois Tigeot 	 */
8402c9916cdSFrançois Tigeot 	WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
8411b13d190SFrançois Tigeot 
842352ff8bdSFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:bdw,chv */
843352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, GEN8_4x4_STC_OPTIMIZATION_DISABLE);
8441b13d190SFrançois Tigeot 
8451b13d190SFrançois Tigeot 	/*
8461b13d190SFrançois Tigeot 	 * BSpec recommends 8x4 when MSAA is used,
8471b13d190SFrançois Tigeot 	 * however in practice 16x4 seems fastest.
8481b13d190SFrançois Tigeot 	 *
8491b13d190SFrançois Tigeot 	 * Note that PS/WM thread counts depend on the WIZ hashing
8501b13d190SFrançois Tigeot 	 * disable bit, which we don't touch here, but it's good
8511b13d190SFrançois Tigeot 	 * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
8521b13d190SFrançois Tigeot 	 */
8532c9916cdSFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
8542c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_MASK,
8552c9916cdSFrançois Tigeot 			    GEN6_WIZ_HASHING_16x4);
8561b13d190SFrançois Tigeot 
8571b13d190SFrançois Tigeot 	return 0;
8581b13d190SFrançois Tigeot }
8591b13d190SFrançois Tigeot 
860352ff8bdSFrançois Tigeot static int bdw_init_workarounds(struct intel_engine_cs *ring)
8611b13d190SFrançois Tigeot {
862352ff8bdSFrançois Tigeot 	int ret;
8631b13d190SFrançois Tigeot 	struct drm_device *dev = ring->dev;
8641b13d190SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
8651b13d190SFrançois Tigeot 
866352ff8bdSFrançois Tigeot 	ret = gen8_init_workarounds(ring);
867352ff8bdSFrançois Tigeot 	if (ret)
868352ff8bdSFrançois Tigeot 		return ret;
869a05eeebfSFrançois Tigeot 
870352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bdw (pre-production) */
871352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
872a05eeebfSFrançois Tigeot 
873352ff8bdSFrançois Tigeot 	/* WaDisableDopClockGating:bdw */
874352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN7_ROW_CHICKEN2,
875352ff8bdSFrançois Tigeot 			  DOP_CLOCK_GATING_DISABLE);
8761b13d190SFrançois Tigeot 
877352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
878352ff8bdSFrançois Tigeot 			  GEN8_SAMPLER_POWER_BYPASS_DIS);
879352ff8bdSFrançois Tigeot 
8802c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0,
881352ff8bdSFrançois Tigeot 			  /* WaForceContextSaveRestoreNonCoherent:bdw */
882352ff8bdSFrançois Tigeot 			  HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT |
883352ff8bdSFrançois Tigeot 			  /* WaDisableFenceDestinationToSLM:bdw (pre-prod) */
884352ff8bdSFrançois Tigeot 			  (IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
8851b13d190SFrançois Tigeot 
886352ff8bdSFrançois Tigeot 	return 0;
887352ff8bdSFrançois Tigeot }
8881b13d190SFrançois Tigeot 
889352ff8bdSFrançois Tigeot static int chv_init_workarounds(struct intel_engine_cs *ring)
890352ff8bdSFrançois Tigeot {
891352ff8bdSFrançois Tigeot 	int ret;
892352ff8bdSFrançois Tigeot 	struct drm_device *dev = ring->dev;
893352ff8bdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
894352ff8bdSFrançois Tigeot 
895352ff8bdSFrançois Tigeot 	ret = gen8_init_workarounds(ring);
896352ff8bdSFrançois Tigeot 	if (ret)
897352ff8bdSFrançois Tigeot 		return ret;
898352ff8bdSFrançois Tigeot 
899352ff8bdSFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:chv */
900352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, STALL_DOP_GATING_DISABLE);
9012c9916cdSFrançois Tigeot 
9022c9916cdSFrançois Tigeot 	/* Improve HiZ throughput on CHV. */
9032c9916cdSFrançois Tigeot 	WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
9042c9916cdSFrançois Tigeot 
9052c9916cdSFrançois Tigeot 	return 0;
9062c9916cdSFrançois Tigeot }
9072c9916cdSFrançois Tigeot 
908477eb7f9SFrançois Tigeot static int gen9_init_workarounds(struct intel_engine_cs *ring)
909477eb7f9SFrançois Tigeot {
910477eb7f9SFrançois Tigeot 	struct drm_device *dev = ring->dev;
911477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
91219c468b4SFrançois Tigeot 	uint32_t tmp;
913*c0e85e96SFrançois Tigeot 	int ret;
914477eb7f9SFrançois Tigeot 
915352ff8bdSFrançois Tigeot 	/* WaEnableLbsSlaRetryTimerDecrement:skl */
916352ff8bdSFrançois Tigeot 	I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) |
917352ff8bdSFrançois Tigeot 		   GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE);
918352ff8bdSFrançois Tigeot 
919352ff8bdSFrançois Tigeot 	/* WaDisableKillLogic:bxt,skl */
920352ff8bdSFrançois Tigeot 	I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
921352ff8bdSFrançois Tigeot 		   ECOCHK_DIS_TLB);
922352ff8bdSFrançois Tigeot 
92319c468b4SFrançois Tigeot 	/* WaDisablePartialInstShootdown:skl,bxt */
924477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
925477eb7f9SFrançois Tigeot 			  PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE);
926477eb7f9SFrançois Tigeot 
92719c468b4SFrançois Tigeot 	/* Syncing dependencies between camera and graphics:skl,bxt */
928477eb7f9SFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
929477eb7f9SFrançois Tigeot 			  GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC);
930477eb7f9SFrançois Tigeot 
93119c468b4SFrançois Tigeot 	/* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */
932aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
933aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
934477eb7f9SFrançois Tigeot 		WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
935477eb7f9SFrançois Tigeot 				  GEN9_DG_MIRROR_FIX_ENABLE);
936477eb7f9SFrançois Tigeot 
93719c468b4SFrançois Tigeot 	/* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */
938aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) ||
939aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
940477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1,
941477eb7f9SFrançois Tigeot 				  GEN9_RHWO_OPTIMIZATION_DISABLE);
942a05eeebfSFrançois Tigeot 		/*
943a05eeebfSFrançois Tigeot 		 * WA also requires GEN9_SLICE_COMMON_ECO_CHICKEN0[14:14] to be set
944a05eeebfSFrançois Tigeot 		 * but we do that in per ctx batchbuffer as there is an issue
945a05eeebfSFrançois Tigeot 		 * with this register not getting restored on ctx restore
946a05eeebfSFrançois Tigeot 		 */
947477eb7f9SFrançois Tigeot 	}
948477eb7f9SFrançois Tigeot 
94919c468b4SFrançois Tigeot 	/* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */
950aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER) || IS_BROXTON(dev))
951477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7,
952477eb7f9SFrançois Tigeot 				  GEN9_ENABLE_YV12_BUGFIX);
953477eb7f9SFrançois Tigeot 
95419c468b4SFrançois Tigeot 	/* Wa4x4STCOptimizationDisable:skl,bxt */
95519c468b4SFrançois Tigeot 	/* WaDisablePartialResolveInVc:skl,bxt */
956352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(CACHE_MODE_1, (GEN8_4x4_STC_OPTIMIZATION_DISABLE |
957352ff8bdSFrançois Tigeot 					 GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE));
958477eb7f9SFrançois Tigeot 
95919c468b4SFrançois Tigeot 	/* WaCcsTlbPrefetchDisable:skl,bxt */
960477eb7f9SFrançois Tigeot 	WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5,
961477eb7f9SFrançois Tigeot 			  GEN9_CCS_TLB_PREFETCH_ENABLE);
962477eb7f9SFrançois Tigeot 
96319c468b4SFrançois Tigeot 	/* WaDisableMaskBasedCammingInRCC:skl,bxt */
964aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_C0) ||
965aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, 0, BXT_REVID_A1))
96619c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0,
96719c468b4SFrançois Tigeot 				  PIXEL_MASK_CAMMING_DISABLE);
96819c468b4SFrançois Tigeot 
96919c468b4SFrançois Tigeot 	/* WaForceContextSaveRestoreNonCoherent:skl,bxt */
97019c468b4SFrançois Tigeot 	tmp = HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT;
971*c0e85e96SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_F0, REVID_FOREVER) ||
972aee94f86SFrançois Tigeot 	    IS_BXT_REVID(dev, BXT_REVID_B0, REVID_FOREVER))
97319c468b4SFrançois Tigeot 		tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE;
97419c468b4SFrançois Tigeot 	WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp);
97519c468b4SFrançois Tigeot 
976352ff8bdSFrançois Tigeot 	/* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */
977aee94f86SFrançois Tigeot 	if (IS_SKYLAKE(dev) || IS_BXT_REVID(dev, 0, BXT_REVID_B0))
978352ff8bdSFrançois Tigeot 		WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3,
979352ff8bdSFrançois Tigeot 				  GEN8_SAMPLER_POWER_BYPASS_DIS);
980352ff8bdSFrançois Tigeot 
981352ff8bdSFrançois Tigeot 	/* WaDisableSTUnitPowerOptimization:skl,bxt */
982352ff8bdSFrançois Tigeot 	WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE);
983352ff8bdSFrançois Tigeot 
984*c0e85e96SFrançois Tigeot 	/* WaOCLCoherentLineFlush:skl,bxt */
985*c0e85e96SFrançois Tigeot 	I915_WRITE(GEN8_L3SQCREG4, (I915_READ(GEN8_L3SQCREG4) |
986*c0e85e96SFrançois Tigeot 				    GEN8_LQSC_FLUSH_COHERENT_LINES));
987*c0e85e96SFrançois Tigeot 
988*c0e85e96SFrançois Tigeot 	/* WaEnablePreemptionGranularityControlByUMD:skl,bxt */
989*c0e85e96SFrançois Tigeot 	ret= wa_ring_whitelist_reg(ring, GEN8_CS_CHICKEN1);
990*c0e85e96SFrançois Tigeot 	if (ret)
991*c0e85e96SFrançois Tigeot 		return ret;
992*c0e85e96SFrançois Tigeot 
993*c0e85e96SFrançois Tigeot 	/* WaAllowUMDToModifyHDCChicken1:skl,bxt */
994*c0e85e96SFrançois Tigeot 	ret = wa_ring_whitelist_reg(ring, GEN8_HDC_CHICKEN1);
995*c0e85e96SFrançois Tigeot 	if (ret)
996*c0e85e96SFrançois Tigeot 		return ret;
997*c0e85e96SFrançois Tigeot 
998477eb7f9SFrançois Tigeot 	return 0;
999477eb7f9SFrançois Tigeot }
1000477eb7f9SFrançois Tigeot 
1001477eb7f9SFrançois Tigeot static int skl_tune_iz_hashing(struct intel_engine_cs *ring)
1002477eb7f9SFrançois Tigeot {
1003477eb7f9SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1004477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1005477eb7f9SFrançois Tigeot 	u8 vals[3] = { 0, 0, 0 };
1006477eb7f9SFrançois Tigeot 	unsigned int i;
1007477eb7f9SFrançois Tigeot 
1008477eb7f9SFrançois Tigeot 	for (i = 0; i < 3; i++) {
1009477eb7f9SFrançois Tigeot 		u8 ss;
1010477eb7f9SFrançois Tigeot 
1011477eb7f9SFrançois Tigeot 		/*
1012477eb7f9SFrançois Tigeot 		 * Only consider slices where one, and only one, subslice has 7
1013477eb7f9SFrançois Tigeot 		 * EUs
1014477eb7f9SFrançois Tigeot 		 */
1015aee94f86SFrançois Tigeot 		if (!is_power_of_2(dev_priv->info.subslice_7eu[i]))
1016477eb7f9SFrançois Tigeot 			continue;
1017477eb7f9SFrançois Tigeot 
1018477eb7f9SFrançois Tigeot 		/*
1019477eb7f9SFrançois Tigeot 		 * subslice_7eu[i] != 0 (because of the check above) and
1020477eb7f9SFrançois Tigeot 		 * ss_max == 4 (maximum number of subslices possible per slice)
1021477eb7f9SFrançois Tigeot 		 *
1022477eb7f9SFrançois Tigeot 		 * ->    0 <= ss <= 3;
1023477eb7f9SFrançois Tigeot 		 */
1024477eb7f9SFrançois Tigeot 		ss = ffs(dev_priv->info.subslice_7eu[i]) - 1;
1025477eb7f9SFrançois Tigeot 		vals[i] = 3 - ss;
1026477eb7f9SFrançois Tigeot 	}
1027477eb7f9SFrançois Tigeot 
1028477eb7f9SFrançois Tigeot 	if (vals[0] == 0 && vals[1] == 0 && vals[2] == 0)
1029477eb7f9SFrançois Tigeot 		return 0;
1030477eb7f9SFrançois Tigeot 
1031477eb7f9SFrançois Tigeot 	/* Tune IZ hashing. See intel_device_info_runtime_init() */
1032477eb7f9SFrançois Tigeot 	WA_SET_FIELD_MASKED(GEN7_GT_MODE,
1033477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(2) |
1034477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(1) |
1035477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING_MASK(0),
1036477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(2, vals[2]) |
1037477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(1, vals[1]) |
1038477eb7f9SFrançois Tigeot 			    GEN9_IZ_HASHING(0, vals[0]));
1039477eb7f9SFrançois Tigeot 
1040477eb7f9SFrançois Tigeot 	return 0;
1041477eb7f9SFrançois Tigeot }
1042477eb7f9SFrançois Tigeot 
1043477eb7f9SFrançois Tigeot static int skl_init_workarounds(struct intel_engine_cs *ring)
1044477eb7f9SFrançois Tigeot {
1045352ff8bdSFrançois Tigeot 	int ret;
1046477eb7f9SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1047477eb7f9SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1048477eb7f9SFrançois Tigeot 
1049352ff8bdSFrançois Tigeot 	ret = gen9_init_workarounds(ring);
1050352ff8bdSFrançois Tigeot 	if (ret)
1051352ff8bdSFrançois Tigeot 		return ret;
1052352ff8bdSFrançois Tigeot 
1053*c0e85e96SFrançois Tigeot 	/*
1054*c0e85e96SFrançois Tigeot 	 * Actual WA is to disable percontext preemption granularity control
1055*c0e85e96SFrançois Tigeot 	 * until D0 which is the default case so this is equivalent to
1056*c0e85e96SFrançois Tigeot 	 * !WaDisablePerCtxtPreemptionGranularityControl:skl
1057*c0e85e96SFrançois Tigeot 	 */
1058*c0e85e96SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_E0, REVID_FOREVER)) {
1059*c0e85e96SFrançois Tigeot 		I915_WRITE(GEN7_FF_SLICE_CS_CHICKEN1,
1060*c0e85e96SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_FFSC_PERCTX_PREEMPT_CTRL));
1061*c0e85e96SFrançois Tigeot 	}
1062*c0e85e96SFrançois Tigeot 
1063aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) {
1064352ff8bdSFrançois Tigeot 		/* WaDisableChickenBitTSGBarrierAckForFFSliceCS:skl */
1065352ff8bdSFrançois Tigeot 		I915_WRITE(FF_SLICE_CS_CHICKEN2,
1066352ff8bdSFrançois Tigeot 			   _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE));
1067352ff8bdSFrançois Tigeot 	}
1068352ff8bdSFrançois Tigeot 
1069352ff8bdSFrançois Tigeot 	/* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
1070352ff8bdSFrançois Tigeot 	 * involving this register should also be added to WA batch as required.
1071352ff8bdSFrançois Tigeot 	 */
1072aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_E0))
1073352ff8bdSFrançois Tigeot 		/* WaDisableLSQCROPERFforOCL:skl */
1074352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
1075352ff8bdSFrançois Tigeot 			   GEN8_LQSC_RO_PERF_DIS);
1076352ff8bdSFrançois Tigeot 
1077352ff8bdSFrançois Tigeot 	/* WaEnableGapsTsvCreditFix:skl */
1078aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER)) {
1079352ff8bdSFrançois Tigeot 		I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) |
1080352ff8bdSFrançois Tigeot 					   GEN9_GAPS_TSV_CREDIT_DISABLE));
1081352ff8bdSFrançois Tigeot 	}
1082477eb7f9SFrançois Tigeot 
1083477eb7f9SFrançois Tigeot 	/* WaDisablePowerCompilerClockGating:skl */
1084aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_B0, SKL_REVID_B0))
1085477eb7f9SFrançois Tigeot 		WA_SET_BIT_MASKED(HIZ_CHICKEN,
1086477eb7f9SFrançois Tigeot 				  BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE);
1087477eb7f9SFrançois Tigeot 
1088*c0e85e96SFrançois Tigeot 	/* This is tied to WaForceContextSaveRestoreNonCoherent */
1089*c0e85e96SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, REVID_FOREVER)) {
109019c468b4SFrançois Tigeot 		/*
109119c468b4SFrançois Tigeot 		 *Use Force Non-Coherent whenever executing a 3D context. This
109219c468b4SFrançois Tigeot 		 * is a workaround for a possible hang in the unlikely event
109319c468b4SFrançois Tigeot 		 * a TLB invalidation occurs during a PSD flush.
109419c468b4SFrançois Tigeot 		 */
109519c468b4SFrançois Tigeot 		/* WaForceEnableNonCoherent:skl */
109619c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
109719c468b4SFrançois Tigeot 				  HDC_FORCE_NON_COHERENT);
1098aee94f86SFrançois Tigeot 
1099aee94f86SFrançois Tigeot 		/* WaDisableHDCInvalidation:skl */
1100aee94f86SFrançois Tigeot 		I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) |
1101aee94f86SFrançois Tigeot 			   BDW_DISABLE_HDC_INVALIDATION);
110219c468b4SFrançois Tigeot 	}
110319c468b4SFrançois Tigeot 
1104a05eeebfSFrançois Tigeot 	/* WaBarrierPerformanceFixDisable:skl */
1105aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0))
1106a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(HDC_CHICKEN0,
1107a05eeebfSFrançois Tigeot 				  HDC_FENCE_DEST_SLM_DISABLE |
1108a05eeebfSFrançois Tigeot 				  HDC_BARRIER_PERFORMANCE_DISABLE);
1109a05eeebfSFrançois Tigeot 
1110a05eeebfSFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:skl */
1111aee94f86SFrançois Tigeot 	if (IS_SKL_REVID(dev, 0, SKL_REVID_F0))
1112a05eeebfSFrançois Tigeot 		WA_SET_BIT_MASKED(
1113a05eeebfSFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
1114a05eeebfSFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
1115a05eeebfSFrançois Tigeot 
1116*c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:skl */
1117*c0e85e96SFrançois Tigeot 	ret = wa_ring_whitelist_reg(ring, GEN8_L3SQCREG4);
1118*c0e85e96SFrançois Tigeot 	if (ret)
1119*c0e85e96SFrançois Tigeot 		return ret;
1120*c0e85e96SFrançois Tigeot 
1121477eb7f9SFrançois Tigeot 	return skl_tune_iz_hashing(ring);
1122477eb7f9SFrançois Tigeot }
1123477eb7f9SFrançois Tigeot 
112419c468b4SFrançois Tigeot static int bxt_init_workarounds(struct intel_engine_cs *ring)
112519c468b4SFrançois Tigeot {
1126352ff8bdSFrançois Tigeot 	int ret;
112719c468b4SFrançois Tigeot 	struct drm_device *dev = ring->dev;
112819c468b4SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
112919c468b4SFrançois Tigeot 
1130352ff8bdSFrançois Tigeot 	ret = gen9_init_workarounds(ring);
1131352ff8bdSFrançois Tigeot 	if (ret)
1132352ff8bdSFrançois Tigeot 		return ret;
1133352ff8bdSFrançois Tigeot 
1134352ff8bdSFrançois Tigeot 	/* WaStoreMultiplePTEenable:bxt */
1135352ff8bdSFrançois Tigeot 	/* This is a requirement according to Hardware specification */
1136aee94f86SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
1137352ff8bdSFrançois Tigeot 		I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF);
1138352ff8bdSFrançois Tigeot 
1139352ff8bdSFrançois Tigeot 	/* WaSetClckGatingDisableMedia:bxt */
1140aee94f86SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
1141352ff8bdSFrançois Tigeot 		I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) &
1142352ff8bdSFrançois Tigeot 					    ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE));
1143352ff8bdSFrançois Tigeot 	}
114419c468b4SFrançois Tigeot 
114519c468b4SFrançois Tigeot 	/* WaDisableThreadStallDopClockGating:bxt */
114619c468b4SFrançois Tigeot 	WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN,
114719c468b4SFrançois Tigeot 			  STALL_DOP_GATING_DISABLE);
114819c468b4SFrançois Tigeot 
114919c468b4SFrançois Tigeot 	/* WaDisableSbeCacheDispatchPortSharing:bxt */
1150aee94f86SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) {
115119c468b4SFrançois Tigeot 		WA_SET_BIT_MASKED(
115219c468b4SFrançois Tigeot 			GEN7_HALF_SLICE_CHICKEN1,
115319c468b4SFrançois Tigeot 			GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE);
115419c468b4SFrançois Tigeot 	}
115519c468b4SFrançois Tigeot 
1156*c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForTrifanOrPolygon:bxt */
1157*c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemptionForInstancedDraw:bxt */
1158*c0e85e96SFrançois Tigeot 	/* WaDisableObjectLevelPreemtionForInstanceId:bxt */
1159*c0e85e96SFrançois Tigeot 	/* WaDisableLSQCROPERFforOCL:bxt */
1160*c0e85e96SFrançois Tigeot 	if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
1161*c0e85e96SFrançois Tigeot 		ret = wa_ring_whitelist_reg(ring, GEN9_CS_DEBUG_MODE1);
1162*c0e85e96SFrançois Tigeot 		if (ret)
1163*c0e85e96SFrançois Tigeot 			return ret;
1164*c0e85e96SFrançois Tigeot 
1165*c0e85e96SFrançois Tigeot 		ret = wa_ring_whitelist_reg(ring, GEN8_L3SQCREG4);
1166*c0e85e96SFrançois Tigeot 		if (ret)
1167*c0e85e96SFrançois Tigeot 			return ret;
1168*c0e85e96SFrançois Tigeot 	}
1169*c0e85e96SFrançois Tigeot 
117019c468b4SFrançois Tigeot 	return 0;
117119c468b4SFrançois Tigeot }
117219c468b4SFrançois Tigeot 
11732c9916cdSFrançois Tigeot int init_workarounds_ring(struct intel_engine_cs *ring)
11742c9916cdSFrançois Tigeot {
11752c9916cdSFrançois Tigeot 	struct drm_device *dev = ring->dev;
11762c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
11772c9916cdSFrançois Tigeot 
11782c9916cdSFrançois Tigeot 	WARN_ON(ring->id != RCS);
11792c9916cdSFrançois Tigeot 
11802c9916cdSFrançois Tigeot 	dev_priv->workarounds.count = 0;
1181*c0e85e96SFrançois Tigeot 	dev_priv->workarounds.hw_whitelist_count[RCS] = 0;
11822c9916cdSFrançois Tigeot 
11832c9916cdSFrançois Tigeot 	if (IS_BROADWELL(dev))
11842c9916cdSFrançois Tigeot 		return bdw_init_workarounds(ring);
11852c9916cdSFrançois Tigeot 
11862c9916cdSFrançois Tigeot 	if (IS_CHERRYVIEW(dev))
11872c9916cdSFrançois Tigeot 		return chv_init_workarounds(ring);
11881b13d190SFrançois Tigeot 
1189477eb7f9SFrançois Tigeot 	if (IS_SKYLAKE(dev))
1190477eb7f9SFrançois Tigeot 		return skl_init_workarounds(ring);
119119c468b4SFrançois Tigeot 
119219c468b4SFrançois Tigeot 	if (IS_BROXTON(dev))
119319c468b4SFrançois Tigeot 		return bxt_init_workarounds(ring);
1194477eb7f9SFrançois Tigeot 
11951b13d190SFrançois Tigeot 	return 0;
11961b13d190SFrançois Tigeot }
11971b13d190SFrançois Tigeot 
1198ba55f2f5SFrançois Tigeot static int init_render_ring(struct intel_engine_cs *ring)
1199e3adcf8fSFrançois Tigeot {
1200e3adcf8fSFrançois Tigeot 	struct drm_device *dev = ring->dev;
1201e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1202e3adcf8fSFrançois Tigeot 	int ret = init_ring_common(ring);
120324edb884SFrançois Tigeot 	if (ret)
120424edb884SFrançois Tigeot 		return ret;
1205e3adcf8fSFrançois Tigeot 
1206ba55f2f5SFrançois Tigeot 	/* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */
1207ba55f2f5SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 4 && INTEL_INFO(dev)->gen < 7)
1208f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
1209f4e1c372SFrançois Tigeot 
1210f4e1c372SFrançois Tigeot 	/* We need to disable the AsyncFlip performance optimisations in order
1211f4e1c372SFrançois Tigeot 	 * to use MI_WAIT_FOR_EVENT within the CS. It should already be
1212f4e1c372SFrançois Tigeot 	 * programmed to '1' on all products.
12135d0b1887SFrançois Tigeot 	 *
1214a05eeebfSFrançois Tigeot 	 * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
1215f4e1c372SFrançois Tigeot 	 */
1216a05eeebfSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8)
1217f4e1c372SFrançois Tigeot 		I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
1218f4e1c372SFrançois Tigeot 
1219f4e1c372SFrançois Tigeot 	/* Required for the hardware to program scanline values for waiting */
1220ba55f2f5SFrançois Tigeot 	/* WaEnableFlushTlbInvalidationMode:snb */
1221f4e1c372SFrançois Tigeot 	if (INTEL_INFO(dev)->gen == 6)
1222f4e1c372SFrançois Tigeot 		I915_WRITE(GFX_MODE,
1223ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT));
1224f4e1c372SFrançois Tigeot 
1225ba55f2f5SFrançois Tigeot 	/* WaBCSVCSTlbInvalidationMode:ivb,vlv,hsw */
1226e3adcf8fSFrançois Tigeot 	if (IS_GEN7(dev))
1227e3adcf8fSFrançois Tigeot 		I915_WRITE(GFX_MODE_GEN7,
1228ba55f2f5SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
1229f4e1c372SFrançois Tigeot 			   _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
1230e3adcf8fSFrançois Tigeot 
1231e3adcf8fSFrançois Tigeot 	if (IS_GEN6(dev)) {
1232e3adcf8fSFrançois Tigeot 		/* From the Sandybridge PRM, volume 1 part 3, page 24:
1233e3adcf8fSFrançois Tigeot 		 * "If this bit is set, STCunit will have LRA as replacement
1234e3adcf8fSFrançois Tigeot 		 *  policy. [...] This bit must be reset.  LRA replacement
1235e3adcf8fSFrançois Tigeot 		 *  policy is not supported."
1236e3adcf8fSFrançois Tigeot 		 */
1237e3adcf8fSFrançois Tigeot 		I915_WRITE(CACHE_MODE_0,
1238f4e1c372SFrançois Tigeot 			   _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
1239e3adcf8fSFrançois Tigeot 	}
1240e3adcf8fSFrançois Tigeot 
1241a05eeebfSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8)
1242f4e1c372SFrançois Tigeot 		I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
1243f4e1c372SFrançois Tigeot 
12449edbd4a0SFrançois Tigeot 	if (HAS_L3_DPF(dev))
12459edbd4a0SFrançois Tigeot 		I915_WRITE_IMR(ring, ~GT_PARITY_ERROR(dev));
1246e3adcf8fSFrançois Tigeot 
12472c9916cdSFrançois Tigeot 	return init_workarounds_ring(ring);
1248e3adcf8fSFrançois Tigeot }
1249e3adcf8fSFrançois Tigeot 
1250ba55f2f5SFrançois Tigeot static void render_ring_cleanup(struct intel_engine_cs *ring)
1251e3adcf8fSFrançois Tigeot {
1252b5c29a34SFrançois Tigeot 	struct drm_device *dev = ring->dev;
125324edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
125424edb884SFrançois Tigeot 
125524edb884SFrançois Tigeot 	if (dev_priv->semaphore_obj) {
125624edb884SFrançois Tigeot 		i915_gem_object_ggtt_unpin(dev_priv->semaphore_obj);
125724edb884SFrançois Tigeot 		drm_gem_object_unreference(&dev_priv->semaphore_obj->base);
125824edb884SFrançois Tigeot 		dev_priv->semaphore_obj = NULL;
125924edb884SFrançois Tigeot 	}
1260b5c29a34SFrançois Tigeot 
12611b13d190SFrançois Tigeot 	intel_fini_pipe_control(ring);
1262e3adcf8fSFrançois Tigeot }
1263e3adcf8fSFrançois Tigeot 
1264a05eeebfSFrançois Tigeot static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req,
126524edb884SFrançois Tigeot 			   unsigned int num_dwords)
126624edb884SFrançois Tigeot {
126724edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 8
1268a05eeebfSFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->ring;
126924edb884SFrançois Tigeot 	struct drm_device *dev = signaller->dev;
127024edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
127124edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
127224edb884SFrançois Tigeot 	int i, ret, num_rings;
127324edb884SFrançois Tigeot 
127424edb884SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
127524edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
127624edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
127724edb884SFrançois Tigeot 
1278a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
127924edb884SFrançois Tigeot 	if (ret)
128024edb884SFrançois Tigeot 		return ret;
128124edb884SFrançois Tigeot 
128224edb884SFrançois Tigeot 	for_each_ring(waiter, dev_priv, i) {
12832c9916cdSFrançois Tigeot 		u32 seqno;
128424edb884SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
128524edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
128624edb884SFrançois Tigeot 			continue;
128724edb884SFrançois Tigeot 
1288a05eeebfSFrançois Tigeot 		seqno = i915_gem_request_get_seqno(signaller_req);
128924edb884SFrançois Tigeot 		intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
129024edb884SFrançois Tigeot 		intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
129124edb884SFrançois Tigeot 					   PIPE_CONTROL_QW_WRITE |
129224edb884SFrançois Tigeot 					   PIPE_CONTROL_FLUSH_ENABLE);
129324edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset));
129424edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
12952c9916cdSFrançois Tigeot 		intel_ring_emit(signaller, seqno);
129624edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
129724edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
129824edb884SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->id));
129924edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
130024edb884SFrançois Tigeot 	}
130124edb884SFrançois Tigeot 
130224edb884SFrançois Tigeot 	return 0;
130324edb884SFrançois Tigeot }
130424edb884SFrançois Tigeot 
1305a05eeebfSFrançois Tigeot static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req,
130624edb884SFrançois Tigeot 			   unsigned int num_dwords)
130724edb884SFrançois Tigeot {
130824edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 6
1309a05eeebfSFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->ring;
131024edb884SFrançois Tigeot 	struct drm_device *dev = signaller->dev;
131124edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
131224edb884SFrançois Tigeot 	struct intel_engine_cs *waiter;
131324edb884SFrançois Tigeot 	int i, ret, num_rings;
131424edb884SFrançois Tigeot 
131524edb884SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
131624edb884SFrançois Tigeot 	num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS;
131724edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
131824edb884SFrançois Tigeot 
1319a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
132024edb884SFrançois Tigeot 	if (ret)
132124edb884SFrançois Tigeot 		return ret;
132224edb884SFrançois Tigeot 
132324edb884SFrançois Tigeot 	for_each_ring(waiter, dev_priv, i) {
13242c9916cdSFrançois Tigeot 		u32 seqno;
132524edb884SFrançois Tigeot 		u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
132624edb884SFrançois Tigeot 		if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
132724edb884SFrançois Tigeot 			continue;
132824edb884SFrançois Tigeot 
1329a05eeebfSFrançois Tigeot 		seqno = i915_gem_request_get_seqno(signaller_req);
133024edb884SFrançois Tigeot 		intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
133124edb884SFrançois Tigeot 					   MI_FLUSH_DW_OP_STOREDW);
133224edb884SFrançois Tigeot 		intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
133324edb884SFrançois Tigeot 					   MI_FLUSH_DW_USE_GTT);
133424edb884SFrançois Tigeot 		intel_ring_emit(signaller, upper_32_bits(gtt_offset));
13352c9916cdSFrançois Tigeot 		intel_ring_emit(signaller, seqno);
133624edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
133724edb884SFrançois Tigeot 					   MI_SEMAPHORE_TARGET(waiter->id));
133824edb884SFrançois Tigeot 		intel_ring_emit(signaller, 0);
133924edb884SFrançois Tigeot 	}
134024edb884SFrançois Tigeot 
134124edb884SFrançois Tigeot 	return 0;
134224edb884SFrançois Tigeot }
134324edb884SFrançois Tigeot 
1344a05eeebfSFrançois Tigeot static int gen6_signal(struct drm_i915_gem_request *signaller_req,
1345ba55f2f5SFrançois Tigeot 		       unsigned int num_dwords)
1346e3adcf8fSFrançois Tigeot {
1347a05eeebfSFrançois Tigeot 	struct intel_engine_cs *signaller = signaller_req->ring;
1348ba55f2f5SFrançois Tigeot 	struct drm_device *dev = signaller->dev;
1349ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1350ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *useless;
135124edb884SFrançois Tigeot 	int i, ret, num_rings;
1352ba55f2f5SFrançois Tigeot 
135324edb884SFrançois Tigeot #define MBOX_UPDATE_DWORDS 3
135424edb884SFrançois Tigeot 	num_rings = hweight32(INTEL_INFO(dev)->ring_mask);
135524edb884SFrançois Tigeot 	num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2);
135624edb884SFrançois Tigeot #undef MBOX_UPDATE_DWORDS
1357ba55f2f5SFrançois Tigeot 
1358a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(signaller_req, num_dwords);
1359ba55f2f5SFrançois Tigeot 	if (ret)
1360ba55f2f5SFrançois Tigeot 		return ret;
1361ba55f2f5SFrançois Tigeot 
1362ba55f2f5SFrançois Tigeot 	for_each_ring(useless, dev_priv, i) {
1363aee94f86SFrançois Tigeot 		i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[i];
1364aee94f86SFrançois Tigeot 
1365aee94f86SFrançois Tigeot 		if (i915_mmio_reg_valid(mbox_reg)) {
1366a05eeebfSFrançois Tigeot 			u32 seqno = i915_gem_request_get_seqno(signaller_req);
1367aee94f86SFrançois Tigeot 
1368ba55f2f5SFrançois Tigeot 			intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
1369aee94f86SFrançois Tigeot 			intel_ring_emit_reg(signaller, mbox_reg);
13702c9916cdSFrançois Tigeot 			intel_ring_emit(signaller, seqno);
1371ba55f2f5SFrançois Tigeot 		}
1372ba55f2f5SFrançois Tigeot 	}
1373ba55f2f5SFrançois Tigeot 
137424edb884SFrançois Tigeot 	/* If num_dwords was rounded, make sure the tail pointer is correct */
137524edb884SFrançois Tigeot 	if (num_rings % 2 == 0)
137624edb884SFrançois Tigeot 		intel_ring_emit(signaller, MI_NOOP);
137724edb884SFrançois Tigeot 
1378ba55f2f5SFrançois Tigeot 	return 0;
1379e3adcf8fSFrançois Tigeot }
1380e3adcf8fSFrançois Tigeot 
1381e3adcf8fSFrançois Tigeot /**
1382e3adcf8fSFrançois Tigeot  * gen6_add_request - Update the semaphore mailbox registers
1383e3adcf8fSFrançois Tigeot  *
1384a05eeebfSFrançois Tigeot  * @request - request to write to the ring
1385e3adcf8fSFrançois Tigeot  *
1386e3adcf8fSFrançois Tigeot  * Update the mailbox registers in the *other* rings with the current seqno.
1387e3adcf8fSFrançois Tigeot  * This acts like a signal in the canonical semaphore.
1388e3adcf8fSFrançois Tigeot  */
1389e3adcf8fSFrançois Tigeot static int
1390a05eeebfSFrançois Tigeot gen6_add_request(struct drm_i915_gem_request *req)
1391e3adcf8fSFrançois Tigeot {
1392a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
1393ba55f2f5SFrançois Tigeot 	int ret;
1394e3adcf8fSFrançois Tigeot 
139524edb884SFrançois Tigeot 	if (ring->semaphore.signal)
1396a05eeebfSFrançois Tigeot 		ret = ring->semaphore.signal(req, 4);
139724edb884SFrançois Tigeot 	else
1398a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 4);
139924edb884SFrançois Tigeot 
14009edbd4a0SFrançois Tigeot 	if (ret)
14019edbd4a0SFrançois Tigeot 		return ret;
14029edbd4a0SFrançois Tigeot 
1403e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
1404e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
1405a05eeebfSFrançois Tigeot 	intel_ring_emit(ring, i915_gem_request_get_seqno(req));
1406e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_USER_INTERRUPT);
14079edbd4a0SFrançois Tigeot 	__intel_ring_advance(ring);
1408e3adcf8fSFrançois Tigeot 
1409e3adcf8fSFrançois Tigeot 	return 0;
1410e3adcf8fSFrançois Tigeot }
1411e3adcf8fSFrançois Tigeot 
1412a2fdbec6SFrançois Tigeot static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev,
1413a2fdbec6SFrançois Tigeot 					      u32 seqno)
1414a2fdbec6SFrançois Tigeot {
1415a2fdbec6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1416a2fdbec6SFrançois Tigeot 	return dev_priv->last_seqno < seqno;
1417a2fdbec6SFrançois Tigeot }
1418a2fdbec6SFrançois Tigeot 
1419e3adcf8fSFrançois Tigeot /**
1420e3adcf8fSFrançois Tigeot  * intel_ring_sync - sync the waiter to the signaller on seqno
1421e3adcf8fSFrançois Tigeot  *
1422e3adcf8fSFrançois Tigeot  * @waiter - ring that is waiting
1423e3adcf8fSFrançois Tigeot  * @signaller - ring which has, or will signal
1424e3adcf8fSFrançois Tigeot  * @seqno - seqno which the waiter will block on
1425e3adcf8fSFrançois Tigeot  */
142624edb884SFrançois Tigeot 
142724edb884SFrançois Tigeot static int
1428a05eeebfSFrançois Tigeot gen8_ring_sync(struct drm_i915_gem_request *waiter_req,
142924edb884SFrançois Tigeot 	       struct intel_engine_cs *signaller,
143024edb884SFrançois Tigeot 	       u32 seqno)
143124edb884SFrançois Tigeot {
1432a05eeebfSFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->ring;
143324edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = waiter->dev->dev_private;
143424edb884SFrançois Tigeot 	int ret;
143524edb884SFrançois Tigeot 
1436a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
143724edb884SFrançois Tigeot 	if (ret)
143824edb884SFrançois Tigeot 		return ret;
143924edb884SFrançois Tigeot 
144024edb884SFrançois Tigeot 	intel_ring_emit(waiter, MI_SEMAPHORE_WAIT |
144124edb884SFrançois Tigeot 				MI_SEMAPHORE_GLOBAL_GTT |
144224edb884SFrançois Tigeot 				MI_SEMAPHORE_POLL |
144324edb884SFrançois Tigeot 				MI_SEMAPHORE_SAD_GTE_SDD);
144424edb884SFrançois Tigeot 	intel_ring_emit(waiter, seqno);
144524edb884SFrançois Tigeot 	intel_ring_emit(waiter,
144624edb884SFrançois Tigeot 			lower_32_bits(GEN8_WAIT_OFFSET(waiter, signaller->id)));
144724edb884SFrançois Tigeot 	intel_ring_emit(waiter,
144824edb884SFrançois Tigeot 			upper_32_bits(GEN8_WAIT_OFFSET(waiter, signaller->id)));
144924edb884SFrançois Tigeot 	intel_ring_advance(waiter);
145024edb884SFrançois Tigeot 	return 0;
145124edb884SFrançois Tigeot }
145224edb884SFrançois Tigeot 
1453e3adcf8fSFrançois Tigeot static int
1454a05eeebfSFrançois Tigeot gen6_ring_sync(struct drm_i915_gem_request *waiter_req,
1455ba55f2f5SFrançois Tigeot 	       struct intel_engine_cs *signaller,
1456e3adcf8fSFrançois Tigeot 	       u32 seqno)
1457e3adcf8fSFrançois Tigeot {
1458a05eeebfSFrançois Tigeot 	struct intel_engine_cs *waiter = waiter_req->ring;
1459e3adcf8fSFrançois Tigeot 	u32 dw1 = MI_SEMAPHORE_MBOX |
1460e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_COMPARE |
1461e3adcf8fSFrançois Tigeot 		  MI_SEMAPHORE_REGISTER;
1462ba55f2f5SFrançois Tigeot 	u32 wait_mbox = signaller->semaphore.mbox.wait[waiter->id];
1463ba55f2f5SFrançois Tigeot 	int ret;
1464e3adcf8fSFrançois Tigeot 
1465686a02f1SFrançois Tigeot 	/* Throughout all of the GEM code, seqno passed implies our current
1466686a02f1SFrançois Tigeot 	 * seqno is >= the last seqno executed. However for hardware the
1467686a02f1SFrançois Tigeot 	 * comparison is strictly greater than.
1468686a02f1SFrançois Tigeot 	 */
1469686a02f1SFrançois Tigeot 	seqno -= 1;
1470686a02f1SFrançois Tigeot 
1471ba55f2f5SFrançois Tigeot 	WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID);
1472686a02f1SFrançois Tigeot 
1473a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(waiter_req, 4);
1474e3adcf8fSFrançois Tigeot 	if (ret)
1475e3adcf8fSFrançois Tigeot 		return ret;
1476e3adcf8fSFrançois Tigeot 
1477a2fdbec6SFrançois Tigeot 	/* If seqno wrap happened, omit the wait with no-ops */
1478a2fdbec6SFrançois Tigeot 	if (likely(!i915_gem_has_seqno_wrapped(waiter->dev, seqno))) {
1479ba55f2f5SFrançois Tigeot 		intel_ring_emit(waiter, dw1 | wait_mbox);
1480e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, seqno);
1481e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, 0);
1482e3adcf8fSFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1483a2fdbec6SFrançois Tigeot 	} else {
1484a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1485a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1486a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1487a2fdbec6SFrançois Tigeot 		intel_ring_emit(waiter, MI_NOOP);
1488a2fdbec6SFrançois Tigeot 	}
1489e3adcf8fSFrançois Tigeot 	intel_ring_advance(waiter);
1490e3adcf8fSFrançois Tigeot 
1491e3adcf8fSFrançois Tigeot 	return 0;
1492e3adcf8fSFrançois Tigeot }
1493e3adcf8fSFrançois Tigeot 
1494e3adcf8fSFrançois Tigeot #define PIPE_CONTROL_FLUSH(ring__, addr__)					\
1495e3adcf8fSFrançois Tigeot do {									\
1496e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |		\
1497e3adcf8fSFrançois Tigeot 		 PIPE_CONTROL_DEPTH_STALL);				\
1498e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT);			\
1499e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, 0);							\
1500e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring__, 0);							\
1501e3adcf8fSFrançois Tigeot } while (0)
1502e3adcf8fSFrançois Tigeot 
1503e3adcf8fSFrançois Tigeot static int
1504a05eeebfSFrançois Tigeot pc_render_add_request(struct drm_i915_gem_request *req)
1505e3adcf8fSFrançois Tigeot {
1506a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
1507ba55f2f5SFrançois Tigeot 	u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
1508e3adcf8fSFrançois Tigeot 	int ret;
1509e3adcf8fSFrançois Tigeot 
1510e3adcf8fSFrançois Tigeot 	/* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently
1511e3adcf8fSFrançois Tigeot 	 * incoherent with writes to memory, i.e. completely fubar,
1512e3adcf8fSFrançois Tigeot 	 * so we need to use PIPE_NOTIFY instead.
1513e3adcf8fSFrançois Tigeot 	 *
1514e3adcf8fSFrançois Tigeot 	 * However, we also need to workaround the qword write
1515e3adcf8fSFrançois Tigeot 	 * incoherence by flushing the 6 PIPE_NOTIFY buffers out to
1516e3adcf8fSFrançois Tigeot 	 * memory before requesting an interrupt.
1517e3adcf8fSFrançois Tigeot 	 */
1518a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 32);
1519e3adcf8fSFrançois Tigeot 	if (ret)
1520e3adcf8fSFrançois Tigeot 		return ret;
1521e3adcf8fSFrançois Tigeot 
1522e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
1523e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_WRITE_FLUSH |
1524e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
15259edbd4a0SFrançois Tigeot 	intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
1526a05eeebfSFrançois Tigeot 	intel_ring_emit(ring, i915_gem_request_get_seqno(req));
1527e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, 0);
1528e3adcf8fSFrançois Tigeot 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
1529ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
1530e3adcf8fSFrançois Tigeot 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
1531ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
1532e3adcf8fSFrançois Tigeot 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
1533ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
1534e3adcf8fSFrançois Tigeot 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
1535ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
1536e3adcf8fSFrançois Tigeot 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
1537ba55f2f5SFrançois Tigeot 	scratch_addr += 2 * CACHELINE_BYTES;
1538e3adcf8fSFrançois Tigeot 	PIPE_CONTROL_FLUSH(ring, scratch_addr);
1539b5c29a34SFrançois Tigeot 
1540e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
1541e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_WRITE_FLUSH |
1542e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
1543e3adcf8fSFrançois Tigeot 			PIPE_CONTROL_NOTIFY);
15449edbd4a0SFrançois Tigeot 	intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
1545a05eeebfSFrançois Tigeot 	intel_ring_emit(ring, i915_gem_request_get_seqno(req));
1546e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, 0);
15479edbd4a0SFrançois Tigeot 	__intel_ring_advance(ring);
1548e3adcf8fSFrançois Tigeot 
1549e3adcf8fSFrançois Tigeot 	return 0;
1550e3adcf8fSFrançois Tigeot }
1551e3adcf8fSFrançois Tigeot 
1552e3adcf8fSFrançois Tigeot static u32
1553ba55f2f5SFrançois Tigeot gen6_ring_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
1554e3adcf8fSFrançois Tigeot {
1555e3adcf8fSFrançois Tigeot 	/* Workaround to force correct ordering between irq and seqno writes on
1556e3adcf8fSFrançois Tigeot 	 * ivb (and maybe also on snb) by reading from a CS register (like
1557e3adcf8fSFrançois Tigeot 	 * ACTHD) before reading the status page. */
1558ba55f2f5SFrançois Tigeot 	if (!lazy_coherency) {
1559ba55f2f5SFrançois Tigeot 		struct drm_i915_private *dev_priv = ring->dev->dev_private;
1560ba55f2f5SFrançois Tigeot 		POSTING_READ(RING_ACTHD(ring->mmio_base));
1561ba55f2f5SFrançois Tigeot 	}
1562ba55f2f5SFrançois Tigeot 
1563e3adcf8fSFrançois Tigeot 	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
1564e3adcf8fSFrançois Tigeot }
1565e3adcf8fSFrançois Tigeot 
1566b030f26bSFrançois Tigeot static u32
1567ba55f2f5SFrançois Tigeot ring_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
1568e3adcf8fSFrançois Tigeot {
1569e3adcf8fSFrançois Tigeot 	return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
1570e3adcf8fSFrançois Tigeot }
1571e3adcf8fSFrançois Tigeot 
1572a2fdbec6SFrançois Tigeot static void
1573ba55f2f5SFrançois Tigeot ring_set_seqno(struct intel_engine_cs *ring, u32 seqno)
1574a2fdbec6SFrançois Tigeot {
1575a2fdbec6SFrançois Tigeot 	intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
1576a2fdbec6SFrançois Tigeot }
1577a2fdbec6SFrançois Tigeot 
1578b030f26bSFrançois Tigeot static u32
1579ba55f2f5SFrançois Tigeot pc_render_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
1580e3adcf8fSFrançois Tigeot {
15819edbd4a0SFrançois Tigeot 	return ring->scratch.cpu_page[0];
1582e3adcf8fSFrançois Tigeot }
1583e3adcf8fSFrançois Tigeot 
1584a2fdbec6SFrançois Tigeot static void
1585ba55f2f5SFrançois Tigeot pc_render_set_seqno(struct intel_engine_cs *ring, u32 seqno)
1586a2fdbec6SFrançois Tigeot {
15879edbd4a0SFrançois Tigeot 	ring->scratch.cpu_page[0] = seqno;
1588a2fdbec6SFrançois Tigeot }
1589a2fdbec6SFrançois Tigeot 
1590e3adcf8fSFrançois Tigeot static bool
1591ba55f2f5SFrançois Tigeot gen5_ring_get_irq(struct intel_engine_cs *ring)
1592e3adcf8fSFrançois Tigeot {
1593e3adcf8fSFrançois Tigeot 	struct drm_device *dev = ring->dev;
1594ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
15955e269720SFrançois Tigeot 	unsigned long flags;
1596e3adcf8fSFrançois Tigeot 
15972c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
1598e3adcf8fSFrançois Tigeot 		return false;
1599e3adcf8fSFrançois Tigeot 
16005e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
16019edbd4a0SFrançois Tigeot 	if (ring->irq_refcount++ == 0)
160224edb884SFrançois Tigeot 		gen5_enable_gt_irq(dev_priv, ring->irq_enable_mask);
16035e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1604e3adcf8fSFrançois Tigeot 
1605e3adcf8fSFrançois Tigeot 	return true;
1606e3adcf8fSFrançois Tigeot }
1607e3adcf8fSFrançois Tigeot 
1608e3adcf8fSFrançois Tigeot static void
1609ba55f2f5SFrançois Tigeot gen5_ring_put_irq(struct intel_engine_cs *ring)
1610e3adcf8fSFrançois Tigeot {
1611e3adcf8fSFrançois Tigeot 	struct drm_device *dev = ring->dev;
1612ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
16135e269720SFrançois Tigeot 	unsigned long flags;
1614e3adcf8fSFrançois Tigeot 
16155e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
16169edbd4a0SFrançois Tigeot 	if (--ring->irq_refcount == 0)
161724edb884SFrançois Tigeot 		gen5_disable_gt_irq(dev_priv, ring->irq_enable_mask);
16185e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1619686a02f1SFrançois Tigeot }
1620686a02f1SFrançois Tigeot 
1621686a02f1SFrançois Tigeot static bool
1622ba55f2f5SFrançois Tigeot i9xx_ring_get_irq(struct intel_engine_cs *ring)
1623686a02f1SFrançois Tigeot {
1624686a02f1SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1625ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
16265e269720SFrançois Tigeot 	unsigned long flags;
1627686a02f1SFrançois Tigeot 
16282c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
1629686a02f1SFrançois Tigeot 		return false;
1630686a02f1SFrançois Tigeot 
16315e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
16329edbd4a0SFrançois Tigeot 	if (ring->irq_refcount++ == 0) {
1633686a02f1SFrançois Tigeot 		dev_priv->irq_mask &= ~ring->irq_enable_mask;
1634686a02f1SFrançois Tigeot 		I915_WRITE(IMR, dev_priv->irq_mask);
1635686a02f1SFrançois Tigeot 		POSTING_READ(IMR);
1636686a02f1SFrançois Tigeot 	}
16375e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1638686a02f1SFrançois Tigeot 
1639686a02f1SFrançois Tigeot 	return true;
1640686a02f1SFrançois Tigeot }
1641686a02f1SFrançois Tigeot 
1642686a02f1SFrançois Tigeot static void
1643ba55f2f5SFrançois Tigeot i9xx_ring_put_irq(struct intel_engine_cs *ring)
1644686a02f1SFrançois Tigeot {
1645686a02f1SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1646ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
16475e269720SFrançois Tigeot 	unsigned long flags;
1648686a02f1SFrançois Tigeot 
16495e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
16509edbd4a0SFrançois Tigeot 	if (--ring->irq_refcount == 0) {
1651686a02f1SFrançois Tigeot 		dev_priv->irq_mask |= ring->irq_enable_mask;
1652686a02f1SFrançois Tigeot 		I915_WRITE(IMR, dev_priv->irq_mask);
1653686a02f1SFrançois Tigeot 		POSTING_READ(IMR);
1654686a02f1SFrançois Tigeot 	}
16555e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1656686a02f1SFrançois Tigeot }
1657686a02f1SFrançois Tigeot 
1658686a02f1SFrançois Tigeot static bool
1659ba55f2f5SFrançois Tigeot i8xx_ring_get_irq(struct intel_engine_cs *ring)
1660686a02f1SFrançois Tigeot {
1661686a02f1SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1662ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
16635e269720SFrançois Tigeot 	unsigned long flags;
1664686a02f1SFrançois Tigeot 
16652c9916cdSFrançois Tigeot 	if (!intel_irqs_enabled(dev_priv))
1666686a02f1SFrançois Tigeot 		return false;
1667686a02f1SFrançois Tigeot 
16685e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
16699edbd4a0SFrançois Tigeot 	if (ring->irq_refcount++ == 0) {
1670686a02f1SFrançois Tigeot 		dev_priv->irq_mask &= ~ring->irq_enable_mask;
1671686a02f1SFrançois Tigeot 		I915_WRITE16(IMR, dev_priv->irq_mask);
1672686a02f1SFrançois Tigeot 		POSTING_READ16(IMR);
1673686a02f1SFrançois Tigeot 	}
16745e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1675686a02f1SFrançois Tigeot 
1676686a02f1SFrançois Tigeot 	return true;
1677686a02f1SFrançois Tigeot }
1678686a02f1SFrançois Tigeot 
1679686a02f1SFrançois Tigeot static void
1680ba55f2f5SFrançois Tigeot i8xx_ring_put_irq(struct intel_engine_cs *ring)
1681686a02f1SFrançois Tigeot {
1682686a02f1SFrançois Tigeot 	struct drm_device *dev = ring->dev;
1683ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
16845e269720SFrançois Tigeot 	unsigned long flags;
1685686a02f1SFrançois Tigeot 
16865e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
16879edbd4a0SFrançois Tigeot 	if (--ring->irq_refcount == 0) {
1688686a02f1SFrançois Tigeot 		dev_priv->irq_mask |= ring->irq_enable_mask;
1689686a02f1SFrançois Tigeot 		I915_WRITE16(IMR, dev_priv->irq_mask);
1690686a02f1SFrançois Tigeot 		POSTING_READ16(IMR);
1691e3adcf8fSFrançois Tigeot 	}
16925e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1693e3adcf8fSFrançois Tigeot }
1694e3adcf8fSFrançois Tigeot 
1695e3adcf8fSFrançois Tigeot static int
1696a05eeebfSFrançois Tigeot bsd_ring_flush(struct drm_i915_gem_request *req,
1697b5c29a34SFrançois Tigeot 	       u32     invalidate_domains,
1698b5c29a34SFrançois Tigeot 	       u32     flush_domains)
1699e3adcf8fSFrançois Tigeot {
1700a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
1701e3adcf8fSFrançois Tigeot 	int ret;
1702e3adcf8fSFrançois Tigeot 
1703a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1704e3adcf8fSFrançois Tigeot 	if (ret)
1705e3adcf8fSFrançois Tigeot 		return ret;
1706e3adcf8fSFrançois Tigeot 
1707e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_FLUSH);
1708e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
1709e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
1710e3adcf8fSFrançois Tigeot 	return 0;
1711e3adcf8fSFrançois Tigeot }
1712e3adcf8fSFrançois Tigeot 
1713e3adcf8fSFrançois Tigeot static int
1714a05eeebfSFrançois Tigeot i9xx_add_request(struct drm_i915_gem_request *req)
1715e3adcf8fSFrançois Tigeot {
1716a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
1717e3adcf8fSFrançois Tigeot 	int ret;
1718e3adcf8fSFrançois Tigeot 
1719a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
1720e3adcf8fSFrançois Tigeot 	if (ret)
1721e3adcf8fSFrançois Tigeot 		return ret;
1722e3adcf8fSFrançois Tigeot 
1723e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
1724e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
1725a05eeebfSFrançois Tigeot 	intel_ring_emit(ring, i915_gem_request_get_seqno(req));
1726e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_USER_INTERRUPT);
17279edbd4a0SFrançois Tigeot 	__intel_ring_advance(ring);
1728e3adcf8fSFrançois Tigeot 
1729e3adcf8fSFrançois Tigeot 	return 0;
1730e3adcf8fSFrançois Tigeot }
1731e3adcf8fSFrançois Tigeot 
1732e3adcf8fSFrançois Tigeot static bool
1733ba55f2f5SFrançois Tigeot gen6_ring_get_irq(struct intel_engine_cs *ring)
1734e3adcf8fSFrançois Tigeot {
1735e3adcf8fSFrançois Tigeot 	struct drm_device *dev = ring->dev;
1736ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17375e269720SFrançois Tigeot 	unsigned long flags;
1738e3adcf8fSFrançois Tigeot 
17392c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
1740e3adcf8fSFrançois Tigeot 		return false;
1741e3adcf8fSFrançois Tigeot 
17425e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17439edbd4a0SFrançois Tigeot 	if (ring->irq_refcount++ == 0) {
17449edbd4a0SFrançois Tigeot 		if (HAS_L3_DPF(dev) && ring->id == RCS)
17455d0b1887SFrançois Tigeot 			I915_WRITE_IMR(ring,
17465d0b1887SFrançois Tigeot 				       ~(ring->irq_enable_mask |
17479edbd4a0SFrançois Tigeot 					 GT_PARITY_ERROR(dev)));
1748686a02f1SFrançois Tigeot 		else
1749686a02f1SFrançois Tigeot 			I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
175024edb884SFrançois Tigeot 		gen5_enable_gt_irq(dev_priv, ring->irq_enable_mask);
1751e3adcf8fSFrançois Tigeot 	}
17525e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1753e3adcf8fSFrançois Tigeot 
1754e3adcf8fSFrançois Tigeot 	return true;
1755e3adcf8fSFrançois Tigeot }
1756e3adcf8fSFrançois Tigeot 
1757e3adcf8fSFrançois Tigeot static void
1758ba55f2f5SFrançois Tigeot gen6_ring_put_irq(struct intel_engine_cs *ring)
1759e3adcf8fSFrançois Tigeot {
1760e3adcf8fSFrançois Tigeot 	struct drm_device *dev = ring->dev;
1761ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17625e269720SFrançois Tigeot 	unsigned long flags;
1763e3adcf8fSFrançois Tigeot 
17645e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17659edbd4a0SFrançois Tigeot 	if (--ring->irq_refcount == 0) {
17669edbd4a0SFrançois Tigeot 		if (HAS_L3_DPF(dev) && ring->id == RCS)
17679edbd4a0SFrançois Tigeot 			I915_WRITE_IMR(ring, ~GT_PARITY_ERROR(dev));
1768686a02f1SFrançois Tigeot 		else
1769686a02f1SFrançois Tigeot 			I915_WRITE_IMR(ring, ~0);
177024edb884SFrançois Tigeot 		gen5_disable_gt_irq(dev_priv, ring->irq_enable_mask);
1771e3adcf8fSFrançois Tigeot 	}
17725e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
1773e3adcf8fSFrançois Tigeot }
1774e3adcf8fSFrançois Tigeot 
17755d0b1887SFrançois Tigeot static bool
1776ba55f2f5SFrançois Tigeot hsw_vebox_get_irq(struct intel_engine_cs *ring)
17775d0b1887SFrançois Tigeot {
17785d0b1887SFrançois Tigeot 	struct drm_device *dev = ring->dev;
17795d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
17805e269720SFrançois Tigeot 	unsigned long flags;
17815d0b1887SFrançois Tigeot 
17822c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
17835d0b1887SFrançois Tigeot 		return false;
17845d0b1887SFrançois Tigeot 
17855e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
17869edbd4a0SFrançois Tigeot 	if (ring->irq_refcount++ == 0) {
17875d0b1887SFrançois Tigeot 		I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
178824edb884SFrançois Tigeot 		gen6_enable_pm_irq(dev_priv, ring->irq_enable_mask);
17895d0b1887SFrançois Tigeot 	}
17905e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
17915d0b1887SFrançois Tigeot 
17925d0b1887SFrançois Tigeot 	return true;
17935d0b1887SFrançois Tigeot }
17945d0b1887SFrançois Tigeot 
17955d0b1887SFrançois Tigeot static void
1796ba55f2f5SFrançois Tigeot hsw_vebox_put_irq(struct intel_engine_cs *ring)
17975d0b1887SFrançois Tigeot {
17985d0b1887SFrançois Tigeot 	struct drm_device *dev = ring->dev;
17995d0b1887SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
18005e269720SFrançois Tigeot 	unsigned long flags;
18015d0b1887SFrançois Tigeot 
18025e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18039edbd4a0SFrançois Tigeot 	if (--ring->irq_refcount == 0) {
18045d0b1887SFrançois Tigeot 		I915_WRITE_IMR(ring, ~0);
180524edb884SFrançois Tigeot 		gen6_disable_pm_irq(dev_priv, ring->irq_enable_mask);
18065d0b1887SFrançois Tigeot 	}
18075e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
18089edbd4a0SFrançois Tigeot }
18099edbd4a0SFrançois Tigeot 
18109edbd4a0SFrançois Tigeot static bool
1811ba55f2f5SFrançois Tigeot gen8_ring_get_irq(struct intel_engine_cs *ring)
18129edbd4a0SFrançois Tigeot {
18139edbd4a0SFrançois Tigeot 	struct drm_device *dev = ring->dev;
18149edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
18155e269720SFrançois Tigeot 	unsigned long flags;
18169edbd4a0SFrançois Tigeot 
18172c9916cdSFrançois Tigeot 	if (WARN_ON(!intel_irqs_enabled(dev_priv)))
18189edbd4a0SFrançois Tigeot 		return false;
18199edbd4a0SFrançois Tigeot 
18205e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18219edbd4a0SFrançois Tigeot 	if (ring->irq_refcount++ == 0) {
18229edbd4a0SFrançois Tigeot 		if (HAS_L3_DPF(dev) && ring->id == RCS) {
18239edbd4a0SFrançois Tigeot 			I915_WRITE_IMR(ring,
18249edbd4a0SFrançois Tigeot 				       ~(ring->irq_enable_mask |
18259edbd4a0SFrançois Tigeot 					 GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
18269edbd4a0SFrançois Tigeot 		} else {
18279edbd4a0SFrançois Tigeot 			I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
18289edbd4a0SFrançois Tigeot 		}
18299edbd4a0SFrançois Tigeot 		POSTING_READ(RING_IMR(ring->mmio_base));
18309edbd4a0SFrançois Tigeot 	}
18315e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
18329edbd4a0SFrançois Tigeot 
18339edbd4a0SFrançois Tigeot 	return true;
18349edbd4a0SFrançois Tigeot }
18359edbd4a0SFrançois Tigeot 
18369edbd4a0SFrançois Tigeot static void
1837ba55f2f5SFrançois Tigeot gen8_ring_put_irq(struct intel_engine_cs *ring)
18389edbd4a0SFrançois Tigeot {
18399edbd4a0SFrançois Tigeot 	struct drm_device *dev = ring->dev;
18409edbd4a0SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
18415e269720SFrançois Tigeot 	unsigned long flags;
18429edbd4a0SFrançois Tigeot 
18435e269720SFrançois Tigeot 	spin_lock_irqsave(&dev_priv->irq_lock, flags);
18449edbd4a0SFrançois Tigeot 	if (--ring->irq_refcount == 0) {
18459edbd4a0SFrançois Tigeot 		if (HAS_L3_DPF(dev) && ring->id == RCS) {
18469edbd4a0SFrançois Tigeot 			I915_WRITE_IMR(ring,
18479edbd4a0SFrançois Tigeot 				       ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
18489edbd4a0SFrançois Tigeot 		} else {
18499edbd4a0SFrançois Tigeot 			I915_WRITE_IMR(ring, ~0);
18509edbd4a0SFrançois Tigeot 		}
18519edbd4a0SFrançois Tigeot 		POSTING_READ(RING_IMR(ring->mmio_base));
18529edbd4a0SFrançois Tigeot 	}
18535e269720SFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
18545d0b1887SFrançois Tigeot }
18555d0b1887SFrançois Tigeot 
1856e3adcf8fSFrançois Tigeot static int
1857a05eeebfSFrançois Tigeot i965_dispatch_execbuffer(struct drm_i915_gem_request *req,
1858ba55f2f5SFrançois Tigeot 			 u64 offset, u32 length,
1859477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1860e3adcf8fSFrançois Tigeot {
1861a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
1862e3adcf8fSFrançois Tigeot 	int ret;
1863e3adcf8fSFrançois Tigeot 
1864a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1865e3adcf8fSFrançois Tigeot 	if (ret)
1866e3adcf8fSFrançois Tigeot 		return ret;
1867e3adcf8fSFrançois Tigeot 
1868e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring,
1869686a02f1SFrançois Tigeot 			MI_BATCH_BUFFER_START |
1870b5c29a34SFrançois Tigeot 			MI_BATCH_GTT |
1871477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
1872477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
1873e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, offset);
1874e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
1875e3adcf8fSFrançois Tigeot 
1876e3adcf8fSFrançois Tigeot 	return 0;
1877e3adcf8fSFrançois Tigeot }
1878e3adcf8fSFrançois Tigeot 
1879b5c29a34SFrançois Tigeot /* Just userspace ABI convention to limit the wa batch bo to a resonable size */
1880b5c29a34SFrançois Tigeot #define I830_BATCH_LIMIT (256*1024)
188124edb884SFrançois Tigeot #define I830_TLB_ENTRIES (2)
188224edb884SFrançois Tigeot #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT)
1883e3adcf8fSFrançois Tigeot static int
1884a05eeebfSFrançois Tigeot i830_dispatch_execbuffer(struct drm_i915_gem_request *req,
1885ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
1886477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1887e3adcf8fSFrançois Tigeot {
1888a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
188924edb884SFrançois Tigeot 	u32 cs_offset = ring->scratch.gtt_offset;
1890e3adcf8fSFrançois Tigeot 	int ret;
1891e3adcf8fSFrançois Tigeot 
1892a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 6);
189324edb884SFrançois Tigeot 	if (ret)
189424edb884SFrançois Tigeot 		return ret;
189524edb884SFrançois Tigeot 
189624edb884SFrançois Tigeot 	/* Evict the invalid PTE TLBs */
189724edb884SFrançois Tigeot 	intel_ring_emit(ring, COLOR_BLT_CMD | BLT_WRITE_RGBA);
189824edb884SFrançois Tigeot 	intel_ring_emit(ring, BLT_DEPTH_32 | BLT_ROP_COLOR_COPY | 4096);
189924edb884SFrançois Tigeot 	intel_ring_emit(ring, I830_TLB_ENTRIES << 16 | 4); /* load each page */
190024edb884SFrançois Tigeot 	intel_ring_emit(ring, cs_offset);
190124edb884SFrançois Tigeot 	intel_ring_emit(ring, 0xdeadbeef);
190224edb884SFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
190324edb884SFrançois Tigeot 	intel_ring_advance(ring);
190424edb884SFrançois Tigeot 
1905477eb7f9SFrançois Tigeot 	if ((dispatch_flags & I915_DISPATCH_PINNED) == 0) {
190624edb884SFrançois Tigeot 		if (len > I830_BATCH_LIMIT)
190724edb884SFrançois Tigeot 			return -ENOSPC;
190824edb884SFrançois Tigeot 
1909a05eeebfSFrançois Tigeot 		ret = intel_ring_begin(req, 6 + 2);
191024edb884SFrançois Tigeot 		if (ret)
191124edb884SFrançois Tigeot 			return ret;
191224edb884SFrançois Tigeot 
191324edb884SFrançois Tigeot 		/* Blit the batch (which has now all relocs applied) to the
191424edb884SFrançois Tigeot 		 * stable batch scratch bo area (so that the CS never
191524edb884SFrançois Tigeot 		 * stumbles over its tlb invalidation bug) ...
191624edb884SFrançois Tigeot 		 */
191724edb884SFrançois Tigeot 		intel_ring_emit(ring, SRC_COPY_BLT_CMD | BLT_WRITE_RGBA);
191824edb884SFrançois Tigeot 		intel_ring_emit(ring, BLT_DEPTH_32 | BLT_ROP_SRC_COPY | 4096);
191924edb884SFrançois Tigeot 		intel_ring_emit(ring, DIV_ROUND_UP(len, 4096) << 16 | 4096);
192024edb884SFrançois Tigeot 		intel_ring_emit(ring, cs_offset);
192124edb884SFrançois Tigeot 		intel_ring_emit(ring, 4096);
192224edb884SFrançois Tigeot 		intel_ring_emit(ring, offset);
192324edb884SFrançois Tigeot 
192424edb884SFrançois Tigeot 		intel_ring_emit(ring, MI_FLUSH);
192524edb884SFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
192624edb884SFrançois Tigeot 		intel_ring_advance(ring);
192724edb884SFrançois Tigeot 
192824edb884SFrançois Tigeot 		/* ... and execute it. */
192924edb884SFrançois Tigeot 		offset = cs_offset;
193024edb884SFrançois Tigeot 	}
193124edb884SFrançois Tigeot 
1932*c0e85e96SFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1933e3adcf8fSFrançois Tigeot 	if (ret)
1934e3adcf8fSFrançois Tigeot 		return ret;
1935e3adcf8fSFrançois Tigeot 
1936*c0e85e96SFrançois Tigeot 	intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
1937477eb7f9SFrançois Tigeot 	intel_ring_emit(ring, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
1938477eb7f9SFrançois Tigeot 					0 : MI_BATCH_NON_SECURE));
1939686a02f1SFrançois Tigeot 	intel_ring_advance(ring);
1940686a02f1SFrançois Tigeot 
1941686a02f1SFrançois Tigeot 	return 0;
1942686a02f1SFrançois Tigeot }
1943686a02f1SFrançois Tigeot 
1944686a02f1SFrançois Tigeot static int
1945a05eeebfSFrançois Tigeot i915_dispatch_execbuffer(struct drm_i915_gem_request *req,
1946ba55f2f5SFrançois Tigeot 			 u64 offset, u32 len,
1947477eb7f9SFrançois Tigeot 			 unsigned dispatch_flags)
1948686a02f1SFrançois Tigeot {
1949a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
1950686a02f1SFrançois Tigeot 	int ret;
1951686a02f1SFrançois Tigeot 
1952a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
1953e3adcf8fSFrançois Tigeot 	if (ret)
1954e3adcf8fSFrançois Tigeot 		return ret;
1955e3adcf8fSFrançois Tigeot 
1956686a02f1SFrançois Tigeot 	intel_ring_emit(ring, MI_BATCH_BUFFER_START | MI_BATCH_GTT);
1957477eb7f9SFrançois Tigeot 	intel_ring_emit(ring, offset | (dispatch_flags & I915_DISPATCH_SECURE ?
1958477eb7f9SFrançois Tigeot 					0 : MI_BATCH_NON_SECURE));
1959e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
1960e3adcf8fSFrançois Tigeot 
1961e3adcf8fSFrançois Tigeot 	return 0;
1962e3adcf8fSFrançois Tigeot }
1963e3adcf8fSFrançois Tigeot 
1964*c0e85e96SFrançois Tigeot static void cleanup_phys_status_page(struct intel_engine_cs *ring)
1965*c0e85e96SFrançois Tigeot {
1966*c0e85e96SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(ring->dev);
1967*c0e85e96SFrançois Tigeot 
1968*c0e85e96SFrançois Tigeot 	if (!dev_priv->status_page_dmah)
1969*c0e85e96SFrançois Tigeot 		return;
1970*c0e85e96SFrançois Tigeot 
1971*c0e85e96SFrançois Tigeot 	drm_pci_free(ring->dev, dev_priv->status_page_dmah);
1972*c0e85e96SFrançois Tigeot 	ring->status_page.page_addr = NULL;
1973*c0e85e96SFrançois Tigeot }
1974*c0e85e96SFrançois Tigeot 
1975ba55f2f5SFrançois Tigeot static void cleanup_status_page(struct intel_engine_cs *ring)
1976e3adcf8fSFrançois Tigeot {
1977e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
1978e3adcf8fSFrançois Tigeot 
1979e3adcf8fSFrançois Tigeot 	obj = ring->status_page.obj;
1980e3adcf8fSFrançois Tigeot 	if (obj == NULL)
1981e3adcf8fSFrançois Tigeot 		return;
1982e3adcf8fSFrançois Tigeot 
19837ec9f8e5SFrançois Tigeot 	kunmap(sg_page(obj->pages->sgl));
1984ba55f2f5SFrançois Tigeot 	i915_gem_object_ggtt_unpin(obj);
1985e3adcf8fSFrançois Tigeot 	drm_gem_object_unreference(&obj->base);
1986e3adcf8fSFrançois Tigeot 	ring->status_page.obj = NULL;
1987e3adcf8fSFrançois Tigeot }
1988e3adcf8fSFrançois Tigeot 
1989ba55f2f5SFrançois Tigeot static int init_status_page(struct intel_engine_cs *ring)
1990e3adcf8fSFrançois Tigeot {
1991*c0e85e96SFrançois Tigeot 	struct drm_i915_gem_object *obj = ring->status_page.obj;
1992ba55f2f5SFrançois Tigeot 
1993*c0e85e96SFrançois Tigeot 	if (obj == NULL) {
199424edb884SFrançois Tigeot 		unsigned flags;
1995e3adcf8fSFrançois Tigeot 		int ret;
1996e3adcf8fSFrançois Tigeot 
1997ba55f2f5SFrançois Tigeot 		obj = i915_gem_alloc_object(ring->dev, 4096);
1998e3adcf8fSFrançois Tigeot 		if (obj == NULL) {
1999e3adcf8fSFrançois Tigeot 			DRM_ERROR("Failed to allocate status page\n");
2000ba55f2f5SFrançois Tigeot 			return -ENOMEM;
2001e3adcf8fSFrançois Tigeot 		}
2002e3adcf8fSFrançois Tigeot 
2003ba55f2f5SFrançois Tigeot 		ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
2004ba55f2f5SFrançois Tigeot 		if (ret)
2005e3adcf8fSFrançois Tigeot 			goto err_unref;
2006ba55f2f5SFrançois Tigeot 
200724edb884SFrançois Tigeot 		flags = 0;
200824edb884SFrançois Tigeot 		if (!HAS_LLC(ring->dev))
200924edb884SFrançois Tigeot 			/* On g33, we cannot place HWS above 256MiB, so
201024edb884SFrançois Tigeot 			 * restrict its pinning to the low mappable arena.
201124edb884SFrançois Tigeot 			 * Though this restriction is not documented for
201224edb884SFrançois Tigeot 			 * gen4, gen5, or byt, they also behave similarly
201324edb884SFrançois Tigeot 			 * and hang if the HWS is placed at the top of the
201424edb884SFrançois Tigeot 			 * GTT. To generalise, it appears that all !llc
201524edb884SFrançois Tigeot 			 * platforms have issues with us placing the HWS
201624edb884SFrançois Tigeot 			 * above the mappable region (even though we never
201724edb884SFrançois Tigeot 			 * actualy map it).
201824edb884SFrançois Tigeot 			 */
201924edb884SFrançois Tigeot 			flags |= PIN_MAPPABLE;
202024edb884SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 4096, flags);
2021ba55f2f5SFrançois Tigeot 		if (ret) {
2022ba55f2f5SFrançois Tigeot err_unref:
2023ba55f2f5SFrançois Tigeot 			drm_gem_object_unreference(&obj->base);
2024ba55f2f5SFrançois Tigeot 			return ret;
2025ba55f2f5SFrançois Tigeot 		}
2026ba55f2f5SFrançois Tigeot 
2027ba55f2f5SFrançois Tigeot 		ring->status_page.obj = obj;
2028e3adcf8fSFrançois Tigeot 	}
2029e3adcf8fSFrançois Tigeot 
20309edbd4a0SFrançois Tigeot 	ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
20317ec9f8e5SFrançois Tigeot 	ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
2032e3adcf8fSFrançois Tigeot 	memset(ring->status_page.page_addr, 0, PAGE_SIZE);
2033e3adcf8fSFrançois Tigeot 
2034b5c29a34SFrançois Tigeot 	DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
2035e3adcf8fSFrançois Tigeot 			ring->name, ring->status_page.gfx_addr);
2036e3adcf8fSFrançois Tigeot 
2037e3adcf8fSFrançois Tigeot 	return 0;
2038e3adcf8fSFrançois Tigeot }
2039e3adcf8fSFrançois Tigeot 
2040ba55f2f5SFrançois Tigeot static int init_phys_status_page(struct intel_engine_cs *ring)
2041686a02f1SFrançois Tigeot {
2042686a02f1SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
2043686a02f1SFrançois Tigeot 
2044686a02f1SFrançois Tigeot 	if (!dev_priv->status_page_dmah) {
2045686a02f1SFrançois Tigeot 		dev_priv->status_page_dmah =
2046b31e9d59SFrançois Tigeot 			drm_pci_alloc(ring->dev, PAGE_SIZE, PAGE_SIZE);
2047686a02f1SFrançois Tigeot 		if (!dev_priv->status_page_dmah)
2048686a02f1SFrançois Tigeot 			return -ENOMEM;
2049686a02f1SFrançois Tigeot 	}
2050686a02f1SFrançois Tigeot 
2051686a02f1SFrançois Tigeot 	ring->status_page.page_addr = dev_priv->status_page_dmah->vaddr;
2052686a02f1SFrançois Tigeot 	memset(ring->status_page.page_addr, 0, PAGE_SIZE);
2053686a02f1SFrançois Tigeot 
2054686a02f1SFrançois Tigeot 	return 0;
2055686a02f1SFrançois Tigeot }
2056686a02f1SFrançois Tigeot 
20572c9916cdSFrançois Tigeot void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
20582c9916cdSFrançois Tigeot {
2059aee94f86SFrançois Tigeot 	if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen)
20606fe294aeSMatthew Dillon 		vunmap(ringbuf->virtual_start, ringbuf->virtual_count);
2061aee94f86SFrançois Tigeot 	else
206224409b39SFrançois Tigeot 		iounmap(ringbuf->virtual_start);
20632c9916cdSFrançois Tigeot 	ringbuf->virtual_start = NULL;
2064*c0e85e96SFrançois Tigeot 	ringbuf->vma = NULL;
20652c9916cdSFrançois Tigeot 	i915_gem_object_ggtt_unpin(ringbuf->obj);
20662c9916cdSFrançois Tigeot }
20672c9916cdSFrançois Tigeot 
20686fe294aeSMatthew Dillon static u32 *vmap_obj(struct drm_i915_gem_object *obj, unsigned int *countp)
2069aee94f86SFrançois Tigeot {
2070aee94f86SFrançois Tigeot 	struct sg_page_iter sg_iter;
2071aee94f86SFrançois Tigeot 	struct vm_page **pages;
2072aee94f86SFrançois Tigeot 	void *addr;
2073aee94f86SFrançois Tigeot 	int i;
2074aee94f86SFrançois Tigeot 
2075aee94f86SFrançois Tigeot 	pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
2076aee94f86SFrançois Tigeot 	if (pages == NULL)
2077aee94f86SFrançois Tigeot 		return NULL;
2078aee94f86SFrançois Tigeot 
2079aee94f86SFrançois Tigeot 	i = 0;
2080aee94f86SFrançois Tigeot 	for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0)
2081aee94f86SFrançois Tigeot 		pages[i++] = sg_page_iter_page(&sg_iter);
20826fe294aeSMatthew Dillon 	*countp = i;
2083aee94f86SFrançois Tigeot 
2084aee94f86SFrançois Tigeot 	addr = vmap(pages, i, 0, PAGE_KERNEL);
2085aee94f86SFrançois Tigeot 	drm_free_large(pages);
2086aee94f86SFrançois Tigeot 
2087aee94f86SFrançois Tigeot 	return addr;
2088aee94f86SFrançois Tigeot }
2089aee94f86SFrançois Tigeot 
20902c9916cdSFrançois Tigeot int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,
20912c9916cdSFrançois Tigeot 				     struct intel_ringbuffer *ringbuf)
20922c9916cdSFrançois Tigeot {
20932c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
20942c9916cdSFrançois Tigeot 	struct drm_i915_gem_object *obj = ringbuf->obj;
2095*c0e85e96SFrançois Tigeot 	/* Ring wraparound at offset 0 sometimes hangs. No idea why. */
2096*c0e85e96SFrançois Tigeot 	unsigned flags = PIN_OFFSET_BIAS | 4096;
20972c9916cdSFrançois Tigeot 	int ret;
20982c9916cdSFrançois Tigeot 
2099aee94f86SFrançois Tigeot 	if (HAS_LLC(dev_priv) && !obj->stolen) {
2100*c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, flags);
2101aee94f86SFrançois Tigeot 		if (ret)
2102aee94f86SFrançois Tigeot 			return ret;
2103aee94f86SFrançois Tigeot 
2104aee94f86SFrançois Tigeot 		ret = i915_gem_object_set_to_cpu_domain(obj, true);
2105aee94f86SFrançois Tigeot 		if (ret) {
2106aee94f86SFrançois Tigeot 			i915_gem_object_ggtt_unpin(obj);
2107aee94f86SFrançois Tigeot 			return ret;
2108aee94f86SFrançois Tigeot 		}
2109aee94f86SFrançois Tigeot 
21106fe294aeSMatthew Dillon 		ringbuf->virtual_start = (char *)vmap_obj(obj,
21116fe294aeSMatthew Dillon 						    &ringbuf->virtual_count);
2112aee94f86SFrançois Tigeot 		if (ringbuf->virtual_start == NULL) {
2113aee94f86SFrançois Tigeot 			i915_gem_object_ggtt_unpin(obj);
2114aee94f86SFrançois Tigeot 			return -ENOMEM;
2115aee94f86SFrançois Tigeot 		}
2116aee94f86SFrançois Tigeot 	} else {
2117*c0e85e96SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE,
2118*c0e85e96SFrançois Tigeot 					    flags | PIN_MAPPABLE);
21192c9916cdSFrançois Tigeot 		if (ret)
21202c9916cdSFrançois Tigeot 			return ret;
21212c9916cdSFrançois Tigeot 
21222c9916cdSFrançois Tigeot 		ret = i915_gem_object_set_to_gtt_domain(obj, true);
21232c9916cdSFrançois Tigeot 		if (ret) {
21242c9916cdSFrançois Tigeot 			i915_gem_object_ggtt_unpin(obj);
21252c9916cdSFrançois Tigeot 			return ret;
21262c9916cdSFrançois Tigeot 		}
21272c9916cdSFrançois Tigeot 
2128*c0e85e96SFrançois Tigeot 		/* Access through the GTT requires the device to be awake. */
2129*c0e85e96SFrançois Tigeot 		assert_rpm_wakelock_held(dev_priv);
2130*c0e85e96SFrançois Tigeot 
21312c9916cdSFrançois Tigeot 		ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +
21322c9916cdSFrançois Tigeot 						    i915_gem_obj_ggtt_offset(obj), ringbuf->size);
21332c9916cdSFrançois Tigeot 		if (ringbuf->virtual_start == NULL) {
21342c9916cdSFrançois Tigeot 			i915_gem_object_ggtt_unpin(obj);
21352c9916cdSFrançois Tigeot 			return -EINVAL;
21362c9916cdSFrançois Tigeot 		}
2137aee94f86SFrançois Tigeot 	}
21382c9916cdSFrançois Tigeot 
2139*c0e85e96SFrançois Tigeot 	ringbuf->vma = i915_gem_obj_to_ggtt(obj);
2140*c0e85e96SFrançois Tigeot 
21412c9916cdSFrançois Tigeot 	return 0;
21422c9916cdSFrançois Tigeot }
21432c9916cdSFrançois Tigeot 
2144352ff8bdSFrançois Tigeot static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
2145e3adcf8fSFrançois Tigeot {
214624edb884SFrançois Tigeot 	drm_gem_object_unreference(&ringbuf->obj->base);
214724edb884SFrançois Tigeot 	ringbuf->obj = NULL;
214824edb884SFrançois Tigeot }
214924edb884SFrançois Tigeot 
2150352ff8bdSFrançois Tigeot static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
215124edb884SFrançois Tigeot 				      struct intel_ringbuffer *ringbuf)
215224edb884SFrançois Tigeot {
2153e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_object *obj;
2154e3adcf8fSFrançois Tigeot 
2155a2fdbec6SFrançois Tigeot 	obj = NULL;
2156a2fdbec6SFrançois Tigeot 	if (!HAS_LLC(dev))
2157ba55f2f5SFrançois Tigeot 		obj = i915_gem_object_create_stolen(dev, ringbuf->size);
2158a2fdbec6SFrançois Tigeot 	if (obj == NULL)
2159ba55f2f5SFrançois Tigeot 		obj = i915_gem_alloc_object(dev, ringbuf->size);
2160ba55f2f5SFrançois Tigeot 	if (obj == NULL)
2161ba55f2f5SFrançois Tigeot 		return -ENOMEM;
2162e3adcf8fSFrançois Tigeot 
216324edb884SFrançois Tigeot 	/* mark ring buffers as read-only from GPU side by default */
216424edb884SFrançois Tigeot 	obj->gt_ro = 1;
216524edb884SFrançois Tigeot 
2166ba55f2f5SFrançois Tigeot 	ringbuf->obj = obj;
2167ba55f2f5SFrançois Tigeot 
21682c9916cdSFrançois Tigeot 	return 0;
2169ba55f2f5SFrançois Tigeot }
2170ba55f2f5SFrançois Tigeot 
2171352ff8bdSFrançois Tigeot struct intel_ringbuffer *
2172352ff8bdSFrançois Tigeot intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size)
2173352ff8bdSFrançois Tigeot {
2174352ff8bdSFrançois Tigeot 	struct intel_ringbuffer *ring;
2175352ff8bdSFrançois Tigeot 	int ret;
2176352ff8bdSFrançois Tigeot 
2177352ff8bdSFrançois Tigeot 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
2178aee94f86SFrançois Tigeot 	if (ring == NULL) {
2179aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
2180aee94f86SFrançois Tigeot 				 engine->name);
2181352ff8bdSFrançois Tigeot 		return ERR_PTR(-ENOMEM);
2182aee94f86SFrançois Tigeot 	}
2183352ff8bdSFrançois Tigeot 
2184352ff8bdSFrançois Tigeot 	ring->ring = engine;
2185aee94f86SFrançois Tigeot 	list_add(&ring->link, &engine->buffers);
2186352ff8bdSFrançois Tigeot 
2187352ff8bdSFrançois Tigeot 	ring->size = size;
2188352ff8bdSFrançois Tigeot 	/* Workaround an erratum on the i830 which causes a hang if
2189352ff8bdSFrançois Tigeot 	 * the TAIL pointer points to within the last 2 cachelines
2190352ff8bdSFrançois Tigeot 	 * of the buffer.
2191352ff8bdSFrançois Tigeot 	 */
2192352ff8bdSFrançois Tigeot 	ring->effective_size = size;
2193352ff8bdSFrançois Tigeot 	if (IS_I830(engine->dev) || IS_845G(engine->dev))
2194352ff8bdSFrançois Tigeot 		ring->effective_size -= 2 * CACHELINE_BYTES;
2195352ff8bdSFrançois Tigeot 
2196352ff8bdSFrançois Tigeot 	ring->last_retired_head = -1;
2197352ff8bdSFrançois Tigeot 	intel_ring_update_space(ring);
2198352ff8bdSFrançois Tigeot 
2199352ff8bdSFrançois Tigeot 	ret = intel_alloc_ringbuffer_obj(engine->dev, ring);
2200352ff8bdSFrançois Tigeot 	if (ret) {
2201aee94f86SFrançois Tigeot 		DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n",
2202352ff8bdSFrançois Tigeot 				 engine->name, ret);
2203aee94f86SFrançois Tigeot 		list_del(&ring->link);
2204352ff8bdSFrançois Tigeot 		kfree(ring);
2205352ff8bdSFrançois Tigeot 		return ERR_PTR(ret);
2206352ff8bdSFrançois Tigeot 	}
2207352ff8bdSFrançois Tigeot 
2208352ff8bdSFrançois Tigeot 	return ring;
2209352ff8bdSFrançois Tigeot }
2210352ff8bdSFrançois Tigeot 
2211352ff8bdSFrançois Tigeot void
2212352ff8bdSFrançois Tigeot intel_ringbuffer_free(struct intel_ringbuffer *ring)
2213352ff8bdSFrançois Tigeot {
2214352ff8bdSFrançois Tigeot 	intel_destroy_ringbuffer_obj(ring);
2215aee94f86SFrançois Tigeot 	list_del(&ring->link);
2216352ff8bdSFrançois Tigeot 	kfree(ring);
2217352ff8bdSFrançois Tigeot }
2218352ff8bdSFrançois Tigeot 
2219ba55f2f5SFrançois Tigeot static int intel_init_ring_buffer(struct drm_device *dev,
2220ba55f2f5SFrançois Tigeot 				  struct intel_engine_cs *ring)
2221ba55f2f5SFrançois Tigeot {
22222c9916cdSFrançois Tigeot 	struct intel_ringbuffer *ringbuf;
2223ba55f2f5SFrançois Tigeot 	int ret;
2224ba55f2f5SFrançois Tigeot 
22252c9916cdSFrançois Tigeot 	WARN_ON(ring->buffer);
22262c9916cdSFrançois Tigeot 
2227ba55f2f5SFrançois Tigeot 	ring->dev = dev;
2228ba55f2f5SFrançois Tigeot 	INIT_LIST_HEAD(&ring->active_list);
2229ba55f2f5SFrançois Tigeot 	INIT_LIST_HEAD(&ring->request_list);
22301b13d190SFrançois Tigeot 	INIT_LIST_HEAD(&ring->execlist_queue);
2231aee94f86SFrançois Tigeot 	INIT_LIST_HEAD(&ring->buffers);
223219c468b4SFrançois Tigeot 	i915_gem_batch_pool_init(dev, &ring->batch_pool);
2233ba55f2f5SFrançois Tigeot 	memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
2234ba55f2f5SFrançois Tigeot 
2235ba55f2f5SFrançois Tigeot 	init_waitqueue_head(&ring->irq_queue);
2236ba55f2f5SFrançois Tigeot 
2237352ff8bdSFrançois Tigeot 	ringbuf = intel_engine_create_ringbuffer(ring, 32 * PAGE_SIZE);
2238aee94f86SFrançois Tigeot 	if (IS_ERR(ringbuf)) {
2239aee94f86SFrançois Tigeot 		ret = PTR_ERR(ringbuf);
2240aee94f86SFrançois Tigeot 		goto error;
2241aee94f86SFrançois Tigeot 	}
2242352ff8bdSFrançois Tigeot 	ring->buffer = ringbuf;
2243352ff8bdSFrançois Tigeot 
2244ba55f2f5SFrançois Tigeot 	if (I915_NEED_GFX_HWS(dev)) {
2245ba55f2f5SFrançois Tigeot 		ret = init_status_page(ring);
2246e3adcf8fSFrançois Tigeot 		if (ret)
2247ba55f2f5SFrançois Tigeot 			goto error;
2248ba55f2f5SFrançois Tigeot 	} else {
2249*c0e85e96SFrançois Tigeot 		WARN_ON(ring->id != RCS);
2250ba55f2f5SFrançois Tigeot 		ret = init_phys_status_page(ring);
2251ba55f2f5SFrançois Tigeot 		if (ret)
2252ba55f2f5SFrançois Tigeot 			goto error;
2253ba55f2f5SFrançois Tigeot 	}
2254ba55f2f5SFrançois Tigeot 
22552c9916cdSFrançois Tigeot 	ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
22562c9916cdSFrançois Tigeot 	if (ret) {
22572c9916cdSFrançois Tigeot 		DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
22582c9916cdSFrançois Tigeot 				ring->name, ret);
22592c9916cdSFrançois Tigeot 		intel_destroy_ringbuffer_obj(ringbuf);
2260ba55f2f5SFrançois Tigeot 		goto error;
2261ba55f2f5SFrançois Tigeot 	}
2262e3adcf8fSFrançois Tigeot 
2263ba55f2f5SFrançois Tigeot 	ret = i915_cmd_parser_init_ring(ring);
2264ba55f2f5SFrançois Tigeot 	if (ret)
2265ba55f2f5SFrançois Tigeot 		goto error;
2266ba55f2f5SFrançois Tigeot 
2267e3adcf8fSFrançois Tigeot 	return 0;
2268e3adcf8fSFrançois Tigeot 
2269ba55f2f5SFrançois Tigeot error:
2270aee94f86SFrançois Tigeot 	intel_cleanup_ring_buffer(ring);
2271e3adcf8fSFrançois Tigeot 	return ret;
2272e3adcf8fSFrançois Tigeot }
2273e3adcf8fSFrançois Tigeot 
2274ba55f2f5SFrançois Tigeot void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
2275e3adcf8fSFrançois Tigeot {
22762c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv;
2277e3adcf8fSFrançois Tigeot 
2278ba55f2f5SFrançois Tigeot 	if (!intel_ring_initialized(ring))
2279e3adcf8fSFrançois Tigeot 		return;
2280e3adcf8fSFrançois Tigeot 
22812c9916cdSFrançois Tigeot 	dev_priv = to_i915(ring->dev);
22822c9916cdSFrançois Tigeot 
2283aee94f86SFrançois Tigeot 	if (ring->buffer) {
2284ba55f2f5SFrançois Tigeot 		intel_stop_ring_buffer(ring);
2285ba55f2f5SFrançois Tigeot 		WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0);
2286b030f26bSFrançois Tigeot 
2287352ff8bdSFrançois Tigeot 		intel_unpin_ringbuffer_obj(ring->buffer);
2288352ff8bdSFrançois Tigeot 		intel_ringbuffer_free(ring->buffer);
2289352ff8bdSFrançois Tigeot 		ring->buffer = NULL;
2290aee94f86SFrançois Tigeot 	}
2291e3adcf8fSFrançois Tigeot 
2292e3adcf8fSFrançois Tigeot 	if (ring->cleanup)
2293e3adcf8fSFrançois Tigeot 		ring->cleanup(ring);
2294e3adcf8fSFrançois Tigeot 
2295*c0e85e96SFrançois Tigeot 	if (I915_NEED_GFX_HWS(ring->dev)) {
2296e3adcf8fSFrançois Tigeot 		cleanup_status_page(ring);
2297*c0e85e96SFrançois Tigeot 	} else {
2298*c0e85e96SFrançois Tigeot 		WARN_ON(ring->id != RCS);
2299*c0e85e96SFrançois Tigeot 		cleanup_phys_status_page(ring);
2300*c0e85e96SFrançois Tigeot 	}
2301ba55f2f5SFrançois Tigeot 
2302ba55f2f5SFrançois Tigeot 	i915_cmd_parser_fini_ring(ring);
230319c468b4SFrançois Tigeot 	i915_gem_batch_pool_fini(&ring->batch_pool);
2304aee94f86SFrançois Tigeot 	ring->dev = NULL;
2305e3adcf8fSFrançois Tigeot }
2306e3adcf8fSFrançois Tigeot 
230719c468b4SFrançois Tigeot static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
2308e3adcf8fSFrançois Tigeot {
2309ba55f2f5SFrançois Tigeot 	struct intel_ringbuffer *ringbuf = ring->buffer;
2310e3adcf8fSFrançois Tigeot 	struct drm_i915_gem_request *request;
231119c468b4SFrançois Tigeot 	unsigned space;
2312e3adcf8fSFrançois Tigeot 	int ret;
2313e3adcf8fSFrançois Tigeot 
23142c9916cdSFrançois Tigeot 	if (intel_ring_space(ringbuf) >= n)
2315e3adcf8fSFrançois Tigeot 		return 0;
2316e3adcf8fSFrançois Tigeot 
2317a05eeebfSFrançois Tigeot 	/* The whole point of reserving space is to not wait! */
2318a05eeebfSFrançois Tigeot 	WARN_ON(ringbuf->reserved_in_use);
2319a05eeebfSFrançois Tigeot 
2320e3adcf8fSFrançois Tigeot 	list_for_each_entry(request, &ring->request_list, list) {
232119c468b4SFrançois Tigeot 		space = __intel_ring_space(request->postfix, ringbuf->tail,
232219c468b4SFrançois Tigeot 					   ringbuf->size);
232319c468b4SFrançois Tigeot 		if (space >= n)
2324e3adcf8fSFrançois Tigeot 			break;
2325e3adcf8fSFrançois Tigeot 	}
2326e3adcf8fSFrançois Tigeot 
232719c468b4SFrançois Tigeot 	if (WARN_ON(&request->list == &ring->request_list))
2328e3adcf8fSFrançois Tigeot 		return -ENOSPC;
2329e3adcf8fSFrançois Tigeot 
23302c9916cdSFrançois Tigeot 	ret = i915_wait_request(request);
2331e3adcf8fSFrançois Tigeot 	if (ret)
2332e3adcf8fSFrançois Tigeot 		return ret;
2333e3adcf8fSFrançois Tigeot 
233419c468b4SFrançois Tigeot 	ringbuf->space = space;
2335e3adcf8fSFrançois Tigeot 	return 0;
2336e3adcf8fSFrançois Tigeot }
2337e3adcf8fSFrançois Tigeot 
2338a05eeebfSFrançois Tigeot static void __wrap_ring_buffer(struct intel_ringbuffer *ringbuf)
2339b030f26bSFrançois Tigeot {
2340b030f26bSFrançois Tigeot 	uint32_t __iomem *virt;
2341ba55f2f5SFrançois Tigeot 	int rem = ringbuf->size - ringbuf->tail;
2342b030f26bSFrançois Tigeot 
2343ba55f2f5SFrançois Tigeot 	virt = (unsigned int *)((char *)ringbuf->virtual_start + ringbuf->tail);
2344b030f26bSFrançois Tigeot 	rem /= 4;
2345b030f26bSFrançois Tigeot 	while (rem--)
2346686a02f1SFrançois Tigeot 		iowrite32(MI_NOOP, virt++);
2347b030f26bSFrançois Tigeot 
2348ba55f2f5SFrançois Tigeot 	ringbuf->tail = 0;
23492c9916cdSFrançois Tigeot 	intel_ring_update_space(ringbuf);
2350b030f26bSFrançois Tigeot }
2351b030f26bSFrançois Tigeot 
2352ba55f2f5SFrançois Tigeot int intel_ring_idle(struct intel_engine_cs *ring)
2353b030f26bSFrançois Tigeot {
23542c9916cdSFrançois Tigeot 	struct drm_i915_gem_request *req;
2355b5c29a34SFrançois Tigeot 
2356b5c29a34SFrançois Tigeot 	/* Wait upon the last request to be completed */
2357b5c29a34SFrançois Tigeot 	if (list_empty(&ring->request_list))
2358b5c29a34SFrançois Tigeot 		return 0;
2359b5c29a34SFrançois Tigeot 
23602c9916cdSFrançois Tigeot 	req = list_entry(ring->request_list.prev,
2361b5c29a34SFrançois Tigeot 			struct drm_i915_gem_request,
23622c9916cdSFrançois Tigeot 			list);
2363b5c29a34SFrançois Tigeot 
236419c468b4SFrançois Tigeot 	/* Make sure we do not trigger any retires */
236519c468b4SFrançois Tigeot 	return __i915_wait_request(req,
236619c468b4SFrançois Tigeot 				   atomic_read(&to_i915(ring->dev)->gpu_error.reset_counter),
236719c468b4SFrançois Tigeot 				   to_i915(ring->dev)->mm.interruptible,
236819c468b4SFrançois Tigeot 				   NULL, NULL);
2369b5c29a34SFrançois Tigeot }
2370b5c29a34SFrançois Tigeot 
237119c468b4SFrançois Tigeot int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
2372b5c29a34SFrançois Tigeot {
237319c468b4SFrançois Tigeot 	request->ringbuf = request->ring->buffer;
23742c9916cdSFrançois Tigeot 	return 0;
23759edbd4a0SFrançois Tigeot }
23769edbd4a0SFrançois Tigeot 
2377a05eeebfSFrançois Tigeot int intel_ring_reserve_space(struct drm_i915_gem_request *request)
2378a2fdbec6SFrançois Tigeot {
2379a05eeebfSFrançois Tigeot 	/*
2380a05eeebfSFrançois Tigeot 	 * The first call merely notes the reserve request and is common for
2381a05eeebfSFrançois Tigeot 	 * all back ends. The subsequent localised _begin() call actually
2382a05eeebfSFrançois Tigeot 	 * ensures that the reservation is available. Without the begin, if
2383a05eeebfSFrançois Tigeot 	 * the request creator immediately submitted the request without
2384a05eeebfSFrançois Tigeot 	 * adding any commands to it then there might not actually be
2385a05eeebfSFrançois Tigeot 	 * sufficient room for the submission commands.
2386a05eeebfSFrançois Tigeot 	 */
2387a05eeebfSFrançois Tigeot 	intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST);
2388a2fdbec6SFrançois Tigeot 
2389a05eeebfSFrançois Tigeot 	return intel_ring_begin(request, 0);
2390a2fdbec6SFrançois Tigeot }
2391a2fdbec6SFrançois Tigeot 
2392a05eeebfSFrançois Tigeot void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size)
2393a05eeebfSFrançois Tigeot {
2394a05eeebfSFrançois Tigeot 	WARN_ON(ringbuf->reserved_size);
2395a05eeebfSFrançois Tigeot 	WARN_ON(ringbuf->reserved_in_use);
2396a05eeebfSFrançois Tigeot 
2397a05eeebfSFrançois Tigeot 	ringbuf->reserved_size = size;
2398a05eeebfSFrançois Tigeot }
2399a05eeebfSFrançois Tigeot 
2400a05eeebfSFrançois Tigeot void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf)
2401a05eeebfSFrançois Tigeot {
2402a05eeebfSFrançois Tigeot 	WARN_ON(ringbuf->reserved_in_use);
2403a05eeebfSFrançois Tigeot 
2404a05eeebfSFrançois Tigeot 	ringbuf->reserved_size   = 0;
2405a05eeebfSFrançois Tigeot 	ringbuf->reserved_in_use = false;
2406a05eeebfSFrançois Tigeot }
2407a05eeebfSFrançois Tigeot 
2408a05eeebfSFrançois Tigeot void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf)
2409a05eeebfSFrançois Tigeot {
2410a05eeebfSFrançois Tigeot 	WARN_ON(ringbuf->reserved_in_use);
2411a05eeebfSFrançois Tigeot 
2412a05eeebfSFrançois Tigeot 	ringbuf->reserved_in_use = true;
2413a05eeebfSFrançois Tigeot 	ringbuf->reserved_tail   = ringbuf->tail;
2414a05eeebfSFrançois Tigeot }
2415a05eeebfSFrançois Tigeot 
2416a05eeebfSFrançois Tigeot void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf)
2417a05eeebfSFrançois Tigeot {
2418a05eeebfSFrançois Tigeot 	WARN_ON(!ringbuf->reserved_in_use);
2419a05eeebfSFrançois Tigeot 	if (ringbuf->tail > ringbuf->reserved_tail) {
2420a05eeebfSFrançois Tigeot 		WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size,
2421a05eeebfSFrançois Tigeot 		     "request reserved size too small: %d vs %d!\n",
2422a05eeebfSFrançois Tigeot 		     ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size);
2423a05eeebfSFrançois Tigeot 	} else {
2424a05eeebfSFrançois Tigeot 		/*
2425a05eeebfSFrançois Tigeot 		 * The ring was wrapped while the reserved space was in use.
2426a05eeebfSFrançois Tigeot 		 * That means that some unknown amount of the ring tail was
2427a05eeebfSFrançois Tigeot 		 * no-op filled and skipped. Thus simply adding the ring size
2428a05eeebfSFrançois Tigeot 		 * to the tail and doing the above space check will not work.
2429a05eeebfSFrançois Tigeot 		 * Rather than attempt to track how much tail was skipped,
2430a05eeebfSFrançois Tigeot 		 * it is much simpler to say that also skipping the sanity
2431a05eeebfSFrançois Tigeot 		 * check every once in a while is not a big issue.
2432a05eeebfSFrançois Tigeot 		 */
2433a05eeebfSFrançois Tigeot 	}
2434a05eeebfSFrançois Tigeot 
2435a05eeebfSFrançois Tigeot 	ringbuf->reserved_size   = 0;
2436a05eeebfSFrançois Tigeot 	ringbuf->reserved_in_use = false;
2437a05eeebfSFrançois Tigeot }
2438a05eeebfSFrançois Tigeot 
2439a05eeebfSFrançois Tigeot static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes)
2440a05eeebfSFrançois Tigeot {
2441a05eeebfSFrançois Tigeot 	struct intel_ringbuffer *ringbuf = ring->buffer;
2442a05eeebfSFrançois Tigeot 	int remain_usable = ringbuf->effective_size - ringbuf->tail;
2443a05eeebfSFrançois Tigeot 	int remain_actual = ringbuf->size - ringbuf->tail;
2444a05eeebfSFrançois Tigeot 	int ret, total_bytes, wait_bytes = 0;
2445a05eeebfSFrançois Tigeot 	bool need_wrap = false;
2446a05eeebfSFrançois Tigeot 
2447a05eeebfSFrançois Tigeot 	if (ringbuf->reserved_in_use)
2448a05eeebfSFrançois Tigeot 		total_bytes = bytes;
2449a05eeebfSFrançois Tigeot 	else
2450a05eeebfSFrançois Tigeot 		total_bytes = bytes + ringbuf->reserved_size;
2451a05eeebfSFrançois Tigeot 
2452a05eeebfSFrançois Tigeot 	if (unlikely(bytes > remain_usable)) {
2453a05eeebfSFrançois Tigeot 		/*
2454a05eeebfSFrançois Tigeot 		 * Not enough space for the basic request. So need to flush
2455a05eeebfSFrançois Tigeot 		 * out the remainder and then wait for base + reserved.
2456a05eeebfSFrançois Tigeot 		 */
2457a05eeebfSFrançois Tigeot 		wait_bytes = remain_actual + total_bytes;
2458a05eeebfSFrançois Tigeot 		need_wrap = true;
2459a05eeebfSFrançois Tigeot 	} else {
2460a05eeebfSFrançois Tigeot 		if (unlikely(total_bytes > remain_usable)) {
2461a05eeebfSFrançois Tigeot 			/*
2462a05eeebfSFrançois Tigeot 			 * The base request will fit but the reserved space
2463*c0e85e96SFrançois Tigeot 			 * falls off the end. So don't need an immediate wrap
2464*c0e85e96SFrançois Tigeot 			 * and only need to effectively wait for the reserved
2465*c0e85e96SFrançois Tigeot 			 * size space from the start of ringbuffer.
2466a05eeebfSFrançois Tigeot 			 */
2467a05eeebfSFrançois Tigeot 			wait_bytes = remain_actual + ringbuf->reserved_size;
2468a05eeebfSFrançois Tigeot 		} else if (total_bytes > ringbuf->space) {
2469a05eeebfSFrançois Tigeot 			/* No wrapping required, just waiting. */
2470a05eeebfSFrançois Tigeot 			wait_bytes = total_bytes;
2471a05eeebfSFrançois Tigeot 		}
2472a05eeebfSFrançois Tigeot 	}
2473a05eeebfSFrançois Tigeot 
2474a05eeebfSFrançois Tigeot 	if (wait_bytes) {
2475a05eeebfSFrançois Tigeot 		ret = ring_wait_for_space(ring, wait_bytes);
2476a2fdbec6SFrançois Tigeot 		if (unlikely(ret))
2477a2fdbec6SFrançois Tigeot 			return ret;
2478a05eeebfSFrançois Tigeot 
2479a05eeebfSFrançois Tigeot 		if (need_wrap)
2480a05eeebfSFrançois Tigeot 			__wrap_ring_buffer(ringbuf);
2481a2fdbec6SFrançois Tigeot 	}
2482a2fdbec6SFrançois Tigeot 
2483a2fdbec6SFrançois Tigeot 	return 0;
2484a2fdbec6SFrançois Tigeot }
2485a2fdbec6SFrançois Tigeot 
2486a05eeebfSFrançois Tigeot int intel_ring_begin(struct drm_i915_gem_request *req,
2487e3adcf8fSFrançois Tigeot 		     int num_dwords)
2488e3adcf8fSFrançois Tigeot {
2489a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring;
2490a05eeebfSFrançois Tigeot 	struct drm_i915_private *dev_priv;
2491e3adcf8fSFrançois Tigeot 	int ret;
2492e3adcf8fSFrançois Tigeot 
2493a05eeebfSFrançois Tigeot 	WARN_ON(req == NULL);
2494a05eeebfSFrançois Tigeot 	ring = req->ring;
2495a05eeebfSFrançois Tigeot 	dev_priv = ring->dev->dev_private;
2496a05eeebfSFrançois Tigeot 
2497a2fdbec6SFrançois Tigeot 	ret = i915_gem_check_wedge(&dev_priv->gpu_error,
2498a2fdbec6SFrançois Tigeot 				   dev_priv->mm.interruptible);
2499245593daSFrançois Tigeot 	if (ret)
2500245593daSFrançois Tigeot 		return ret;
2501e3adcf8fSFrançois Tigeot 
25029edbd4a0SFrançois Tigeot 	ret = __intel_ring_prepare(ring, num_dwords * sizeof(uint32_t));
25039edbd4a0SFrançois Tigeot 	if (ret)
25049edbd4a0SFrançois Tigeot 		return ret;
25059edbd4a0SFrançois Tigeot 
2506ba55f2f5SFrançois Tigeot 	ring->buffer->space -= num_dwords * sizeof(uint32_t);
25079edbd4a0SFrançois Tigeot 	return 0;
25089edbd4a0SFrançois Tigeot }
25099edbd4a0SFrançois Tigeot 
25109edbd4a0SFrançois Tigeot /* Align the ring tail to a cacheline boundary */
2511a05eeebfSFrançois Tigeot int intel_ring_cacheline_align(struct drm_i915_gem_request *req)
25129edbd4a0SFrançois Tigeot {
2513a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
2514ba55f2f5SFrançois Tigeot 	int num_dwords = (ring->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t);
25159edbd4a0SFrançois Tigeot 	int ret;
25169edbd4a0SFrançois Tigeot 
25179edbd4a0SFrançois Tigeot 	if (num_dwords == 0)
25189edbd4a0SFrançois Tigeot 		return 0;
25199edbd4a0SFrançois Tigeot 
2520ba55f2f5SFrançois Tigeot 	num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords;
2521a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, num_dwords);
25229edbd4a0SFrançois Tigeot 	if (ret)
25239edbd4a0SFrançois Tigeot 		return ret;
25249edbd4a0SFrançois Tigeot 
25259edbd4a0SFrançois Tigeot 	while (num_dwords--)
25269edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
25279edbd4a0SFrançois Tigeot 
25289edbd4a0SFrançois Tigeot 	intel_ring_advance(ring);
25299edbd4a0SFrançois Tigeot 
25309edbd4a0SFrançois Tigeot 	return 0;
2531e3adcf8fSFrançois Tigeot }
2532e3adcf8fSFrançois Tigeot 
2533ba55f2f5SFrançois Tigeot void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno)
2534a2fdbec6SFrançois Tigeot {
253524edb884SFrançois Tigeot 	struct drm_device *dev = ring->dev;
253624edb884SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2537a2fdbec6SFrançois Tigeot 
253824edb884SFrançois Tigeot 	if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) {
2539a2fdbec6SFrançois Tigeot 		I915_WRITE(RING_SYNC_0(ring->mmio_base), 0);
2540a2fdbec6SFrançois Tigeot 		I915_WRITE(RING_SYNC_1(ring->mmio_base), 0);
254124edb884SFrançois Tigeot 		if (HAS_VEBOX(dev))
25429edbd4a0SFrançois Tigeot 			I915_WRITE(RING_SYNC_2(ring->mmio_base), 0);
2543e3adcf8fSFrançois Tigeot 	}
2544e3adcf8fSFrançois Tigeot 
2545a2fdbec6SFrançois Tigeot 	ring->set_seqno(ring, seqno);
25465d0b1887SFrançois Tigeot 	ring->hangcheck.seqno = seqno;
2547e3adcf8fSFrançois Tigeot }
2548e3adcf8fSFrançois Tigeot 
2549ba55f2f5SFrançois Tigeot static void gen6_bsd_ring_write_tail(struct intel_engine_cs *ring,
2550f4e1c372SFrançois Tigeot 				     u32 value)
2551e3adcf8fSFrançois Tigeot {
2552ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
2553e3adcf8fSFrançois Tigeot 
2554e3adcf8fSFrançois Tigeot        /* Every tail move must follow the sequence below */
2555f4e1c372SFrançois Tigeot 
2556f4e1c372SFrançois Tigeot 	/* Disable notification that the ring is IDLE. The GT
2557f4e1c372SFrançois Tigeot 	 * will then assume that it is busy and bring it out of rc6.
2558f4e1c372SFrançois Tigeot 	 */
2559e3adcf8fSFrançois Tigeot 	I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
2560f4e1c372SFrançois Tigeot 		   _MASKED_BIT_ENABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2561e3adcf8fSFrançois Tigeot 
2562f4e1c372SFrançois Tigeot 	/* Clear the context id. Here be magic! */
2563f4e1c372SFrançois Tigeot 	I915_WRITE64(GEN6_BSD_RNCID, 0x0);
2564e3adcf8fSFrançois Tigeot 
2565f4e1c372SFrançois Tigeot 	/* Wait for the ring not to be idle, i.e. for it to wake up. */
2566f4e1c372SFrançois Tigeot 	if (wait_for((I915_READ(GEN6_BSD_SLEEP_PSMI_CONTROL) &
2567f4e1c372SFrançois Tigeot 		      GEN6_BSD_SLEEP_INDICATOR) == 0,
2568f4e1c372SFrançois Tigeot 		     50))
2569f4e1c372SFrançois Tigeot 		DRM_ERROR("timed out waiting for the BSD ring to wake up\n");
2570f4e1c372SFrançois Tigeot 
2571f4e1c372SFrançois Tigeot 	/* Now that the ring is fully powered up, update the tail */
2572e3adcf8fSFrançois Tigeot 	I915_WRITE_TAIL(ring, value);
2573f4e1c372SFrançois Tigeot 	POSTING_READ(RING_TAIL(ring->mmio_base));
2574f4e1c372SFrançois Tigeot 
2575f4e1c372SFrançois Tigeot 	/* Let the ring send IDLE messages to the GT again,
2576f4e1c372SFrançois Tigeot 	 * and so let it sleep to conserve power when idle.
2577f4e1c372SFrançois Tigeot 	 */
2578e3adcf8fSFrançois Tigeot 	I915_WRITE(GEN6_BSD_SLEEP_PSMI_CONTROL,
2579f4e1c372SFrançois Tigeot 		   _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
2580e3adcf8fSFrançois Tigeot }
2581e3adcf8fSFrançois Tigeot 
2582a05eeebfSFrançois Tigeot static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req,
2583b5c29a34SFrançois Tigeot 			       u32 invalidate, u32 flush)
2584e3adcf8fSFrançois Tigeot {
2585a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
2586e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2587e3adcf8fSFrançois Tigeot 	int ret;
2588e3adcf8fSFrançois Tigeot 
2589a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2590e3adcf8fSFrançois Tigeot 	if (ret)
2591e3adcf8fSFrançois Tigeot 		return ret;
2592e3adcf8fSFrançois Tigeot 
2593e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
25949edbd4a0SFrançois Tigeot 	if (INTEL_INFO(ring->dev)->gen >= 8)
25959edbd4a0SFrançois Tigeot 		cmd += 1;
25962c9916cdSFrançois Tigeot 
25972c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
25982c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
25992c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
26002c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
26012c9916cdSFrançois Tigeot 	 */
26022c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
26032c9916cdSFrançois Tigeot 
2604b5c29a34SFrançois Tigeot 	/*
2605b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.5 - video engine command streamer:
2606b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2607b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2608b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2609b5c29a34SFrançois Tigeot 	 */
2610e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_GPU_DOMAINS)
26112c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
26122c9916cdSFrançois Tigeot 
2613e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, cmd);
2614b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
26159edbd4a0SFrançois Tigeot 	if (INTEL_INFO(ring->dev)->gen >= 8) {
26169edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, 0); /* upper addr */
26179edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, 0); /* value */
26189edbd4a0SFrançois Tigeot 	} else  {
26199edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, 0);
26209edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
26219edbd4a0SFrançois Tigeot 	}
26229edbd4a0SFrançois Tigeot 	intel_ring_advance(ring);
26239edbd4a0SFrançois Tigeot 	return 0;
26249edbd4a0SFrançois Tigeot }
26259edbd4a0SFrançois Tigeot 
26269edbd4a0SFrançois Tigeot static int
2627a05eeebfSFrançois Tigeot gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2628ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2629477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
26309edbd4a0SFrançois Tigeot {
2631a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
2632477eb7f9SFrançois Tigeot 	bool ppgtt = USES_PPGTT(ring->dev) &&
2633477eb7f9SFrançois Tigeot 			!(dispatch_flags & I915_DISPATCH_SECURE);
26349edbd4a0SFrançois Tigeot 	int ret;
26359edbd4a0SFrançois Tigeot 
2636a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
26379edbd4a0SFrançois Tigeot 	if (ret)
26389edbd4a0SFrançois Tigeot 		return ret;
26399edbd4a0SFrançois Tigeot 
26409edbd4a0SFrançois Tigeot 	/* FIXME(BDW): Address space and security selectors. */
2641a05eeebfSFrançois Tigeot 	intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) |
2642a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2643a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
2644ba55f2f5SFrançois Tigeot 	intel_ring_emit(ring, lower_32_bits(offset));
2645ba55f2f5SFrançois Tigeot 	intel_ring_emit(ring, upper_32_bits(offset));
2646e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, MI_NOOP);
2647e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
26489edbd4a0SFrançois Tigeot 
2649e3adcf8fSFrançois Tigeot 	return 0;
2650e3adcf8fSFrançois Tigeot }
2651e3adcf8fSFrançois Tigeot 
2652e3adcf8fSFrançois Tigeot static int
2653a05eeebfSFrançois Tigeot hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2654ba55f2f5SFrançois Tigeot 			     u64 offset, u32 len,
2655477eb7f9SFrançois Tigeot 			     unsigned dispatch_flags)
2656e3adcf8fSFrançois Tigeot {
2657a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
2658e3adcf8fSFrançois Tigeot 	int ret;
2659e3adcf8fSFrançois Tigeot 
2660a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2661e3adcf8fSFrançois Tigeot 	if (ret)
2662e3adcf8fSFrançois Tigeot 		return ret;
2663e3adcf8fSFrançois Tigeot 
2664b5c29a34SFrançois Tigeot 	intel_ring_emit(ring,
26651b13d190SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2666477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2667a05eeebfSFrançois Tigeot 			 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) |
2668a05eeebfSFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_RS ?
2669a05eeebfSFrançois Tigeot 			 MI_BATCH_RESOURCE_STREAMER : 0));
2670b5c29a34SFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
2671b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, offset);
2672b5c29a34SFrançois Tigeot 	intel_ring_advance(ring);
2673b5c29a34SFrançois Tigeot 
2674b5c29a34SFrançois Tigeot 	return 0;
2675b5c29a34SFrançois Tigeot }
2676b5c29a34SFrançois Tigeot 
2677b5c29a34SFrançois Tigeot static int
2678a05eeebfSFrançois Tigeot gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req,
2679ba55f2f5SFrançois Tigeot 			      u64 offset, u32 len,
2680477eb7f9SFrançois Tigeot 			      unsigned dispatch_flags)
2681b5c29a34SFrançois Tigeot {
2682a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
2683b5c29a34SFrançois Tigeot 	int ret;
2684b5c29a34SFrançois Tigeot 
2685a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 2);
2686b5c29a34SFrançois Tigeot 	if (ret)
2687b5c29a34SFrançois Tigeot 		return ret;
2688b5c29a34SFrançois Tigeot 
2689b5c29a34SFrançois Tigeot 	intel_ring_emit(ring,
2690b5c29a34SFrançois Tigeot 			MI_BATCH_BUFFER_START |
2691477eb7f9SFrançois Tigeot 			(dispatch_flags & I915_DISPATCH_SECURE ?
2692477eb7f9SFrançois Tigeot 			 0 : MI_BATCH_NON_SECURE_I965));
2693e3adcf8fSFrançois Tigeot 	/* bit0-7 is the length on GEN6+ */
2694e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, offset);
2695e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
2696e3adcf8fSFrançois Tigeot 
2697e3adcf8fSFrançois Tigeot 	return 0;
2698e3adcf8fSFrançois Tigeot }
2699e3adcf8fSFrançois Tigeot 
2700e3adcf8fSFrançois Tigeot /* Blitter support (SandyBridge+) */
2701e3adcf8fSFrançois Tigeot 
2702a05eeebfSFrançois Tigeot static int gen6_ring_flush(struct drm_i915_gem_request *req,
2703b5c29a34SFrançois Tigeot 			   u32 invalidate, u32 flush)
2704e3adcf8fSFrançois Tigeot {
2705a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
27065d0b1887SFrançois Tigeot 	struct drm_device *dev = ring->dev;
2707e3adcf8fSFrançois Tigeot 	uint32_t cmd;
2708e3adcf8fSFrançois Tigeot 	int ret;
2709e3adcf8fSFrançois Tigeot 
2710a05eeebfSFrançois Tigeot 	ret = intel_ring_begin(req, 4);
2711e3adcf8fSFrançois Tigeot 	if (ret)
2712e3adcf8fSFrançois Tigeot 		return ret;
2713e3adcf8fSFrançois Tigeot 
2714e3adcf8fSFrançois Tigeot 	cmd = MI_FLUSH_DW;
2715477eb7f9SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8)
27169edbd4a0SFrançois Tigeot 		cmd += 1;
27172c9916cdSFrançois Tigeot 
27182c9916cdSFrançois Tigeot 	/* We always require a command barrier so that subsequent
27192c9916cdSFrançois Tigeot 	 * commands, such as breadcrumb interrupts, are strictly ordered
27202c9916cdSFrançois Tigeot 	 * wrt the contents of the write cache being flushed to memory
27212c9916cdSFrançois Tigeot 	 * (and thus being coherent from the CPU).
27222c9916cdSFrançois Tigeot 	 */
27232c9916cdSFrançois Tigeot 	cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
27242c9916cdSFrançois Tigeot 
2725b5c29a34SFrançois Tigeot 	/*
2726b5c29a34SFrançois Tigeot 	 * Bspec vol 1c.3 - blitter engine command streamer:
2727b5c29a34SFrançois Tigeot 	 * "If ENABLED, all TLBs will be invalidated once the flush
2728b5c29a34SFrançois Tigeot 	 * operation is complete. This bit is only valid when the
2729b5c29a34SFrançois Tigeot 	 * Post-Sync Operation field is a value of 1h or 3h."
2730b5c29a34SFrançois Tigeot 	 */
2731e3adcf8fSFrançois Tigeot 	if (invalidate & I915_GEM_DOMAIN_RENDER)
27322c9916cdSFrançois Tigeot 		cmd |= MI_INVALIDATE_TLB;
2733e3adcf8fSFrançois Tigeot 	intel_ring_emit(ring, cmd);
2734b5c29a34SFrançois Tigeot 	intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
2735477eb7f9SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
27369edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, 0); /* upper addr */
27379edbd4a0SFrançois Tigeot 		intel_ring_emit(ring, 0); /* value */
27389edbd4a0SFrançois Tigeot 	} else  {
2739e3adcf8fSFrançois Tigeot 		intel_ring_emit(ring, 0);
2740e3adcf8fSFrançois Tigeot 		intel_ring_emit(ring, MI_NOOP);
27419edbd4a0SFrançois Tigeot 	}
2742e3adcf8fSFrançois Tigeot 	intel_ring_advance(ring);
27435d0b1887SFrançois Tigeot 
2744e3adcf8fSFrançois Tigeot 	return 0;
2745e3adcf8fSFrançois Tigeot }
2746e3adcf8fSFrançois Tigeot 
2747e3adcf8fSFrançois Tigeot int intel_init_render_ring_buffer(struct drm_device *dev)
2748e3adcf8fSFrançois Tigeot {
2749ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2750ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[RCS];
275124edb884SFrançois Tigeot 	struct drm_i915_gem_object *obj;
275224edb884SFrançois Tigeot 	int ret;
2753e3adcf8fSFrançois Tigeot 
2754686a02f1SFrançois Tigeot 	ring->name = "render ring";
2755686a02f1SFrançois Tigeot 	ring->id = RCS;
2756*c0e85e96SFrançois Tigeot 	ring->exec_id = I915_EXEC_RENDER;
2757686a02f1SFrançois Tigeot 	ring->mmio_base = RENDER_RING_BASE;
2758686a02f1SFrançois Tigeot 
275924edb884SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
276024edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
276124edb884SFrançois Tigeot 			obj = i915_gem_alloc_object(dev, 4096);
276224edb884SFrançois Tigeot 			if (obj == NULL) {
276324edb884SFrançois Tigeot 				DRM_ERROR("Failed to allocate semaphore bo. Disabling semaphores\n");
276424edb884SFrançois Tigeot 				i915.semaphores = 0;
276524edb884SFrançois Tigeot 			} else {
276624edb884SFrançois Tigeot 				i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
276724edb884SFrançois Tigeot 				ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_NONBLOCK);
276824edb884SFrançois Tigeot 				if (ret != 0) {
276924edb884SFrançois Tigeot 					drm_gem_object_unreference(&obj->base);
277024edb884SFrançois Tigeot 					DRM_ERROR("Failed to pin semaphore bo. Disabling semaphores\n");
277124edb884SFrançois Tigeot 					i915.semaphores = 0;
277224edb884SFrançois Tigeot 				} else
277324edb884SFrançois Tigeot 					dev_priv->semaphore_obj = obj;
277424edb884SFrançois Tigeot 			}
277524edb884SFrançois Tigeot 		}
27762c9916cdSFrançois Tigeot 
27772c9916cdSFrançois Tigeot 		ring->init_context = intel_rcs_ctx_init;
277824edb884SFrançois Tigeot 		ring->add_request = gen6_add_request;
277924edb884SFrançois Tigeot 		ring->flush = gen8_render_ring_flush;
278024edb884SFrançois Tigeot 		ring->irq_get = gen8_ring_get_irq;
278124edb884SFrançois Tigeot 		ring->irq_put = gen8_ring_put_irq;
278224edb884SFrançois Tigeot 		ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
278324edb884SFrançois Tigeot 		ring->get_seqno = gen6_ring_get_seqno;
278424edb884SFrançois Tigeot 		ring->set_seqno = ring_set_seqno;
278524edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
278624edb884SFrançois Tigeot 			WARN_ON(!dev_priv->semaphore_obj);
278724edb884SFrançois Tigeot 			ring->semaphore.sync_to = gen8_ring_sync;
278824edb884SFrançois Tigeot 			ring->semaphore.signal = gen8_rcs_signal;
278924edb884SFrançois Tigeot 			GEN8_RING_SEMAPHORE_INIT;
279024edb884SFrançois Tigeot 		}
279124edb884SFrançois Tigeot 	} else if (INTEL_INFO(dev)->gen >= 6) {
2792352ff8bdSFrançois Tigeot 		ring->init_context = intel_rcs_ctx_init;
2793e3adcf8fSFrançois Tigeot 		ring->add_request = gen6_add_request;
2794b5c29a34SFrançois Tigeot 		ring->flush = gen7_render_ring_flush;
2795b5c29a34SFrançois Tigeot 		if (INTEL_INFO(dev)->gen == 6)
2796e3adcf8fSFrançois Tigeot 			ring->flush = gen6_render_ring_flush;
2797686a02f1SFrançois Tigeot 		ring->irq_get = gen6_ring_get_irq;
2798686a02f1SFrançois Tigeot 		ring->irq_put = gen6_ring_put_irq;
27995d0b1887SFrançois Tigeot 		ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
2800e3adcf8fSFrançois Tigeot 		ring->get_seqno = gen6_ring_get_seqno;
2801a2fdbec6SFrançois Tigeot 		ring->set_seqno = ring_set_seqno;
280224edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
2803ba55f2f5SFrançois Tigeot 			ring->semaphore.sync_to = gen6_ring_sync;
2804ba55f2f5SFrançois Tigeot 			ring->semaphore.signal = gen6_signal;
2805ba55f2f5SFrançois Tigeot 			/*
280624edb884SFrançois Tigeot 			 * The current semaphore is only applied on pre-gen8
280724edb884SFrançois Tigeot 			 * platform.  And there is no VCS2 ring on the pre-gen8
280824edb884SFrançois Tigeot 			 * platform. So the semaphore between RCS and VCS2 is
280924edb884SFrançois Tigeot 			 * initialized as INVALID.  Gen8 will initialize the
281024edb884SFrançois Tigeot 			 * sema between VCS2 and RCS later.
2811ba55f2f5SFrançois Tigeot 			 */
2812ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_INVALID;
2813ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_RV;
2814ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_RB;
2815ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_RVE;
2816ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
2817ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[RCS] = GEN6_NOSYNC;
2818ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VCS] = GEN6_VRSYNC;
2819ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[BCS] = GEN6_BRSYNC;
2820ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VECS] = GEN6_VERSYNC;
2821ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
282224edb884SFrançois Tigeot 		}
2823e3adcf8fSFrançois Tigeot 	} else if (IS_GEN5(dev)) {
2824e3adcf8fSFrançois Tigeot 		ring->add_request = pc_render_add_request;
2825686a02f1SFrançois Tigeot 		ring->flush = gen4_render_ring_flush;
2826e3adcf8fSFrançois Tigeot 		ring->get_seqno = pc_render_get_seqno;
2827a2fdbec6SFrançois Tigeot 		ring->set_seqno = pc_render_set_seqno;
2828686a02f1SFrançois Tigeot 		ring->irq_get = gen5_ring_get_irq;
2829686a02f1SFrançois Tigeot 		ring->irq_put = gen5_ring_put_irq;
28305d0b1887SFrançois Tigeot 		ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT |
28315d0b1887SFrançois Tigeot 					GT_RENDER_PIPECTL_NOTIFY_INTERRUPT;
2832686a02f1SFrançois Tigeot 	} else {
2833686a02f1SFrançois Tigeot 		ring->add_request = i9xx_add_request;
2834686a02f1SFrançois Tigeot 		if (INTEL_INFO(dev)->gen < 4)
2835686a02f1SFrançois Tigeot 			ring->flush = gen2_render_ring_flush;
2836686a02f1SFrançois Tigeot 		else
2837686a02f1SFrançois Tigeot 			ring->flush = gen4_render_ring_flush;
2838686a02f1SFrançois Tigeot 		ring->get_seqno = ring_get_seqno;
2839a2fdbec6SFrançois Tigeot 		ring->set_seqno = ring_set_seqno;
2840686a02f1SFrançois Tigeot 		if (IS_GEN2(dev)) {
2841686a02f1SFrançois Tigeot 			ring->irq_get = i8xx_ring_get_irq;
2842686a02f1SFrançois Tigeot 			ring->irq_put = i8xx_ring_put_irq;
2843686a02f1SFrançois Tigeot 		} else {
2844686a02f1SFrançois Tigeot 			ring->irq_get = i9xx_ring_get_irq;
2845686a02f1SFrançois Tigeot 			ring->irq_put = i9xx_ring_put_irq;
2846e3adcf8fSFrançois Tigeot 		}
2847686a02f1SFrançois Tigeot 		ring->irq_enable_mask = I915_USER_INTERRUPT;
2848686a02f1SFrançois Tigeot 	}
2849686a02f1SFrançois Tigeot 	ring->write_tail = ring_write_tail;
285024edb884SFrançois Tigeot 
2851b5c29a34SFrançois Tigeot 	if (IS_HASWELL(dev))
2852b5c29a34SFrançois Tigeot 		ring->dispatch_execbuffer = hsw_ring_dispatch_execbuffer;
28539edbd4a0SFrançois Tigeot 	else if (IS_GEN8(dev))
28549edbd4a0SFrançois Tigeot 		ring->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
2855b5c29a34SFrançois Tigeot 	else if (INTEL_INFO(dev)->gen >= 6)
2856686a02f1SFrançois Tigeot 		ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
2857686a02f1SFrançois Tigeot 	else if (INTEL_INFO(dev)->gen >= 4)
2858686a02f1SFrançois Tigeot 		ring->dispatch_execbuffer = i965_dispatch_execbuffer;
2859686a02f1SFrançois Tigeot 	else if (IS_I830(dev) || IS_845G(dev))
2860686a02f1SFrançois Tigeot 		ring->dispatch_execbuffer = i830_dispatch_execbuffer;
2861686a02f1SFrançois Tigeot 	else
2862686a02f1SFrançois Tigeot 		ring->dispatch_execbuffer = i915_dispatch_execbuffer;
28632c9916cdSFrançois Tigeot 	ring->init_hw = init_render_ring;
2864686a02f1SFrançois Tigeot 	ring->cleanup = render_ring_cleanup;
2865e3adcf8fSFrançois Tigeot 
2866b5c29a34SFrançois Tigeot 	/* Workaround batchbuffer to combat CS tlb bug. */
2867b5c29a34SFrançois Tigeot 	if (HAS_BROKEN_CS_TLB(dev)) {
286824edb884SFrançois Tigeot 		obj = i915_gem_alloc_object(dev, I830_WA_SIZE);
2869b5c29a34SFrançois Tigeot 		if (obj == NULL) {
2870b5c29a34SFrançois Tigeot 			DRM_ERROR("Failed to allocate batch bo\n");
2871b5c29a34SFrançois Tigeot 			return -ENOMEM;
2872b5c29a34SFrançois Tigeot 		}
2873b5c29a34SFrançois Tigeot 
2874ba55f2f5SFrançois Tigeot 		ret = i915_gem_obj_ggtt_pin(obj, 0, 0);
2875b5c29a34SFrançois Tigeot 		if (ret != 0) {
2876b5c29a34SFrançois Tigeot 			drm_gem_object_unreference(&obj->base);
2877b5c29a34SFrançois Tigeot 			DRM_ERROR("Failed to ping batch bo\n");
2878b5c29a34SFrançois Tigeot 			return ret;
2879b5c29a34SFrançois Tigeot 		}
2880b5c29a34SFrançois Tigeot 
28819edbd4a0SFrançois Tigeot 		ring->scratch.obj = obj;
28829edbd4a0SFrançois Tigeot 		ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
2883e3adcf8fSFrançois Tigeot 	}
2884e3adcf8fSFrançois Tigeot 
28852c9916cdSFrançois Tigeot 	ret = intel_init_ring_buffer(dev, ring);
2886b5c29a34SFrançois Tigeot 	if (ret)
28872c9916cdSFrançois Tigeot 		return ret;
28882c9916cdSFrançois Tigeot 
28892c9916cdSFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 5) {
28902c9916cdSFrançois Tigeot 		ret = intel_init_pipe_control(ring);
28912c9916cdSFrançois Tigeot 		if (ret)
28922c9916cdSFrançois Tigeot 			return ret;
2893b5c29a34SFrançois Tigeot 	}
2894b5c29a34SFrançois Tigeot 
2895e3adcf8fSFrançois Tigeot 	return 0;
2896e3adcf8fSFrançois Tigeot }
2897e3adcf8fSFrançois Tigeot 
2898e3adcf8fSFrançois Tigeot int intel_init_bsd_ring_buffer(struct drm_device *dev)
2899e3adcf8fSFrançois Tigeot {
2900ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2901ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[VCS];
2902e3adcf8fSFrançois Tigeot 
2903686a02f1SFrançois Tigeot 	ring->name = "bsd ring";
2904686a02f1SFrançois Tigeot 	ring->id = VCS;
2905*c0e85e96SFrançois Tigeot 	ring->exec_id = I915_EXEC_BSD;
2906686a02f1SFrançois Tigeot 
2907686a02f1SFrançois Tigeot 	ring->write_tail = ring_write_tail;
29089edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 6) {
2909686a02f1SFrançois Tigeot 		ring->mmio_base = GEN6_BSD_RING_BASE;
2910686a02f1SFrançois Tigeot 		/* gen6 bsd needs a special wa for tail updates */
2911686a02f1SFrançois Tigeot 		if (IS_GEN6(dev))
2912686a02f1SFrançois Tigeot 			ring->write_tail = gen6_bsd_ring_write_tail;
29135d0b1887SFrançois Tigeot 		ring->flush = gen6_bsd_ring_flush;
2914686a02f1SFrançois Tigeot 		ring->add_request = gen6_add_request;
2915686a02f1SFrançois Tigeot 		ring->get_seqno = gen6_ring_get_seqno;
2916a2fdbec6SFrançois Tigeot 		ring->set_seqno = ring_set_seqno;
29179edbd4a0SFrançois Tigeot 		if (INTEL_INFO(dev)->gen >= 8) {
29189edbd4a0SFrançois Tigeot 			ring->irq_enable_mask =
29199edbd4a0SFrançois Tigeot 				GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
29209edbd4a0SFrançois Tigeot 			ring->irq_get = gen8_ring_get_irq;
29219edbd4a0SFrançois Tigeot 			ring->irq_put = gen8_ring_put_irq;
29229edbd4a0SFrançois Tigeot 			ring->dispatch_execbuffer =
29239edbd4a0SFrançois Tigeot 				gen8_ring_dispatch_execbuffer;
292424edb884SFrançois Tigeot 			if (i915_semaphore_is_enabled(dev)) {
292524edb884SFrançois Tigeot 				ring->semaphore.sync_to = gen8_ring_sync;
292624edb884SFrançois Tigeot 				ring->semaphore.signal = gen8_xcs_signal;
292724edb884SFrançois Tigeot 				GEN8_RING_SEMAPHORE_INIT;
292824edb884SFrançois Tigeot 			}
29299edbd4a0SFrançois Tigeot 		} else {
29305d0b1887SFrançois Tigeot 			ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
2931686a02f1SFrançois Tigeot 			ring->irq_get = gen6_ring_get_irq;
2932686a02f1SFrançois Tigeot 			ring->irq_put = gen6_ring_put_irq;
29339edbd4a0SFrançois Tigeot 			ring->dispatch_execbuffer =
29349edbd4a0SFrançois Tigeot 				gen6_ring_dispatch_execbuffer;
293524edb884SFrançois Tigeot 			if (i915_semaphore_is_enabled(dev)) {
2936ba55f2f5SFrançois Tigeot 				ring->semaphore.sync_to = gen6_ring_sync;
2937ba55f2f5SFrançois Tigeot 				ring->semaphore.signal = gen6_signal;
2938ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VR;
2939ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_INVALID;
2940ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VB;
2941ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_VVE;
2942ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
2943ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.signal[RCS] = GEN6_RVSYNC;
2944ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.signal[VCS] = GEN6_NOSYNC;
2945ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.signal[BCS] = GEN6_BVSYNC;
2946ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.signal[VECS] = GEN6_VEVSYNC;
2947ba55f2f5SFrançois Tigeot 				ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
294824edb884SFrançois Tigeot 			}
294924edb884SFrançois Tigeot 		}
2950686a02f1SFrançois Tigeot 	} else {
2951686a02f1SFrançois Tigeot 		ring->mmio_base = BSD_RING_BASE;
2952686a02f1SFrançois Tigeot 		ring->flush = bsd_ring_flush;
2953686a02f1SFrançois Tigeot 		ring->add_request = i9xx_add_request;
2954686a02f1SFrançois Tigeot 		ring->get_seqno = ring_get_seqno;
2955a2fdbec6SFrançois Tigeot 		ring->set_seqno = ring_set_seqno;
2956686a02f1SFrançois Tigeot 		if (IS_GEN5(dev)) {
29575d0b1887SFrançois Tigeot 			ring->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
2958686a02f1SFrançois Tigeot 			ring->irq_get = gen5_ring_get_irq;
2959686a02f1SFrançois Tigeot 			ring->irq_put = gen5_ring_put_irq;
2960686a02f1SFrançois Tigeot 		} else {
2961686a02f1SFrançois Tigeot 			ring->irq_enable_mask = I915_BSD_USER_INTERRUPT;
2962686a02f1SFrançois Tigeot 			ring->irq_get = i9xx_ring_get_irq;
2963686a02f1SFrançois Tigeot 			ring->irq_put = i9xx_ring_put_irq;
2964686a02f1SFrançois Tigeot 		}
2965686a02f1SFrançois Tigeot 		ring->dispatch_execbuffer = i965_dispatch_execbuffer;
2966686a02f1SFrançois Tigeot 	}
29672c9916cdSFrançois Tigeot 	ring->init_hw = init_ring_common;
2968e3adcf8fSFrançois Tigeot 
2969e3adcf8fSFrançois Tigeot 	return intel_init_ring_buffer(dev, ring);
2970e3adcf8fSFrançois Tigeot }
2971e3adcf8fSFrançois Tigeot 
2972ba55f2f5SFrançois Tigeot /**
2973477eb7f9SFrançois Tigeot  * Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
2974ba55f2f5SFrançois Tigeot  */
2975ba55f2f5SFrançois Tigeot int intel_init_bsd2_ring_buffer(struct drm_device *dev)
2976ba55f2f5SFrançois Tigeot {
2977ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2978ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[VCS2];
2979ba55f2f5SFrançois Tigeot 
298024edb884SFrançois Tigeot 	ring->name = "bsd2 ring";
2981ba55f2f5SFrançois Tigeot 	ring->id = VCS2;
2982*c0e85e96SFrançois Tigeot 	ring->exec_id = I915_EXEC_BSD;
2983ba55f2f5SFrançois Tigeot 
2984ba55f2f5SFrançois Tigeot 	ring->write_tail = ring_write_tail;
2985ba55f2f5SFrançois Tigeot 	ring->mmio_base = GEN8_BSD2_RING_BASE;
2986ba55f2f5SFrançois Tigeot 	ring->flush = gen6_bsd_ring_flush;
2987ba55f2f5SFrançois Tigeot 	ring->add_request = gen6_add_request;
2988ba55f2f5SFrançois Tigeot 	ring->get_seqno = gen6_ring_get_seqno;
2989ba55f2f5SFrançois Tigeot 	ring->set_seqno = ring_set_seqno;
2990ba55f2f5SFrançois Tigeot 	ring->irq_enable_mask =
2991ba55f2f5SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
2992ba55f2f5SFrançois Tigeot 	ring->irq_get = gen8_ring_get_irq;
2993ba55f2f5SFrançois Tigeot 	ring->irq_put = gen8_ring_put_irq;
2994ba55f2f5SFrançois Tigeot 	ring->dispatch_execbuffer =
2995ba55f2f5SFrançois Tigeot 			gen8_ring_dispatch_execbuffer;
299624edb884SFrançois Tigeot 	if (i915_semaphore_is_enabled(dev)) {
299724edb884SFrançois Tigeot 		ring->semaphore.sync_to = gen8_ring_sync;
299824edb884SFrançois Tigeot 		ring->semaphore.signal = gen8_xcs_signal;
299924edb884SFrançois Tigeot 		GEN8_RING_SEMAPHORE_INIT;
300024edb884SFrançois Tigeot 	}
30012c9916cdSFrançois Tigeot 	ring->init_hw = init_ring_common;
3002ba55f2f5SFrançois Tigeot 
3003ba55f2f5SFrançois Tigeot 	return intel_init_ring_buffer(dev, ring);
3004ba55f2f5SFrançois Tigeot }
3005ba55f2f5SFrançois Tigeot 
3006e3adcf8fSFrançois Tigeot int intel_init_blt_ring_buffer(struct drm_device *dev)
3007e3adcf8fSFrançois Tigeot {
3008ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
3009ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[BCS];
3010e3adcf8fSFrançois Tigeot 
3011686a02f1SFrançois Tigeot 	ring->name = "blitter ring";
3012686a02f1SFrançois Tigeot 	ring->id = BCS;
3013*c0e85e96SFrançois Tigeot 	ring->exec_id = I915_EXEC_BLT;
3014686a02f1SFrançois Tigeot 
3015686a02f1SFrançois Tigeot 	ring->mmio_base = BLT_RING_BASE;
3016686a02f1SFrançois Tigeot 	ring->write_tail = ring_write_tail;
30175d0b1887SFrançois Tigeot 	ring->flush = gen6_ring_flush;
3018686a02f1SFrançois Tigeot 	ring->add_request = gen6_add_request;
3019686a02f1SFrançois Tigeot 	ring->get_seqno = gen6_ring_get_seqno;
3020a2fdbec6SFrançois Tigeot 	ring->set_seqno = ring_set_seqno;
30219edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
30229edbd4a0SFrançois Tigeot 		ring->irq_enable_mask =
30239edbd4a0SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
30249edbd4a0SFrançois Tigeot 		ring->irq_get = gen8_ring_get_irq;
30259edbd4a0SFrançois Tigeot 		ring->irq_put = gen8_ring_put_irq;
30269edbd4a0SFrançois Tigeot 		ring->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
302724edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
302824edb884SFrançois Tigeot 			ring->semaphore.sync_to = gen8_ring_sync;
302924edb884SFrançois Tigeot 			ring->semaphore.signal = gen8_xcs_signal;
303024edb884SFrançois Tigeot 			GEN8_RING_SEMAPHORE_INIT;
303124edb884SFrançois Tigeot 		}
30329edbd4a0SFrançois Tigeot 	} else {
30335d0b1887SFrançois Tigeot 		ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
3034686a02f1SFrançois Tigeot 		ring->irq_get = gen6_ring_get_irq;
3035686a02f1SFrançois Tigeot 		ring->irq_put = gen6_ring_put_irq;
3036686a02f1SFrançois Tigeot 		ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
303724edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
3038ba55f2f5SFrançois Tigeot 			ring->semaphore.signal = gen6_signal;
303924edb884SFrançois Tigeot 			ring->semaphore.sync_to = gen6_ring_sync;
3040ba55f2f5SFrançois Tigeot 			/*
304124edb884SFrançois Tigeot 			 * The current semaphore is only applied on pre-gen8
304224edb884SFrançois Tigeot 			 * platform.  And there is no VCS2 ring on the pre-gen8
304324edb884SFrançois Tigeot 			 * platform. So the semaphore between BCS and VCS2 is
304424edb884SFrançois Tigeot 			 * initialized as INVALID.  Gen8 will initialize the
304524edb884SFrançois Tigeot 			 * sema between BCS and VCS2 later.
3046ba55f2f5SFrançois Tigeot 			 */
3047ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_BR;
3048ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_BV;
3049ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_INVALID;
3050ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_BVE;
3051ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
3052ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[RCS] = GEN6_RBSYNC;
3053ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VCS] = GEN6_VBSYNC;
3054ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[BCS] = GEN6_NOSYNC;
3055ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VECS] = GEN6_VEBSYNC;
3056ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
305724edb884SFrançois Tigeot 		}
305824edb884SFrançois Tigeot 	}
30592c9916cdSFrançois Tigeot 	ring->init_hw = init_ring_common;
30605d0b1887SFrançois Tigeot 
30615d0b1887SFrançois Tigeot 	return intel_init_ring_buffer(dev, ring);
30625d0b1887SFrançois Tigeot }
30635d0b1887SFrançois Tigeot 
30645d0b1887SFrançois Tigeot int intel_init_vebox_ring_buffer(struct drm_device *dev)
30655d0b1887SFrançois Tigeot {
3066ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
3067ba55f2f5SFrançois Tigeot 	struct intel_engine_cs *ring = &dev_priv->ring[VECS];
30685d0b1887SFrançois Tigeot 
30695d0b1887SFrançois Tigeot 	ring->name = "video enhancement ring";
30705d0b1887SFrançois Tigeot 	ring->id = VECS;
3071*c0e85e96SFrançois Tigeot 	ring->exec_id = I915_EXEC_VEBOX;
30725d0b1887SFrançois Tigeot 
30735d0b1887SFrançois Tigeot 	ring->mmio_base = VEBOX_RING_BASE;
30745d0b1887SFrançois Tigeot 	ring->write_tail = ring_write_tail;
30755d0b1887SFrançois Tigeot 	ring->flush = gen6_ring_flush;
30765d0b1887SFrançois Tigeot 	ring->add_request = gen6_add_request;
30775d0b1887SFrançois Tigeot 	ring->get_seqno = gen6_ring_get_seqno;
30785d0b1887SFrançois Tigeot 	ring->set_seqno = ring_set_seqno;
30799edbd4a0SFrançois Tigeot 
30809edbd4a0SFrançois Tigeot 	if (INTEL_INFO(dev)->gen >= 8) {
30819edbd4a0SFrançois Tigeot 		ring->irq_enable_mask =
30829edbd4a0SFrançois Tigeot 			GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
30839edbd4a0SFrançois Tigeot 		ring->irq_get = gen8_ring_get_irq;
30849edbd4a0SFrançois Tigeot 		ring->irq_put = gen8_ring_put_irq;
30859edbd4a0SFrançois Tigeot 		ring->dispatch_execbuffer = gen8_ring_dispatch_execbuffer;
308624edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
308724edb884SFrançois Tigeot 			ring->semaphore.sync_to = gen8_ring_sync;
308824edb884SFrançois Tigeot 			ring->semaphore.signal = gen8_xcs_signal;
308924edb884SFrançois Tigeot 			GEN8_RING_SEMAPHORE_INIT;
309024edb884SFrançois Tigeot 		}
30919edbd4a0SFrançois Tigeot 	} else {
30929edbd4a0SFrançois Tigeot 		ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT;
30935d0b1887SFrançois Tigeot 		ring->irq_get = hsw_vebox_get_irq;
30945d0b1887SFrançois Tigeot 		ring->irq_put = hsw_vebox_put_irq;
30955d0b1887SFrançois Tigeot 		ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
309624edb884SFrançois Tigeot 		if (i915_semaphore_is_enabled(dev)) {
3097ba55f2f5SFrançois Tigeot 			ring->semaphore.sync_to = gen6_ring_sync;
3098ba55f2f5SFrançois Tigeot 			ring->semaphore.signal = gen6_signal;
3099ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[RCS] = MI_SEMAPHORE_SYNC_VER;
3100ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VCS] = MI_SEMAPHORE_SYNC_VEV;
3101ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[BCS] = MI_SEMAPHORE_SYNC_VEB;
3102ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VECS] = MI_SEMAPHORE_SYNC_INVALID;
3103ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.wait[VCS2] = MI_SEMAPHORE_SYNC_INVALID;
3104ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[RCS] = GEN6_RVESYNC;
3105ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VCS] = GEN6_VVESYNC;
3106ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[BCS] = GEN6_BVESYNC;
3107ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VECS] = GEN6_NOSYNC;
3108ba55f2f5SFrançois Tigeot 			ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
310924edb884SFrançois Tigeot 		}
311024edb884SFrançois Tigeot 	}
31112c9916cdSFrançois Tigeot 	ring->init_hw = init_ring_common;
3112e3adcf8fSFrançois Tigeot 
3113e3adcf8fSFrançois Tigeot 	return intel_init_ring_buffer(dev, ring);
3114e3adcf8fSFrançois Tigeot }
3115b030f26bSFrançois Tigeot 
3116b030f26bSFrançois Tigeot int
3117a05eeebfSFrançois Tigeot intel_ring_flush_all_caches(struct drm_i915_gem_request *req)
3118b030f26bSFrançois Tigeot {
3119a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
3120b030f26bSFrançois Tigeot 	int ret;
3121b030f26bSFrançois Tigeot 
3122b030f26bSFrançois Tigeot 	if (!ring->gpu_caches_dirty)
3123b030f26bSFrançois Tigeot 		return 0;
3124b030f26bSFrançois Tigeot 
3125a05eeebfSFrançois Tigeot 	ret = ring->flush(req, 0, I915_GEM_GPU_DOMAINS);
3126b030f26bSFrançois Tigeot 	if (ret)
3127b030f26bSFrançois Tigeot 		return ret;
3128b030f26bSFrançois Tigeot 
3129a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS);
3130a2fdbec6SFrançois Tigeot 
3131b030f26bSFrançois Tigeot 	ring->gpu_caches_dirty = false;
3132b030f26bSFrançois Tigeot 	return 0;
3133b030f26bSFrançois Tigeot }
3134b030f26bSFrançois Tigeot 
3135b030f26bSFrançois Tigeot int
3136a05eeebfSFrançois Tigeot intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req)
3137b030f26bSFrançois Tigeot {
3138a05eeebfSFrançois Tigeot 	struct intel_engine_cs *ring = req->ring;
3139b030f26bSFrançois Tigeot 	uint32_t flush_domains;
3140b030f26bSFrançois Tigeot 	int ret;
3141b030f26bSFrançois Tigeot 
3142b030f26bSFrançois Tigeot 	flush_domains = 0;
3143b030f26bSFrançois Tigeot 	if (ring->gpu_caches_dirty)
3144b030f26bSFrançois Tigeot 		flush_domains = I915_GEM_GPU_DOMAINS;
3145b030f26bSFrançois Tigeot 
3146a05eeebfSFrançois Tigeot 	ret = ring->flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
3147b030f26bSFrançois Tigeot 	if (ret)
3148b030f26bSFrançois Tigeot 		return ret;
3149b030f26bSFrançois Tigeot 
3150a05eeebfSFrançois Tigeot 	trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains);
3151a2fdbec6SFrançois Tigeot 
3152b030f26bSFrançois Tigeot 	ring->gpu_caches_dirty = false;
3153b030f26bSFrançois Tigeot 	return 0;
3154b030f26bSFrançois Tigeot }
3155ba55f2f5SFrançois Tigeot 
3156ba55f2f5SFrançois Tigeot void
3157ba55f2f5SFrançois Tigeot intel_stop_ring_buffer(struct intel_engine_cs *ring)
3158ba55f2f5SFrançois Tigeot {
3159ba55f2f5SFrançois Tigeot 	int ret;
3160ba55f2f5SFrançois Tigeot 
3161ba55f2f5SFrançois Tigeot 	if (!intel_ring_initialized(ring))
3162ba55f2f5SFrançois Tigeot 		return;
3163ba55f2f5SFrançois Tigeot 
3164ba55f2f5SFrançois Tigeot 	ret = intel_ring_idle(ring);
3165ba55f2f5SFrançois Tigeot 	if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error))
3166ba55f2f5SFrançois Tigeot 		DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
3167ba55f2f5SFrançois Tigeot 			  ring->name, ret);
3168ba55f2f5SFrançois Tigeot 
3169ba55f2f5SFrançois Tigeot 	stop_ring(ring);
3170ba55f2f5SFrançois Tigeot }
3171