From: Ville Syrj?l? <ville.syrjala at linux.intel.com> 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. Signed-off-by: Ville Syrj?l? <ville.syrjala at linux.intel.com> --- drivers/gpu/drm/i915/i915_irq.c | 2 ++ drivers/gpu/drm/i915/intel_display.c | 31 +++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 2 ++ 3 files changed, 35 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 672816a..873552d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -917,6 +917,8 @@ static void i915_error_work_func(struct work_struct *work) wake_up_all(&dev_priv->pending_flip_queue); + intel_display_handle_reset(dev); + wake_up_all(&dev_priv->gpu_error.reset_queue); } } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f0c6416..bc277dc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2218,6 +2218,37 @@ 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. + */ + + 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); + + 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) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d282052..0dc14c2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -694,4 +694,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__ */ -- 1.7.12.4