diff options
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 162 |
2 files changed, 162 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2ddb98b5c90f..e4a2e2c3dbe3 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -349,7 +349,7 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev) | |||
349 | READ_BREADCRUMB(dev_priv); | 349 | READ_BREADCRUMB(dev_priv); |
350 | } | 350 | } |
351 | 351 | ||
352 | if (gt_iir & GT_USER_INTERRUPT) | 352 | if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY)) |
353 | notify_ring(dev, &dev_priv->ring[RCS]); | 353 | notify_ring(dev, &dev_priv->ring[RCS]); |
354 | if (gt_iir & bsd_usr_interrupt) | 354 | if (gt_iir & bsd_usr_interrupt) |
355 | notify_ring(dev, &dev_priv->ring[VCS]); | 355 | notify_ring(dev, &dev_priv->ring[VCS]); |
@@ -1558,6 +1558,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev) | |||
1558 | else | 1558 | else |
1559 | render_irqs = | 1559 | render_irqs = |
1560 | GT_USER_INTERRUPT | | 1560 | GT_USER_INTERRUPT | |
1561 | GT_PIPE_NOTIFY | | ||
1561 | GT_BSD_USER_INTERRUPT; | 1562 | GT_BSD_USER_INTERRUPT; |
1562 | I915_WRITE(GTIER, render_irqs); | 1563 | I915_WRITE(GTIER, render_irqs); |
1563 | POSTING_READ(GTIER); | 1564 | POSTING_READ(GTIER); |
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a3fd993e0de0..56bc95c056dd 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c | |||
@@ -209,6 +209,78 @@ static int init_ring_common(struct intel_ring_buffer *ring) | |||
209 | return 0; | 209 | return 0; |
210 | } | 210 | } |
211 | 211 | ||
212 | /* | ||
213 | * 965+ support PIPE_CONTROL commands, which provide finer grained control | ||
214 | * over cache flushing. | ||
215 | */ | ||
216 | struct pipe_control { | ||
217 | struct drm_i915_gem_object *obj; | ||
218 | volatile u32 *cpu_page; | ||
219 | u32 gtt_offset; | ||
220 | }; | ||
221 | |||
222 | static int | ||
223 | init_pipe_control(struct intel_ring_buffer *ring) | ||
224 | { | ||
225 | struct pipe_control *pc; | ||
226 | struct drm_i915_gem_object *obj; | ||
227 | int ret; | ||
228 | |||
229 | if (ring->private) | ||
230 | return 0; | ||
231 | |||
232 | pc = kmalloc(sizeof(*pc), GFP_KERNEL); | ||
233 | if (!pc) | ||
234 | return -ENOMEM; | ||
235 | |||
236 | obj = i915_gem_alloc_object(ring->dev, 4096); | ||
237 | if (obj == NULL) { | ||
238 | DRM_ERROR("Failed to allocate seqno page\n"); | ||
239 | ret = -ENOMEM; | ||
240 | goto err; | ||
241 | } | ||
242 | obj->agp_type = AGP_USER_CACHED_MEMORY; | ||
243 | |||
244 | ret = i915_gem_object_pin(obj, 4096, true); | ||
245 | if (ret) | ||
246 | goto err_unref; | ||
247 | |||
248 | pc->gtt_offset = obj->gtt_offset; | ||
249 | pc->cpu_page = kmap(obj->pages[0]); | ||
250 | if (pc->cpu_page == NULL) | ||
251 | goto err_unpin; | ||
252 | |||
253 | pc->obj = obj; | ||
254 | ring->private = pc; | ||
255 | return 0; | ||
256 | |||
257 | err_unpin: | ||
258 | i915_gem_object_unpin(obj); | ||
259 | err_unref: | ||
260 | drm_gem_object_unreference(&obj->base); | ||
261 | err: | ||
262 | kfree(pc); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static void | ||
267 | cleanup_pipe_control(struct intel_ring_buffer *ring) | ||
268 | { | ||
269 | struct pipe_control *pc = ring->private; | ||
270 | struct drm_i915_gem_object *obj; | ||
271 | |||
272 | if (!ring->private) | ||
273 | return; | ||
274 | |||
275 | obj = pc->obj; | ||
276 | kunmap(obj->pages[0]); | ||
277 | i915_gem_object_unpin(obj); | ||
278 | drm_gem_object_unreference(&obj->base); | ||
279 | |||
280 | kfree(pc); | ||
281 | ring->private = NULL; | ||
282 | } | ||
283 | |||
212 | static int init_render_ring(struct intel_ring_buffer *ring) | 284 | static int init_render_ring(struct intel_ring_buffer *ring) |
213 | { | 285 | { |
214 | struct drm_device *dev = ring->dev; | 286 | struct drm_device *dev = ring->dev; |
@@ -222,9 +294,24 @@ static int init_render_ring(struct intel_ring_buffer *ring) | |||
222 | I915_WRITE(MI_MODE, mode); | 294 | I915_WRITE(MI_MODE, mode); |
223 | } | 295 | } |
224 | 296 | ||
297 | if (INTEL_INFO(dev)->gen >= 6) { | ||
298 | } else if (IS_GEN5(dev)) { | ||
299 | ret = init_pipe_control(ring); | ||
300 | if (ret) | ||
301 | return ret; | ||
302 | } | ||
303 | |||
225 | return ret; | 304 | return ret; |
226 | } | 305 | } |
227 | 306 | ||
307 | static void render_ring_cleanup(struct intel_ring_buffer *ring) | ||
308 | { | ||
309 | if (!ring->private) | ||
310 | return; | ||
311 | |||
312 | cleanup_pipe_control(ring); | ||
313 | } | ||
314 | |||
228 | static void | 315 | static void |
229 | update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno) | 316 | update_semaphore(struct intel_ring_buffer *ring, int i, u32 seqno) |
230 | { | 317 | { |
@@ -299,6 +386,65 @@ intel_ring_sync(struct intel_ring_buffer *ring, | |||
299 | return 0; | 386 | return 0; |
300 | } | 387 | } |
301 | 388 | ||
389 | #define PIPE_CONTROL_FLUSH(ring__, addr__) \ | ||
390 | do { \ | ||
391 | intel_ring_emit(ring__, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \ | ||
392 | PIPE_CONTROL_DEPTH_STALL | 2); \ | ||
393 | intel_ring_emit(ring__, (addr__) | PIPE_CONTROL_GLOBAL_GTT); \ | ||
394 | intel_ring_emit(ring__, 0); \ | ||
395 | intel_ring_emit(ring__, 0); \ | ||
396 | } while (0) | ||
397 | |||
398 | static int | ||
399 | pc_render_add_request(struct intel_ring_buffer *ring, | ||
400 | u32 *result) | ||
401 | { | ||
402 | struct drm_device *dev = ring->dev; | ||
403 | u32 seqno = i915_gem_get_seqno(dev); | ||
404 | struct pipe_control *pc = ring->private; | ||
405 | u32 scratch_addr = pc->gtt_offset + 128; | ||
406 | int ret; | ||
407 | |||
408 | /* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently | ||
409 | * incoherent with writes to memory, i.e. completely fubar, | ||
410 | * so we need to use PIPE_NOTIFY instead. | ||
411 | * | ||
412 | * However, we also need to workaround the qword write | ||
413 | * incoherence by flushing the 6 PIPE_NOTIFY buffers out to | ||
414 | * memory before requesting an interrupt. | ||
415 | */ | ||
416 | ret = intel_ring_begin(ring, 32); | ||
417 | if (ret) | ||
418 | return ret; | ||
419 | |||
420 | intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | | ||
421 | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH); | ||
422 | intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); | ||
423 | intel_ring_emit(ring, seqno); | ||
424 | intel_ring_emit(ring, 0); | ||
425 | PIPE_CONTROL_FLUSH(ring, scratch_addr); | ||
426 | scratch_addr += 128; /* write to separate cachelines */ | ||
427 | PIPE_CONTROL_FLUSH(ring, scratch_addr); | ||
428 | scratch_addr += 128; | ||
429 | PIPE_CONTROL_FLUSH(ring, scratch_addr); | ||
430 | scratch_addr += 128; | ||
431 | PIPE_CONTROL_FLUSH(ring, scratch_addr); | ||
432 | scratch_addr += 128; | ||
433 | PIPE_CONTROL_FLUSH(ring, scratch_addr); | ||
434 | scratch_addr += 128; | ||
435 | PIPE_CONTROL_FLUSH(ring, scratch_addr); | ||
436 | intel_ring_emit(ring, GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | | ||
437 | PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH | | ||
438 | PIPE_CONTROL_NOTIFY); | ||
439 | intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT); | ||
440 | intel_ring_emit(ring, seqno); | ||
441 | intel_ring_emit(ring, 0); | ||
442 | intel_ring_advance(ring); | ||
443 | |||
444 | *result = seqno; | ||
445 | return 0; | ||
446 | } | ||
447 | |||
302 | static int | 448 | static int |
303 | render_ring_add_request(struct intel_ring_buffer *ring, | 449 | render_ring_add_request(struct intel_ring_buffer *ring, |
304 | u32 *result) | 450 | u32 *result) |
@@ -327,6 +473,13 @@ ring_get_seqno(struct intel_ring_buffer *ring) | |||
327 | return intel_read_status_page(ring, I915_GEM_HWS_INDEX); | 473 | return intel_read_status_page(ring, I915_GEM_HWS_INDEX); |
328 | } | 474 | } |
329 | 475 | ||
476 | static u32 | ||
477 | pc_render_get_seqno(struct intel_ring_buffer *ring) | ||
478 | { | ||
479 | struct pipe_control *pc = ring->private; | ||
480 | return pc->cpu_page[0]; | ||
481 | } | ||
482 | |||
330 | static bool | 483 | static bool |
331 | render_ring_get_irq(struct intel_ring_buffer *ring) | 484 | render_ring_get_irq(struct intel_ring_buffer *ring) |
332 | { | 485 | { |
@@ -342,7 +495,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring) | |||
342 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | 495 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
343 | if (HAS_PCH_SPLIT(dev)) | 496 | if (HAS_PCH_SPLIT(dev)) |
344 | ironlake_enable_graphics_irq(dev_priv, | 497 | ironlake_enable_graphics_irq(dev_priv, |
345 | GT_USER_INTERRUPT); | 498 | GT_PIPE_NOTIFY | GT_USER_INTERRUPT); |
346 | else | 499 | else |
347 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); | 500 | i915_enable_irq(dev_priv, I915_USER_INTERRUPT); |
348 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | 501 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
@@ -363,7 +516,8 @@ render_ring_put_irq(struct intel_ring_buffer *ring) | |||
363 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); | 516 | spin_lock_irqsave(&dev_priv->irq_lock, irqflags); |
364 | if (HAS_PCH_SPLIT(dev)) | 517 | if (HAS_PCH_SPLIT(dev)) |
365 | ironlake_disable_graphics_irq(dev_priv, | 518 | ironlake_disable_graphics_irq(dev_priv, |
366 | GT_USER_INTERRUPT); | 519 | GT_USER_INTERRUPT | |
520 | GT_PIPE_NOTIFY); | ||
367 | else | 521 | else |
368 | i915_disable_irq(dev_priv, I915_USER_INTERRUPT); | 522 | i915_disable_irq(dev_priv, I915_USER_INTERRUPT); |
369 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); | 523 | spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); |
@@ -776,6 +930,7 @@ static const struct intel_ring_buffer render_ring = { | |||
776 | .irq_get = render_ring_get_irq, | 930 | .irq_get = render_ring_get_irq, |
777 | .irq_put = render_ring_put_irq, | 931 | .irq_put = render_ring_put_irq, |
778 | .dispatch_execbuffer = render_ring_dispatch_execbuffer, | 932 | .dispatch_execbuffer = render_ring_dispatch_execbuffer, |
933 | .cleanup = render_ring_cleanup, | ||
779 | }; | 934 | }; |
780 | 935 | ||
781 | /* ring buffer for bit-stream decoder */ | 936 | /* ring buffer for bit-stream decoder */ |
@@ -1010,6 +1165,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev) | |||
1010 | *ring = render_ring; | 1165 | *ring = render_ring; |
1011 | if (INTEL_INFO(dev)->gen >= 6) { | 1166 | if (INTEL_INFO(dev)->gen >= 6) { |
1012 | ring->add_request = gen6_add_request; | 1167 | ring->add_request = gen6_add_request; |
1168 | } else if (IS_GEN5(dev)) { | ||
1169 | ring->add_request = pc_render_add_request; | ||
1170 | ring->get_seqno = pc_render_get_seqno; | ||
1013 | } | 1171 | } |
1014 | 1172 | ||
1015 | if (!I915_NEED_GFX_HWS(dev)) { | 1173 | if (!I915_NEED_GFX_HWS(dev)) { |