drm/i915: Flush the pending flips on the CRTC before modification
[linux-2.6.git] / drivers / gpu / drm / i915 / intel_display.c
index db2163f..8e95c94 100644 (file)
@@ -2895,13 +2895,34 @@ static void intel_clear_scanline_wait(struct drm_device *dev)
                I915_WRITE_CTL(ring, tmp);
 }
 
+static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+       bool pending;
+
+       if (atomic_read(&dev_priv->mm.wedged))
+               return false;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       pending = to_intel_crtc(crtc)->unpin_work != NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       return pending;
+}
+
 static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (crtc->fb == NULL)
                return;
 
+       wait_event(dev_priv->pending_flip_queue,
+                  !intel_crtc_has_pending_flip(crtc));
+
        mutex_lock(&dev->struct_mutex);
        intel_finish_fb(crtc->fb);
        mutex_unlock(&dev->struct_mutex);
@@ -7258,9 +7279,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
        atomic_clear_mask(1 << intel_crtc->plane,
                          &obj->pending_flip.counter);
-       if (atomic_read(&obj->pending_flip) == 0)
-               wake_up(&dev_priv->pending_flip_queue);
 
+       wake_up(&dev_priv->pending_flip_queue);
        schedule_work(&work->work);
 
        trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);