Commit 7317c75e66fce0c9f82fbe6f72f7e5256b315422

Authored by Jesse Barnes
Committed by Keith Packard
1 parent c0f372b374

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>

Showing 1 changed file with 7 additions and 5 deletions Side-by-side Diff

drivers/gpu/drm/i915/intel_display.c
... ... @@ -7189,11 +7189,16 @@
7189 7189 work->old_fb_obj = intel_fb->obj;
7190 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 7196 /* We borrow the event spin lock for protecting unpin_work */
7193 7197 spin_lock_irqsave(&dev->event_lock, flags);
7194 7198 if (intel_crtc->unpin_work) {
7195 7199 spin_unlock_irqrestore(&dev->event_lock, flags);
7196 7200 kfree(work);
  7201 + drm_vblank_put(dev, intel_crtc->pipe);
7197 7202  
7198 7203 DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
7199 7204 return -EBUSY;
... ... @@ -7212,10 +7217,6 @@
7212 7217  
7213 7218 crtc->fb = fb;
7214 7219  
7215   - ret = drm_vblank_get(dev, intel_crtc->pipe);
7216   - if (ret)
7217   - goto cleanup_objs;
7218   -
7219 7220 work->pending_flip_obj = obj;
7220 7221  
7221 7222 work->enable_stall_check = true;
... ... @@ -7238,7 +7239,6 @@
7238 7239  
7239 7240 cleanup_pending:
7240 7241 atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
7241   -cleanup_objs:
7242 7242 drm_gem_object_unreference(&work->old_fb_obj->base);
7243 7243 drm_gem_object_unreference(&obj->base);
7244 7244 mutex_unlock(&dev->struct_mutex);
... ... @@ -7247,6 +7247,8 @@
7247 7247 intel_crtc->unpin_work = NULL;
7248 7248 spin_unlock_irqrestore(&dev->event_lock, flags);
7249 7249  
  7250 + drm_vblank_put(dev, intel_crtc->pipe);
  7251 +free_work:
7250 7252 kfree(work);
7251 7253  
7252 7254 return ret;