diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2011-08-29 12:45:28 -0400 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2011-12-16 11:49:58 -0500 |
commit | 7317c75e66fce0c9f82fbe6f72f7e5256b315422 (patch) | |
tree | b80e8c08261ee4b6551ea6d87f3fb26d578d8805 /drivers/gpu | |
parent | c0f372b3746d4ede07b2ace2beabd38d9c045b25 (diff) |
drm/i915: don't set unpin_work if vblank_get fails
This fixes a race where we may try to finish a page flip and decrement
the refcount even if our vblank_get failed and we ended up with a
spurious flip pending interrupt.
Fixes https://bugs.freedesktop.org/show_bug.cgi?id=34211.
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d544de9e6634..91b5f8707a62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -7189,11 +7189,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, | |||
7189 | work->old_fb_obj = intel_fb->obj; | 7189 | work->old_fb_obj = intel_fb->obj; |
7190 | INIT_WORK(&work->work, intel_unpin_work_fn); | 7190 | INIT_WORK(&work->work, intel_unpin_work_fn); |
7191 | 7191 | ||
7192 | ret = drm_vblank_get(dev, intel_crtc->pipe); | ||
7193 | if (ret) | ||
7194 | goto free_work; | ||
7195 | |||
7192 | /* We borrow the event spin lock for protecting unpin_work */ | 7196 | /* We borrow the event spin lock for protecting unpin_work */ |
7193 | spin_lock_irqsave(&dev->event_lock, flags); | 7197 | spin_lock_irqsave(&dev->event_lock, flags); |
7194 | if (intel_crtc->unpin_work) { | 7198 | if (intel_crtc->unpin_work) { |
7195 | spin_unlock_irqrestore(&dev->event_lock, flags); | 7199 | spin_unlock_irqrestore(&dev->event_lock, flags); |
7196 | kfree(work); | 7200 | kfree(work); |
7201 | drm_vblank_put(dev, intel_crtc->pipe); | ||
7197 | 7202 | ||
7198 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); | 7203 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); |
7199 | return -EBUSY; | 7204 | return -EBUSY; |
@@ -7212,10 +7217,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, | |||
7212 | 7217 | ||
7213 | crtc->fb = fb; | 7218 | crtc->fb = fb; |
7214 | 7219 | ||
7215 | ret = drm_vblank_get(dev, intel_crtc->pipe); | ||
7216 | if (ret) | ||
7217 | goto cleanup_objs; | ||
7218 | |||
7219 | work->pending_flip_obj = obj; | 7220 | work->pending_flip_obj = obj; |
7220 | 7221 | ||
7221 | work->enable_stall_check = true; | 7222 | work->enable_stall_check = true; |
@@ -7238,7 +7239,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, | |||
7238 | 7239 | ||
7239 | cleanup_pending: | 7240 | cleanup_pending: |
7240 | atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); | 7241 | atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); |
7241 | cleanup_objs: | ||
7242 | drm_gem_object_unreference(&work->old_fb_obj->base); | 7242 | drm_gem_object_unreference(&work->old_fb_obj->base); |
7243 | drm_gem_object_unreference(&obj->base); | 7243 | drm_gem_object_unreference(&obj->base); |
7244 | mutex_unlock(&dev->struct_mutex); | 7244 | mutex_unlock(&dev->struct_mutex); |
@@ -7247,6 +7247,8 @@ cleanup_objs: | |||
7247 | intel_crtc->unpin_work = NULL; | 7247 | intel_crtc->unpin_work = NULL; |
7248 | spin_unlock_irqrestore(&dev->event_lock, flags); | 7248 | spin_unlock_irqrestore(&dev->event_lock, flags); |
7249 | 7249 | ||
7250 | drm_vblank_put(dev, intel_crtc->pipe); | ||
7251 | free_work: | ||
7250 | kfree(work); | 7252 | kfree(work); |
7251 | 7253 | ||
7252 | return ret; | 7254 | return ret; |