aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_display.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-09-27 16:25:58 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2012-10-02 05:50:26 -0400
commit5bb61643f6a70d48de9cfe91ad0fee0d618b6816 (patch)
tree5fbdbef644e855410645a53802db9c555f976357 /drivers/gpu/drm/i915/intel_display.c
parentac82ea2e97a32f9c49d0746874b4cd1d8904d10f (diff)
drm/i915: Flush the pending flips on the CRTC before modification
This was meant to be the purpose of the intel_crtc_wait_for_pending_flips() function which is called whilst preparing the CRTC for a modeset or before disabling. However, as Ville Syrjala pointed out, we set the pending flip notification on the old framebuffer that is no longer attached to the CRTC by the time we come to flush the pending operations. Instead, we can simply wait on the pending unpin work to be finished on this CRTC, knowning that the hardware has therefore finished modifying the registers, before proceeding with our direct access. Fixes i-g-t/flip_test on non-pch platforms. pch platforms simply schedule the flip immediately when the pipe is disabled, leading to other funny issues. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@vger.kernel.org [danvet: Added i-g-t note and cc: stable] Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_display.c')
-rw-r--r--drivers/gpu/drm/i915/intel_display.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f6e274c5db62..57c1309733f6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2806,13 +2806,34 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc)
2806 udelay(100); 2806 udelay(100);
2807} 2807}
2808 2808
2809static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
2810{
2811 struct drm_device *dev = crtc->dev;
2812 struct drm_i915_private *dev_priv = dev->dev_private;
2813 unsigned long flags;
2814 bool pending;
2815
2816 if (atomic_read(&dev_priv->mm.wedged))
2817 return false;
2818
2819 spin_lock_irqsave(&dev->event_lock, flags);
2820 pending = to_intel_crtc(crtc)->unpin_work != NULL;
2821 spin_unlock_irqrestore(&dev->event_lock, flags);
2822
2823 return pending;
2824}
2825
2809static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) 2826static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
2810{ 2827{
2811 struct drm_device *dev = crtc->dev; 2828 struct drm_device *dev = crtc->dev;
2829 struct drm_i915_private *dev_priv = dev->dev_private;
2812 2830
2813 if (crtc->fb == NULL) 2831 if (crtc->fb == NULL)
2814 return; 2832 return;
2815 2833
2834 wait_event(dev_priv->pending_flip_queue,
2835 !intel_crtc_has_pending_flip(crtc));
2836
2816 mutex_lock(&dev->struct_mutex); 2837 mutex_lock(&dev->struct_mutex);
2817 intel_finish_fb(crtc->fb); 2838 intel_finish_fb(crtc->fb);
2818 mutex_unlock(&dev->struct_mutex); 2839 mutex_unlock(&dev->struct_mutex);
@@ -6217,9 +6238,8 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
6217 6238
6218 atomic_clear_mask(1 << intel_crtc->plane, 6239 atomic_clear_mask(1 << intel_crtc->plane,
6219 &obj->pending_flip.counter); 6240 &obj->pending_flip.counter);
6220 if (atomic_read(&obj->pending_flip) == 0)
6221 wake_up(&dev_priv->pending_flip_queue);
6222 6241
6242 wake_up(&dev_priv->pending_flip_queue);
6223 schedule_work(&work->work); 6243 schedule_work(&work->work);
6224 6244
6225 trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); 6245 trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);