aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2012-12-14 10:01:25 -0500
committerKeith Packard <keithp@keithp.com>2012-01-19 15:28:57 -0500
commit4cd53c0c8b01fc05c3ad5b2acdad02e37d3c2f55 (patch)
tree043bc8565dab11960796056be6ae1505ee781534
parentc937504e2b96af3b281b1ef859e063ef4af656c1 (diff)
drm/i915: paper over missed irq issues with force wake voodoo
Two things seem to do the trick on my ivb machine here: - prevent the gt from powering down while waiting for seqno notification interrupts by grabbing the force_wake in get_irq (and dropping it in put_irq again). - ordering writes from the ring's CS by reading a CS register, ACTHD seems to work. Only the blt&bsd ring on ivb seem to be massively affected by this, but for paranoia do this dance also on the render ring and on snb (i.e. all gpus with forcewake). Tested with Eric's glCopyPixels loop which without this patch scores a missed irq every few seconds. This patch needs my forcewake rework to use a spinlock instead of dev->struct_mutex. After crawling through docs a lot I've found the following nugget: Internal doc "SNB GT PM Programming Guide", Section 4.3.1: "GT does not generate interrupts while in RC6 (by design)" So it looks like rc6 and irq generation are indeed related. v2: Improve the comment per Eugeni Dodonov's suggestion. v3: Add the documentation snipped. Also restrict the w/a to ivb only for -fixes, as suggested by Keith Packard. Cc: stable@kernel.org Cc: Eric Anholt <eric@anholt.net> Cc: Kenneth Graunke <kenneth@whitecape.org> Cc: Eugeni Dodonov <eugeni.dodonov@intel.com> Tested-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Signed-Off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Keith Packard <keithp@keithp.com>
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 77e729d4e4f0..fa5702c5da42 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -636,6 +636,19 @@ render_ring_add_request(struct intel_ring_buffer *ring,
636} 636}
637 637
638static u32 638static u32
639gen6_ring_get_seqno(struct intel_ring_buffer *ring)
640{
641 struct drm_device *dev = ring->dev;
642
643 /* Workaround to force correct ordering between irq and seqno writes on
644 * ivb (and maybe also on snb) by reading from a CS register (like
645 * ACTHD) before reading the status page. */
646 if (IS_GEN7(dev))
647 intel_ring_get_active_head(ring);
648 return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
649}
650
651static u32
639ring_get_seqno(struct intel_ring_buffer *ring) 652ring_get_seqno(struct intel_ring_buffer *ring)
640{ 653{
641 return intel_read_status_page(ring, I915_GEM_HWS_INDEX); 654 return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
@@ -811,6 +824,12 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
811 if (!dev->irq_enabled) 824 if (!dev->irq_enabled)
812 return false; 825 return false;
813 826
827 /* It looks like we need to prevent the gt from suspending while waiting
828 * for an notifiy irq, otherwise irqs seem to get lost on at least the
829 * blt/bsd rings on ivb. */
830 if (IS_GEN7(dev))
831 gen6_gt_force_wake_get(dev_priv);
832
814 spin_lock(&ring->irq_lock); 833 spin_lock(&ring->irq_lock);
815 if (ring->irq_refcount++ == 0) { 834 if (ring->irq_refcount++ == 0) {
816 ring->irq_mask &= ~rflag; 835 ring->irq_mask &= ~rflag;
@@ -835,6 +854,9 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
835 ironlake_disable_irq(dev_priv, gflag); 854 ironlake_disable_irq(dev_priv, gflag);
836 } 855 }
837 spin_unlock(&ring->irq_lock); 856 spin_unlock(&ring->irq_lock);
857
858 if (IS_GEN7(dev))
859 gen6_gt_force_wake_put(dev_priv);
838} 860}
839 861
840static bool 862static bool
@@ -1341,7 +1363,7 @@ static const struct intel_ring_buffer gen6_bsd_ring = {
1341 .write_tail = gen6_bsd_ring_write_tail, 1363 .write_tail = gen6_bsd_ring_write_tail,
1342 .flush = gen6_ring_flush, 1364 .flush = gen6_ring_flush,
1343 .add_request = gen6_add_request, 1365 .add_request = gen6_add_request,
1344 .get_seqno = ring_get_seqno, 1366 .get_seqno = gen6_ring_get_seqno,
1345 .irq_get = gen6_bsd_ring_get_irq, 1367 .irq_get = gen6_bsd_ring_get_irq,
1346 .irq_put = gen6_bsd_ring_put_irq, 1368 .irq_put = gen6_bsd_ring_put_irq,
1347 .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, 1369 .dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
@@ -1476,7 +1498,7 @@ static const struct intel_ring_buffer gen6_blt_ring = {
1476 .write_tail = ring_write_tail, 1498 .write_tail = ring_write_tail,
1477 .flush = blt_ring_flush, 1499 .flush = blt_ring_flush,
1478 .add_request = gen6_add_request, 1500 .add_request = gen6_add_request,
1479 .get_seqno = ring_get_seqno, 1501 .get_seqno = gen6_ring_get_seqno,
1480 .irq_get = blt_ring_get_irq, 1502 .irq_get = blt_ring_get_irq,
1481 .irq_put = blt_ring_put_irq, 1503 .irq_put = blt_ring_put_irq,
1482 .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, 1504 .dispatch_execbuffer = gen6_ring_dispatch_execbuffer,
@@ -1499,6 +1521,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
1499 ring->flush = gen6_render_ring_flush; 1521 ring->flush = gen6_render_ring_flush;
1500 ring->irq_get = gen6_render_ring_get_irq; 1522 ring->irq_get = gen6_render_ring_get_irq;
1501 ring->irq_put = gen6_render_ring_put_irq; 1523 ring->irq_put = gen6_render_ring_put_irq;
1524 ring->get_seqno = gen6_ring_get_seqno;
1502 } else if (IS_GEN5(dev)) { 1525 } else if (IS_GEN5(dev)) {
1503 ring->add_request = pc_render_add_request; 1526 ring->add_request = pc_render_add_request;
1504 ring->get_seqno = pc_render_get_seqno; 1527 ring->get_seqno = pc_render_get_seqno;