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>
This commit is contained in:
parent
71e0ffa599
commit
dc1336ff4f
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue