From: Jesse B. <jb...@vi...> - 2009-01-08 00:36:42
|
On Tuesday, January 6, 2009 10:21 am Jesse Barnes wrote: > 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. > > This patch fixes fdo bug #18879, so hopefully we can apply it or another > fix for this problem soon. Here's an updated version I've been testing with. It removes the change to drm_wait_vblank (we can still do it but it should be a separate patch). Suspend/resume works for me with this one too, so if it looks good on inspection I'd like to see it included. Even if it doesn't fix all the VT switch/IRQ install bugs we have I think it's a step in the right direction (IRQ uninstall really does imply vblank_enable == 0). Thanks, -- Jesse Barnes, Intel Open Source Technology Center diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 1e787f8..4cc8d3d 100644 --- 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) 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; |