aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2011-08-29 12:45:28 -0400
committerKeith Packard <keithp@keithp.com>2011-12-16 11:49:58 -0500
commit7317c75e66fce0c9f82fbe6f72f7e5256b315422 (patch)
treeb80e8c08261ee4b6551ea6d87f3fb26d578d8805
parentc0f372b3746d4ede07b2ace2beabd38d9c045b25 (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>
-rw-r--r--drivers/gpu/drm/i915/intel_display.c12
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 d544de9e663..91b5f8707a6 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
7239cleanup_pending: 7240cleanup_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);
7241cleanup_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);
7251free_work:
7250 kfree(work); 7252 kfree(work);
7251 7253
7252 return ret; 7254 return ret;