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

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
...@@ -267,7 +267,8 @@ EXPORT_SYMBOL(drm_irq_install); ...@@ -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) ...@@ -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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment