]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/2.6.33.5/drm-i915-use-pipe_control-instruction-on-ironlake-and-sandy-bridge.patch
Linux 5.1.3
[thirdparty/kernel/stable-queue.git] / releases / 2.6.33.5 / drm-i915-use-pipe_control-instruction-on-ironlake-and-sandy-bridge.patch
CommitLineData
a8f45b2e
GKH
1From e552eb7038a36d9b18860f525aa02875e313fe16 Mon Sep 17 00:00:00 2001
2From: Jesse Barnes <jbarnes@virtuousgeek.org>
3Date: Wed, 21 Apr 2010 11:39:23 -0700
4Subject: drm/i915: use PIPE_CONTROL instruction on Ironlake and Sandy Bridge
5
6From: Jesse Barnes <jbarnes@virtuousgeek.org>
7
8commit e552eb7038a36d9b18860f525aa02875e313fe16 upstream.
9
10Since 965, the hardware has supported the PIPE_CONTROL command, which
11provides fine grained GPU cache flushing control. On recent chipsets,
12this instruction is required for reliable interrupt and sequence number
13reporting in the driver.
14
15So add support for this instruction, including workarounds, on Ironlake
16and Sandy Bridge hardware.
17
18https://bugs.freedesktop.org/show_bug.cgi?id=27108
19
20Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
21Tested-by: Chris Wilson <chris@chris-wilson.co.uk>
22Signed-off-by: Eric Anholt <eric@anholt.net>
23Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
24
25---
26 drivers/gpu/drm/i915/i915_drv.h | 4 +
27 drivers/gpu/drm/i915/i915_gem.c | 145 ++++++++++++++++++++++++++++++++++++----
28 drivers/gpu/drm/i915/i915_irq.c | 8 +-
29 drivers/gpu/drm/i915/i915_reg.h | 11 +++
30 4 files changed, 152 insertions(+), 16 deletions(-)
31
32--- a/drivers/gpu/drm/i915/i915_drv.h
33+++ b/drivers/gpu/drm/i915/i915_drv.h
34@@ -206,11 +206,14 @@ typedef struct drm_i915_private {
35
36 drm_dma_handle_t *status_page_dmah;
37 void *hw_status_page;
38+ void *seqno_page;
39 dma_addr_t dma_status_page;
40 uint32_t counter;
41 unsigned int status_gfx_addr;
42+ unsigned int seqno_gfx_addr;
43 drm_local_map_t hws_map;
44 struct drm_gem_object *hws_obj;
45+ struct drm_gem_object *seqno_obj;
46 struct drm_gem_object *pwrctx;
47
48 struct resource mch_res;
49@@ -1090,6 +1093,7 @@ extern int i915_wait_ring(struct drm_dev
50
51 #define HAS_PCH_SPLIT(dev) (IS_IRONLAKE(dev) || \
52 IS_GEN6(dev))
53+#define HAS_PIPE_CONTROL(dev) (IS_IRONLAKE(dev) || IS_GEN6(dev))
54
55 #define PRIMARY_RINGBUFFER_SIZE (128*1024)
56
57--- a/drivers/gpu/drm/i915/i915_gem.c
58+++ b/drivers/gpu/drm/i915/i915_gem.c
59@@ -1559,6 +1559,13 @@ i915_gem_object_move_to_inactive(struct
60 i915_verify_inactive(dev, __FILE__, __LINE__);
61 }
62
63+#define PIPE_CONTROL_FLUSH(addr) \
64+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
65+ PIPE_CONTROL_DEPTH_STALL); \
66+ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \
67+ OUT_RING(0); \
68+ OUT_RING(0); \
69+
70 /**
71 * Creates a new sequence number, emitting a write of it to the status page
72 * plus an interrupt, which will trigger i915_user_interrupt_handler.
73@@ -1593,13 +1600,47 @@ i915_add_request(struct drm_device *dev,
74 if (dev_priv->mm.next_gem_seqno == 0)
75 dev_priv->mm.next_gem_seqno++;
76
77- BEGIN_LP_RING(4);
78- OUT_RING(MI_STORE_DWORD_INDEX);
79- OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
80- OUT_RING(seqno);
81+ if (HAS_PIPE_CONTROL(dev)) {
82+ u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
83
84- OUT_RING(MI_USER_INTERRUPT);
85- ADVANCE_LP_RING();
86+ /*
87+ * Workaround qword write incoherence by flushing the
88+ * PIPE_NOTIFY buffers out to memory before requesting
89+ * an interrupt.
90+ */
91+ BEGIN_LP_RING(32);
92+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
93+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
94+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
95+ OUT_RING(seqno);
96+ OUT_RING(0);
97+ PIPE_CONTROL_FLUSH(scratch_addr);
98+ scratch_addr += 128; /* write to separate cachelines */
99+ PIPE_CONTROL_FLUSH(scratch_addr);
100+ scratch_addr += 128;
101+ PIPE_CONTROL_FLUSH(scratch_addr);
102+ scratch_addr += 128;
103+ PIPE_CONTROL_FLUSH(scratch_addr);
104+ scratch_addr += 128;
105+ PIPE_CONTROL_FLUSH(scratch_addr);
106+ scratch_addr += 128;
107+ PIPE_CONTROL_FLUSH(scratch_addr);
108+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
109+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
110+ PIPE_CONTROL_NOTIFY);
111+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
112+ OUT_RING(seqno);
113+ OUT_RING(0);
114+ ADVANCE_LP_RING();
115+ } else {
116+ BEGIN_LP_RING(4);
117+ OUT_RING(MI_STORE_DWORD_INDEX);
118+ OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
119+ OUT_RING(seqno);
120+
121+ OUT_RING(MI_USER_INTERRUPT);
122+ ADVANCE_LP_RING();
123+ }
124
125 DRM_DEBUG_DRIVER("%d\n", seqno);
126
127@@ -1744,7 +1785,10 @@ i915_get_gem_seqno(struct drm_device *de
128 {
129 drm_i915_private_t *dev_priv = dev->dev_private;
130
131- return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
132+ if (IS_I965G(dev))
133+ return ((volatile u32 *)(dev_priv->seqno_page))[0];
134+ else
135+ return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
136 }
137
138 /**
139@@ -4576,6 +4620,49 @@ i915_gem_idle(struct drm_device *dev)
140 return 0;
141 }
142
143+/*
144+ * 965+ support PIPE_CONTROL commands, which provide finer grained control
145+ * over cache flushing.
146+ */
147+static int
148+i915_gem_init_pipe_control(struct drm_device *dev)
149+{
150+ drm_i915_private_t *dev_priv = dev->dev_private;
151+ struct drm_gem_object *obj;
152+ struct drm_i915_gem_object *obj_priv;
153+ int ret;
154+
155+ obj = drm_gem_object_alloc(dev, 4096);
156+ if (obj == NULL) {
157+ DRM_ERROR("Failed to allocate seqno page\n");
158+ ret = -ENOMEM;
159+ goto err;
160+ }
161+ obj_priv = obj->driver_private;
162+ obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
163+
164+ ret = i915_gem_object_pin(obj, 4096);
165+ if (ret)
166+ goto err_unref;
167+
168+ dev_priv->seqno_gfx_addr = obj_priv->gtt_offset;
169+ dev_priv->seqno_page = kmap(obj_priv->pages[0]);
170+ if (dev_priv->seqno_page == NULL)
171+ goto err_unpin;
172+
173+ dev_priv->seqno_obj = obj;
174+ memset(dev_priv->seqno_page, 0, PAGE_SIZE);
175+
176+ return 0;
177+
178+err_unpin:
179+ i915_gem_object_unpin(obj);
180+err_unref:
181+ drm_gem_object_unreference(obj);
182+err:
183+ return ret;
184+}
185+
186 static int
187 i915_gem_init_hws(struct drm_device *dev)
188 {
189@@ -4593,7 +4680,8 @@ i915_gem_init_hws(struct drm_device *dev
190 obj = drm_gem_object_alloc(dev, 4096);
191 if (obj == NULL) {
192 DRM_ERROR("Failed to allocate status page\n");
193- return -ENOMEM;
194+ ret = -ENOMEM;
195+ goto err;
196 }
197 obj_priv = obj->driver_private;
198 obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
199@@ -4601,7 +4689,7 @@ i915_gem_init_hws(struct drm_device *dev
200 ret = i915_gem_object_pin(obj, 4096);
201 if (ret != 0) {
202 drm_gem_object_unreference(obj);
203- return ret;
204+ goto err_unref;
205 }
206
207 dev_priv->status_gfx_addr = obj_priv->gtt_offset;
208@@ -4610,10 +4698,16 @@ i915_gem_init_hws(struct drm_device *dev
209 if (dev_priv->hw_status_page == NULL) {
210 DRM_ERROR("Failed to map status page.\n");
211 memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
212- i915_gem_object_unpin(obj);
213- drm_gem_object_unreference(obj);
214- return -EINVAL;
215+ ret = -EINVAL;
216+ goto err_unpin;
217 }
218+
219+ if (HAS_PIPE_CONTROL(dev)) {
220+ ret = i915_gem_init_pipe_control(dev);
221+ if (ret)
222+ goto err_unpin;
223+ }
224+
225 dev_priv->hws_obj = obj;
226 memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
227 I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
228@@ -4621,6 +4715,30 @@ i915_gem_init_hws(struct drm_device *dev
229 DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
230
231 return 0;
232+
233+err_unpin:
234+ i915_gem_object_unpin(obj);
235+err_unref:
236+ drm_gem_object_unreference(obj);
237+err:
238+ return 0;
239+}
240+
241+static void
242+i915_gem_cleanup_pipe_control(struct drm_device *dev)
243+{
244+ drm_i915_private_t *dev_priv = dev->dev_private;
245+ struct drm_gem_object *obj;
246+ struct drm_i915_gem_object *obj_priv;
247+
248+ obj = dev_priv->seqno_obj;
249+ obj_priv = obj->driver_private;
250+ kunmap(obj_priv->pages[0]);
251+ i915_gem_object_unpin(obj);
252+ drm_gem_object_unreference(obj);
253+ dev_priv->seqno_obj = NULL;
254+
255+ dev_priv->seqno_page = NULL;
256 }
257
258 static void
259@@ -4644,6 +4762,9 @@ i915_gem_cleanup_hws(struct drm_device *
260 memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
261 dev_priv->hw_status_page = NULL;
262
263+ if (HAS_PIPE_CONTROL(dev))
264+ i915_gem_cleanup_pipe_control(dev);
265+
266 /* Write high address into HWS_PGA when disabling. */
267 I915_WRITE(HWS_PGA, 0x1ffff000);
268 }
269--- a/drivers/gpu/drm/i915/i915_irq.c
270+++ b/drivers/gpu/drm/i915/i915_irq.c
271@@ -297,7 +297,7 @@ irqreturn_t ironlake_irq_handler(struct
272 READ_BREADCRUMB(dev_priv);
273 }
274
275- if (gt_iir & GT_USER_INTERRUPT) {
276+ if (gt_iir & GT_PIPE_NOTIFY) {
277 u32 seqno = i915_get_gem_seqno(dev);
278 dev_priv->mm.irq_gem_seqno = seqno;
279 trace_i915_gem_request_complete(dev, seqno);
280@@ -738,7 +738,7 @@ void i915_user_irq_get(struct drm_device
281 spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
282 if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
283 if (HAS_PCH_SPLIT(dev))
284- ironlake_enable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
285+ ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
286 else
287 i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
288 }
289@@ -754,7 +754,7 @@ void i915_user_irq_put(struct drm_device
290 BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
291 if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
292 if (HAS_PCH_SPLIT(dev))
293- ironlake_disable_graphics_irq(dev_priv, GT_USER_INTERRUPT);
294+ ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
295 else
296 i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
297 }
298@@ -1034,7 +1034,7 @@ static int ironlake_irq_postinstall(stru
299 /* enable kind of interrupts always enabled */
300 u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
301 DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
302- u32 render_mask = GT_USER_INTERRUPT;
303+ u32 render_mask = GT_PIPE_NOTIFY;
304 u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
305 SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
306
307--- a/drivers/gpu/drm/i915/i915_reg.h
308+++ b/drivers/gpu/drm/i915/i915_reg.h
309@@ -210,6 +210,16 @@
310 #define ASYNC_FLIP (1<<22)
311 #define DISPLAY_PLANE_A (0<<20)
312 #define DISPLAY_PLANE_B (1<<20)
313+#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
314+#define PIPE_CONTROL_QW_WRITE (1<<14)
315+#define PIPE_CONTROL_DEPTH_STALL (1<<13)
316+#define PIPE_CONTROL_WC_FLUSH (1<<12)
317+#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */
318+#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
319+#define PIPE_CONTROL_ISP_DIS (1<<9)
320+#define PIPE_CONTROL_NOTIFY (1<<8)
321+#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
322+#define PIPE_CONTROL_STALL_EN (1<<1) /* in addr word, Ironlake+ only */
323
324 /*
325 * Fence registers
326@@ -2111,6 +2121,7 @@
327 #define DEIER 0x4400c
328
329 /* GT interrupt */
330+#define GT_PIPE_NOTIFY (1 << 4)
331 #define GT_SYNC_STATUS (1 << 2)
332 #define GT_USER_INTERRUPT (1 << 0)
333