From 7f668375781e046b7c7f06c200b42948f5520eab Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 16 Jun 2011 12:59:17 +0100 Subject: [PATCH] drm/i915: Finish any pending operations on the framebuffer before disabling Similar to the case where we are changing from one framebuffer to another, we need to be sure that there are no pending WAIT_FOR_EVENTs on the pipe for the current framebuffer before switching. If we disable the pipe, and then try to execute a WAIT_FOR_EVENT it will block indefinitely and cause a GPU hang. We attempted to fix this in commit 85345517fe6d4de27b0d6ca19fef9d28ac947c4a (drm/i915: Retire any pending operations on the old scanout when switching) for the case of mode switching, but this leaves the condition where we are switching off the pipe vulnerable. There still remains the race condition were a display may be unplugged, switched off by the core, a uevent sent to notify the DDX and the DDX may issue a WAIT_FOR_EVENT before it processes the uevent. This window does not exist if the pipe is only switched off in response to the uevent. Time to make sure that is so... Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/intel_display.c | 45 +++++++++++++++++++-------------- 1 files changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 81a9059..2c70614 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1923,6 +1923,29 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, return 0; } +static void +intel_finish_fb(struct drm_framebuffer *old_fb) +{ + struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int ret; + + wait_event(dev_priv->pending_flip_queue, + atomic_read(&dev_priv->mm.wedged) || + atomic_read(&obj->pending_flip) == 0); + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. + * + * This should only fail upon a hung GPU, in which case we + * can safely continue. + */ + ret = i915_gem_object_flush_gpu(obj); + (void)ret; +} + static int intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) @@ -1955,25 +1978,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - if (old_fb) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *obj = to_intel_framebuffer(old_fb)->obj; - - wait_event(dev_priv->pending_flip_queue, - atomic_read(&dev_priv->mm.wedged) || - atomic_read(&obj->pending_flip) == 0); - - /* Big Hammer, we also need to ensure that any pending - * MI_WAIT_FOR_EVENT inside a user batch buffer on the - * current scanout is retired before unpinning the old - * framebuffer. - * - * This should only fail upon a hung GPU, in which case we - * can safely continue. - */ - ret = i915_gem_object_flush_gpu(obj); - (void) ret; - } + if (old_fb) + intel_finish_fb(old_fb); ret = intel_pipe_set_base_atomic(crtc, crtc->fb, x, y, LEAVE_ATOMIC_MODE_SET); @@ -2981,6 +2987,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc) if (crtc->fb) { mutex_lock(&dev->struct_mutex); + intel_finish_fb(crtc->fb); i915_gem_object_unpin(to_intel_framebuffer(crtc->fb)->obj); mutex_unlock(&dev->struct_mutex); } -- 1.7.5.4