drm/i915: Fix mmio vs. CS flip race on ILK+
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / intel_display.c
index 39f37bb7a16a690b9424da4af7289500076b3bea..930746527e9d8c0e46a4ed0ce0e48aa0b7d8dbe2 100644 (file)
@@ -1694,6 +1694,7 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
 
 static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
 {
+       enum dpio_channel port = vlv_pipe_to_channel(pipe);
        u32 val;
 
        /* Make sure the pipe isn't still relying on us */
@@ -1705,6 +1706,15 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
                val |= DPLL_INTEGRATED_CRI_CLK_VLV;
        I915_WRITE(DPLL(pipe), val);
        POSTING_READ(DPLL(pipe));
+
+       mutex_lock(&dev_priv->dpio_lock);
+
+       /* Disable 10bit clock to display controller */
+       val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
+       val &= ~DPIO_DCLKP_EN;
+       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val);
+
+       mutex_unlock(&dev_priv->dpio_lock);
 }
 
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
@@ -5505,7 +5515,7 @@ static void chv_update_pll(struct intel_crtc *crtc)
        int pipe = crtc->pipe;
        int dpll_reg = DPLL(crtc->pipe);
        enum dpio_channel port = vlv_pipe_to_channel(pipe);
-       u32 val, loopfilter, intcoeff;
+       u32 loopfilter, intcoeff;
        u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
        int refclk;
 
@@ -5533,16 +5543,6 @@ static void chv_update_pll(struct intel_crtc *crtc)
 
        mutex_lock(&dev_priv->dpio_lock);
 
-       /* Propagate soft reset to data lane reset */
-       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS_DW0(port));
-       val &= ~(DPIO_PCS_TX_LANE2_RESET | DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), val);
-
-       /* Disable 10bit clock to display controller */
-       val = vlv_dpio_read(dev_priv, pipe, CHV_CMN_DW14(port));
-       val &= ~DPIO_DCLKP_EN;
-       vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW14(port), val);
-
        /* p1 and p2 divider */
        vlv_dpio_write(dev_priv, pipe, CHV_CMN_DW13(port),
                        5 << DPIO_CHV_S1_DIV_SHIFT |
@@ -8846,6 +8846,48 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
        do_intel_finish_page_flip(dev, crtc);
 }
 
+/* Is 'a' after or equal to 'b'? */
+static bool g4x_flip_count_after_eq(u32 a, u32 b)
+{
+       return !((a - b) & 0x80000000);
+}
+
+static bool page_flip_finished(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       /*
+        * The relevant registers doen't exist on pre-ctg.
+        * As the flip done interrupt doesn't trigger for mmio
+        * flips on gmch platforms, a flip count check isn't
+        * really needed there. But since ctg has the registers,
+        * include it in the check anyway.
+        */
+       if (INTEL_INFO(dev)->gen < 5 && !IS_G4X(dev))
+               return true;
+
+       /*
+        * A DSPSURFLIVE check isn't enough in case the mmio and CS flips
+        * used the same base address. In that case the mmio flip might
+        * have completed, but the CS hasn't even executed the flip yet.
+        *
+        * A flip count check isn't enough as the CS might have updated
+        * the base address just after start of vblank, but before we
+        * managed to process the interrupt. This means we'd complete the
+        * CS flip too soon.
+        *
+        * Combining both checks should get us a good enough result. It may
+        * still happen that the CS flip has been executed, but has not
+        * yet actually completed. But in case the base address is the same
+        * anyway, we don't really care.
+        */
+       return (I915_READ(DSPSURFLIVE(crtc->plane)) & ~0xfff) ==
+               crtc->unpin_work->gtt_offset &&
+               g4x_flip_count_after_eq(I915_READ(PIPE_FLIPCOUNT_GM45(crtc->pipe)),
+                                   crtc->unpin_work->flip_count);
+}
+
 void intel_prepare_page_flip(struct drm_device *dev, int plane)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8858,7 +8900,7 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane)
         * is also accompanied by a spurious intel_prepare_page_flip().
         */
        spin_lock_irqsave(&dev->event_lock, flags);
-       if (intel_crtc->unpin_work)
+       if (intel_crtc->unpin_work && page_flip_finished(intel_crtc))
                atomic_inc_not_zero(&intel_crtc->unpin_work->pending);
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
@@ -8888,6 +8930,9 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
        if (ret)
                goto err;
 
+       intel_crtc->unpin_work->gtt_offset =
+               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+
        ret = intel_ring_begin(ring, 6);
        if (ret)
                goto err_unpin;
@@ -8904,7 +8949,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
        intel_ring_emit(ring, 0); /* aux display base address, unused */
 
        intel_mark_page_flip_active(intel_crtc);
@@ -8933,6 +8978,9 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
        if (ret)
                goto err;
 
+       intel_crtc->unpin_work->gtt_offset =
+               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+
        ret = intel_ring_begin(ring, 6);
        if (ret)
                goto err_unpin;
@@ -8946,7 +8994,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
        intel_ring_emit(ring, MI_NOOP);
 
        intel_mark_page_flip_active(intel_crtc);
@@ -8975,6 +9023,9 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
        if (ret)
                goto err;
 
+       intel_crtc->unpin_work->gtt_offset =
+               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+
        ret = intel_ring_begin(ring, 4);
        if (ret)
                goto err_unpin;
@@ -8986,8 +9037,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0]);
-       intel_ring_emit(ring,
-                       (i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset) |
+       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset |
                        obj->tiling_mode);
 
        /* XXX Enabling the panel-fitter across page-flip is so far
@@ -9024,6 +9074,9 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
        if (ret)
                goto err;
 
+       intel_crtc->unpin_work->gtt_offset =
+               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+
        ret = intel_ring_begin(ring, 4);
        if (ret)
                goto err_unpin;
@@ -9031,7 +9084,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev,
        intel_ring_emit(ring, MI_DISPLAY_FLIP |
                        MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
        intel_ring_emit(ring, fb->pitches[0] | obj->tiling_mode);
-       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
 
        /* Contrary to the suggestions in the documentation,
         * "Enable Panel Fitter" does not seem to be required when page
@@ -9073,6 +9126,9 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
        if (ret)
                goto err;
 
+       intel_crtc->unpin_work->gtt_offset =
+               i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset;
+
        switch (intel_crtc->plane) {
        case PLANE_A:
                plane_bit = MI_DISPLAY_FLIP_IVB_PLANE_A;
@@ -9150,7 +9206,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
        intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
-       intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+       intel_ring_emit(ring, intel_crtc->unpin_work->gtt_offset);
        intel_ring_emit(ring, (MI_NOOP));
 
        intel_mark_page_flip_active(intel_crtc);
@@ -9248,6 +9304,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        atomic_inc(&intel_crtc->unpin_work_count);
        intel_crtc->reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
 
+       if (INTEL_INFO(dev)->gen >= 5 || IS_G4X(dev))
+               work->flip_count = I915_READ(PIPE_FLIPCOUNT_GM45(intel_crtc->pipe)) + 1;
+
        ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, page_flip_flags);
        if (ret)
                goto cleanup_pending;