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

Commit dc1336ff authored by Jesse Barnes's avatar Jesse Barnes Committed by Dave Airlie
Browse files

drm/i915: set vblank enabled flag correctly across IRQ install/uninstall



In the absence of kernel mode setting, many drivers disable IRQs across VT
switch.  The core DRM vblank code is missing a check for this case however;
even after IRQ disable, the vblank code will still have the vblank_enabled
flag set, so unless we track the fact that they're disabled at IRQ uninstall
time, when we VT switch back in we won't actually re-enable them, which means
any apps waiting on vblank before the switch will hang.

This patch does that and also adds a sanity check to the wait condition to
look for the irq_enabled flag in general, as well as adding a wakeup to the
IRQ uninstall path.

Fixes fdo bug #18879 with compiz hangs at VT switch.

Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 71e0ffa5
Loading
Loading
Loading
Loading
+15 −3
Original line number Original line Diff line number Diff line
@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install);
 */
 */
int drm_irq_uninstall(struct drm_device * dev)
int drm_irq_uninstall(struct drm_device * dev)
{
{
	int irq_enabled;
	unsigned long irqflags;
	int irq_enabled, i;


	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
	if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
		return -EINVAL;
		return -EINVAL;
@@ -277,6 +278,16 @@ int drm_irq_uninstall(struct drm_device * dev)
	dev->irq_enabled = 0;
	dev->irq_enabled = 0;
	mutex_unlock(&dev->struct_mutex);
	mutex_unlock(&dev->struct_mutex);


	/*
	 * Wake up any waiters so they don't hang.
	 */
	spin_lock_irqsave(&dev->vbl_lock, irqflags);
	for (i = 0; i < dev->num_crtcs; i++) {
		DRM_WAKEUP(&dev->vbl_queue[i]);
		dev->vblank_enabled[i] = 0;
	}
	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);

	if (!irq_enabled)
	if (!irq_enabled)
		return -EINVAL;
		return -EINVAL;


@@ -652,8 +663,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
			  vblwait->request.sequence, crtc);
			  vblwait->request.sequence, crtc);
		dev->last_vblank_wait[crtc] = vblwait->request.sequence;
		dev->last_vblank_wait[crtc] = vblwait->request.sequence;
		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
		DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ,
			    ((drm_vblank_count(dev, crtc)
			    (((drm_vblank_count(dev, crtc) -
			      - vblwait->request.sequence) <= (1 << 23)));
			       vblwait->request.sequence) <= (1 << 23)) ||
			     !dev->irq_enabled));


		if (ret != -EINTR) {
		if (ret != -EINTR) {
			struct timeval now;
			struct timeval now;