drm/i915: Finish page flips and update primary planes after a GPU reset
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Mon, 18 Feb 2013 17:08:49 +0000 (19:08 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 20 Feb 2013 00:33:43 +0000 (01:33 +0100)
GPU reset will drop all flips that are still in the ring. So after the
reset, call update_plane() for all CRTCs to make sure the primary
planes are scanning out from the correct buffer.

Also finish all pending flips. That means user space will get its
page flip events and won't get stuck waiting for them.

v2: Explicitly finish page flips instead of relying on FLIP_DONE
    interrupt being generated by the base address update.
v3: Make two loops over crtcs to avoid deadlocks with the crtc mutex

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
[danvet: Fixup long line complaint from checkpatch.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h

index 2cd97d1cc920dbf1555af5d28d97d7cf893f6567..9fde49a299990da73abed9d5e8e29e41c3e549ac 100644 (file)
@@ -915,6 +915,8 @@ static void i915_error_work_func(struct work_struct *work)
                for_each_ring(ring, dev_priv, i)
                        wake_up_all(&ring->irq_queue);
 
+               intel_display_handle_reset(dev);
+
                wake_up_all(&dev_priv->gpu_error.reset_queue);
        }
 }
index 85bf178bac75a9b07a5229fe2f63cfd21f4e512b..ba8307dc03be73b7ce2bb4f63718ac5cc26e8eb6 100644 (file)
@@ -2218,6 +2218,44 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        return dev_priv->display.update_plane(crtc, fb, x, y);
 }
 
+void intel_display_handle_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc;
+
+       /*
+        * Flips in the rings have been nuked by the reset,
+        * so complete all pending flips so that user space
+        * will get its events and not get stuck.
+        *
+        * Also update the base address of all primary
+        * planes to the the last fb to make sure we're
+        * showing the correct fb after a reset.
+        *
+        * Need to make two loops over the crtcs so that we
+        * don't try to grab a crtc mutex before the
+        * pending_flip_queue really got woken up.
+        */
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+               enum plane plane = intel_crtc->plane;
+
+               intel_prepare_page_flip(dev, plane);
+               intel_finish_page_flip_plane(dev, plane);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+               mutex_lock(&crtc->mutex);
+               if (intel_crtc->active)
+                       dev_priv->display.update_plane(crtc, crtc->fb,
+                                                      crtc->x, crtc->y);
+               mutex_unlock(&crtc->mutex);
+       }
+}
+
 static int
 intel_finish_fb(struct drm_framebuffer *old_fb)
 {
index 005a91f1f8f5eded92cd22b4ca479d145aa9dd83..febed9a010dab441444bc3f884ae31c5f08fd024 100644 (file)
@@ -695,4 +695,6 @@ extern bool
 intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
 extern void intel_ddi_fdi_disable(struct drm_crtc *crtc);
 
+extern void intel_display_handle_reset(struct drm_device *dev);
+
 #endif /* __INTEL_DRV_H__ */