| From dc1336ff4fe08ae7cfe8301bfd7f0b2cfd31d20a Mon Sep 17 00:00:00 2001 |
| From: Jesse Barnes <jbarnes@virtuousgeek.org> |
| Date: Tue, 6 Jan 2009 10:21:24 -0800 |
| Subject: drm/i915: set vblank enabled flag correctly across IRQ install/uninstall |
| |
| From: Jesse Barnes <jbarnes@virtuousgeek.org> |
| |
| commit dc1336ff4fe08ae7cfe8301bfd7f0b2cfd31d20a upstream. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| drivers/gpu/drm/drm_irq.c | 18 +++++++++++++++--- |
| 1 file changed, 15 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/gpu/drm/drm_irq.c |
| +++ b/drivers/gpu/drm/drm_irq.c |
| @@ -259,7 +259,8 @@ EXPORT_SYMBOL(drm_irq_install); |
| */ |
| 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)) |
| return -EINVAL; |
| @@ -269,6 +270,16 @@ int drm_irq_uninstall(struct drm_device |
| dev->irq_enabled = 0; |
| 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) |
| return -EINVAL; |
| |
| @@ -617,8 +628,9 @@ int drm_wait_vblank(struct drm_device *d |
| DRM_DEBUG("waiting on vblank count %d, crtc %d\n", |
| vblwait->request.sequence, crtc); |
| DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, |
| - ((drm_vblank_count(dev, crtc) |
| - - vblwait->request.sequence) <= (1 << 23))); |
| + (((drm_vblank_count(dev, crtc) - |
| + vblwait->request.sequence) <= (1 << 23)) || |
| + !dev->irq_enabled)); |
| |
| if (ret != -EINTR) { |
| struct timeval now; |