[Intel-gfx] Interrupt handling across leave/entervt
Jesse Barnes
jbarnes at virtuousgeek.org
Wed Dec 31 22:56:15 CET 2008
On Wednesday, December 31, 2008 12:03 pm Keith Packard wrote:
> On Wed, 2008-12-31 at 11:29 -0800, Jesse Barnes wrote:
> > The problem with disabling interrupts is that the server may wait on a
> > vblank event before the DDX has had a chance to call into the entervt
> > ioctl, resulting in a hang if say compiz is running before the VT switch
> > (see bug 18879).
>
> How about waking up anyone blocked on vblank at vt switch time instead?
>
> I kinda like the idea of not touching the HW while switched away.
The real problem is that we're violating the assumption in the drm_irq.c code,
which tries to keep interrupts on across mode switches (which includes VT
switch). So what's happening is this:
1) drm code takes a vblank ref
2) vt switch ioctl disables irqs
<sitting at console>
3) vt switch re-enables irqs
4) drm code puts vblank ref
5) X server hangs waiting for an event (getting interrupted a lot)
Even though the drm_wait_vblank code takes a ref, the vblank interrupt doesn't
actually get re-enabled since when we get to drm_vblank_get dev-
>vblank_enabled[crtc] is still set. So something like the below also works.
But really, having the kernel try to keep its hands off of the hardware while
X is VT switched away is of arguable benefit, so I'd still rather just leave
things enabled across VT switches.
--
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..e2f5d23 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;
@@ -617,8 +628,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
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;
More information about the Intel-gfx
mailing list