Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Dave Airlie <airlied@linux.ie>

authored by

Jesse Barnes and committed by
Dave Airlie
dc1336ff 71e0ffa5

+15 -3
+15 -3
drivers/gpu/drm/drm_irq.c
··· 267 267 */ 268 268 int drm_irq_uninstall(struct drm_device * dev) 269 269 { 270 - int irq_enabled; 270 + unsigned long irqflags; 271 + int irq_enabled, i; 271 272 272 273 if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ)) 273 274 return -EINVAL; ··· 277 276 irq_enabled = dev->irq_enabled; 278 277 dev->irq_enabled = 0; 279 278 mutex_unlock(&dev->struct_mutex); 279 + 280 + /* 281 + * Wake up any waiters so they don't hang. 282 + */ 283 + spin_lock_irqsave(&dev->vbl_lock, irqflags); 284 + for (i = 0; i < dev->num_crtcs; i++) { 285 + DRM_WAKEUP(&dev->vbl_queue[i]); 286 + dev->vblank_enabled[i] = 0; 287 + } 288 + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 280 289 281 290 if (!irq_enabled) 282 291 return -EINVAL; ··· 663 652 vblwait->request.sequence, crtc); 664 653 dev->last_vblank_wait[crtc] = vblwait->request.sequence; 665 654 DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, 666 - ((drm_vblank_count(dev, crtc) 667 - - vblwait->request.sequence) <= (1 << 23))); 655 + (((drm_vblank_count(dev, crtc) - 656 + vblwait->request.sequence) <= (1 << 23)) || 657 + !dev->irq_enabled)); 668 658 669 659 if (ret != -EINTR) { 670 660 struct timeval now;