Merge remote-tracking branch 'airlied/drm-fixes' into drm-intel-next-queued
[linux-2.6-block.git] / drivers / gpu / drm / i915 / intel_ringbuffer.c
index 6e80f83683558327387335eef35a36d70581ce16..4956f1bff5226e697f0ed63a94d80d57f20c6977 100644 (file)
@@ -633,6 +633,19 @@ render_ring_add_request(struct intel_ring_buffer *ring,
        return 0;
 }
 
+static u32
+gen6_ring_get_seqno(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+
+       /* Workaround to force correct ordering between irq and seqno writes on
+        * ivb (and maybe also on snb) by reading from a CS register (like
+        * ACTHD) before reading the status page. */
+       if (IS_GEN7(dev))
+               intel_ring_get_active_head(ring);
+       return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
 static u32
 ring_get_seqno(struct intel_ring_buffer *ring)
 {
@@ -789,17 +802,6 @@ ring_add_request(struct intel_ring_buffer *ring,
        return 0;
 }
 
-static bool
-gen7_blt_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       /* The BLT ring on IVB appears to have broken synchronization
-        * between the seqno write and the interrupt, so that the
-        * interrupt appears first.  Returning false here makes
-        * i915_wait_request() do a polling loop, instead.
-        */
-       return false;
-}
-
 static bool
 gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
 {
@@ -809,6 +811,12 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
        if (!dev->irq_enabled)
               return false;
 
+       /* It looks like we need to prevent the gt from suspending while waiting
+        * for an notifiy irq, otherwise irqs seem to get lost on at least the
+        * blt/bsd rings on ivb. */
+       if (IS_GEN7(dev))
+               gen6_gt_force_wake_get(dev_priv);
+
        spin_lock(&ring->irq_lock);
        if (ring->irq_refcount++ == 0) {
                ring->irq_mask &= ~rflag;
@@ -833,6 +841,9 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
                ironlake_disable_irq(dev_priv, gflag);
        }
        spin_unlock(&ring->irq_lock);
+
+       if (IS_GEN7(dev))
+               gen6_gt_force_wake_put(dev_priv);
 }
 
 static bool
@@ -1339,7 +1350,7 @@ static const struct intel_ring_buffer gen6_bsd_ring = {
        .write_tail             = gen6_bsd_ring_write_tail,
        .flush                  = gen6_ring_flush,
        .add_request            = gen6_add_request,
-       .get_seqno              = ring_get_seqno,
+       .get_seqno              = gen6_ring_get_seqno,
        .irq_get                = gen6_bsd_ring_get_irq,
        .irq_put                = gen6_bsd_ring_put_irq,
        .dispatch_execbuffer    = gen6_ring_dispatch_execbuffer,
@@ -1398,7 +1409,7 @@ static const struct intel_ring_buffer gen6_blt_ring = {
        .write_tail             = ring_write_tail,
        .flush                  = blt_ring_flush,
        .add_request            = gen6_add_request,
-       .get_seqno              = ring_get_seqno,
+       .get_seqno              = gen6_ring_get_seqno,
        .irq_get                = blt_ring_get_irq,
        .irq_put                = blt_ring_put_irq,
        .dispatch_execbuffer    = gen6_ring_dispatch_execbuffer,
@@ -1420,6 +1431,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                ring->flush = gen6_render_ring_flush;
                ring->irq_get = gen6_render_ring_get_irq;
                ring->irq_put = gen6_render_ring_put_irq;
+               ring->get_seqno = gen6_ring_get_seqno;
        } else if (IS_GEN5(dev)) {
                ring->add_request = pc_render_add_request;
                ring->get_seqno = pc_render_get_seqno;
@@ -1498,8 +1510,5 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
 
        *ring = gen6_blt_ring;
 
-       if (IS_GEN7(dev))
-               ring->irq_get = gen7_blt_ring_get_irq;
-
        return intel_init_ring_buffer(dev, ring);
 }