Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7317c75e authored by Jesse Barnes's avatar Jesse Barnes Committed by Keith Packard
Browse files

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: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent c0f372b3
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -7189,11 +7189,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
	work->old_fb_obj = intel_fb->obj;
	INIT_WORK(&work->work, intel_unpin_work_fn);

	ret = drm_vblank_get(dev, intel_crtc->pipe);
	if (ret)
		goto free_work;

	/* We borrow the event spin lock for protecting unpin_work */
	spin_lock_irqsave(&dev->event_lock, flags);
	if (intel_crtc->unpin_work) {
		spin_unlock_irqrestore(&dev->event_lock, flags);
		kfree(work);
		drm_vblank_put(dev, intel_crtc->pipe);

		DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
		return -EBUSY;
@@ -7212,10 +7217,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,

	crtc->fb = fb;

	ret = drm_vblank_get(dev, intel_crtc->pipe);
	if (ret)
		goto cleanup_objs;

	work->pending_flip_obj = obj;

	work->enable_stall_check = true;
@@ -7238,7 +7239,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,

cleanup_pending:
	atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
cleanup_objs:
	drm_gem_object_unreference(&work->old_fb_obj->base);
	drm_gem_object_unreference(&obj->base);
	mutex_unlock(&dev->struct_mutex);
@@ -7247,6 +7247,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
	intel_crtc->unpin_work = NULL;
	spin_unlock_irqrestore(&dev->event_lock, flags);

	drm_vblank_put(dev, intel_crtc->pipe);
free_work:
	kfree(work);

	return ret;