diff mbox

[1/3] drm: Send pending vblank events before disabling vblank.

Message ID 1303884659-739-1-git-send-email-christopher.halse.rogers@canonical.com (mailing list archive)
State New, archived
Headers show

Commit Message

Christopher James Halse Rogers April 27, 2011, 6:10 a.m. UTC
From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>

This is the least-bad behaviour.  It means that we signal the
vblank event before it actually happens, but since we're disabling
vblanks there's no guarantee that it will *ever* happen otherwise.

This prevents GL applications which use WaitMSC from hanging
indefinitely.

Signed-off-by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
---
 drivers/gpu/drm/drm_irq.c |   23 +++++++++++++++++++++++
 1 files changed, 23 insertions(+), 0 deletions(-)

Comments

Michel Dänzer April 27, 2011, 8:32 a.m. UTC | #1
On Mit, 2011-04-27 at 16:10 +1000, christopher.halse.rogers@canonical.com wrote:
> From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> 
> This is the least-bad behaviour.  It means that we signal the
> vblank event before it actually happens, but since we're disabling
> vblanks there's no guarantee that it will *ever* happen otherwise.

This may indeed be the best we can do for events that are pending when
the CRTC is disabled[0], but I can't see anything that would prevent new
events from getting scheduled (or synchronous vblank waits from timing
out) while the CRTC is disabled?

[0] Though it might unnecessarily send events prematurely when the CRTC
is just disabled temporarily, e.g. as part of a modeset.


Also, this patch won't seem to help at all for other drivers which don't
call drm_vblank_off() directly when disabling a CRTC.

Maybe it would be possible to move those calls to core code, and/or only
force sending out events when the CRTC isn't just getting disabled
temporarily.
Christopher James Halse Rogers April 27, 2011, 8:58 a.m. UTC | #2
On Wed, 2011-04-27 at 10:32 +0200, Michel Dänzer wrote:
> On Mit, 2011-04-27 at 16:10 +1000, christopher.halse.rogers@canonical.com wrote:
> > From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> > 
> > This is the least-bad behaviour.  It means that we signal the
> > vblank event before it actually happens, but since we're disabling
> > vblanks there's no guarantee that it will *ever* happen otherwise.
> 
> This may indeed be the best we can do for events that are pending when
> the CRTC is disabled[0], but I can't see anything that would prevent new
> events from getting scheduled (or synchronous vblank waits from timing
> out) while the CRTC is disabled?
> 
> [0] Though it might unnecessarily send events prematurely when the CRTC
> is just disabled temporarily, e.g. as part of a modeset.
> 
> 
> Also, this patch won't seem to help at all for other drivers which don't
> call drm_vblank_off() directly when disabling a CRTC.

This is true.  On the other hand, the other drivers don't wedge the
vblank code into a state where vblanks cannot be re-enabled.  So it's
only a problem when disabling one of 2+ monitors on those drivers,
whereas it's easily triggerable on single monitor systems on intel. 

> 
> Maybe it would be possible to move those calls to core code, and/or only
> force sending out events when the CRTC isn't just getting disabled
> temporarily.
> 

As in: have the core modesetting code call drm_vblank_off before making
the driver-specific calls when disabling a crtc?  I'll look into it -
that would appear to be a more general solution.

It would be nice if the OML_sync_control had been written with a less
than laser-like focus on the single monitor case, too. :/
Michel Dänzer April 27, 2011, 9:08 a.m. UTC | #3
On Mit, 2011-04-27 at 18:58 +1000, Christopher James Halse Rogers
wrote: 
> On Wed, 2011-04-27 at 10:32 +0200, Michel Dänzer wrote:
> > On Mit, 2011-04-27 at 16:10 +1000, christopher.halse.rogers@canonical.com wrote:
> > > From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> > > 
> > > This is the least-bad behaviour.  It means that we signal the
> > > vblank event before it actually happens, but since we're disabling
> > > vblanks there's no guarantee that it will *ever* happen otherwise.
> > 
> > This may indeed be the best we can do for events that are pending when
> > the CRTC is disabled[0], but I can't see anything that would prevent new
> > events from getting scheduled (or synchronous vblank waits from timing
> > out) while the CRTC is disabled?
> > 
> > [0] Though it might unnecessarily send events prematurely when the CRTC
> > is just disabled temporarily, e.g. as part of a modeset.
> > 
> > 
> > Also, this patch won't seem to help at all for other drivers which don't
> > call drm_vblank_off() directly when disabling a CRTC.
> 
> This is true.  On the other hand, the other drivers don't wedge the
> vblank code into a state where vblanks cannot be re-enabled.  So it's
> only a problem when disabling one of 2+ monitors on those drivers,

And with DPMS?

> whereas it's easily triggerable on single monitor systems on intel. 

Anyway, this patch is probably good at least as a preliminary fix for
the inconsistent vblank state with the intel driver.


> > Maybe it would be possible to move those calls to core code, and/or only
> > force sending out events when the CRTC isn't just getting disabled
> > temporarily.
> > 
> 
> As in: have the core modesetting code call drm_vblank_off before making
> the driver-specific calls when disabling a crtc?  I'll look into it -
> that would appear to be a more general solution.

Yeah, something like that, thanks.
Christopher James Halse Rogers April 27, 2011, 9:17 a.m. UTC | #4
On Wed, 2011-04-27 at 11:08 +0200, Michel Dänzer wrote:
> On Mit, 2011-04-27 at 18:58 +1000, Christopher James Halse Rogers
> wrote: 
> > On Wed, 2011-04-27 at 10:32 +0200, Michel Dänzer wrote:
> > > On Mit, 2011-04-27 at 16:10 +1000, christopher.halse.rogers@canonical.com wrote:
> > > > From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> > > > 
> > > > This is the least-bad behaviour.  It means that we signal the
> > > > vblank event before it actually happens, but since we're disabling
> > > > vblanks there's no guarantee that it will *ever* happen otherwise.
> > > 
> > > This may indeed be the best we can do for events that are pending when
> > > the CRTC is disabled[0], but I can't see anything that would prevent new
> > > events from getting scheduled (or synchronous vblank waits from timing
> > > out) while the CRTC is disabled?
> > > 
> > > [0] Though it might unnecessarily send events prematurely when the CRTC
> > > is just disabled temporarily, e.g. as part of a modeset.
> > > 
> > > 
> > > Also, this patch won't seem to help at all for other drivers which don't
> > > call drm_vblank_off() directly when disabling a CRTC.
> > 
> > This is true.  On the other hand, the other drivers don't wedge the
> > vblank code into a state where vblanks cannot be re-enabled.  So it's
> > only a problem when disabling one of 2+ monitors on those drivers,
> 
> And with DPMS?
> 

Possibly.  Since vblanks aren't wedged off in this case it's more likely
that the user turning the monitors back on will result in a vblank irq,
which will kick everything back into correct operation.

I've not managed to trigger this on my radeon system in the same way as
my intel systems, but I haven't stressed it as hard either.
Christopher James Halse Rogers April 28, 2011, 8:09 a.m. UTC | #5
On Wed, 2011-04-27 at 11:08 +0200, Michel Dänzer wrote:
> On Mit, 2011-04-27 at 18:58 +1000, Christopher James Halse Rogers
> wrote: 
> > On Wed, 2011-04-27 at 10:32 +0200, Michel Dänzer wrote:
> > > On Mit, 2011-04-27 at 16:10 +1000, christopher.halse.rogers@canonical.com wrote:
> > > > From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> > > > 
> > > > This is the least-bad behaviour.  It means that we signal the
> > > > vblank event before it actually happens, but since we're disabling
> > > > vblanks there's no guarantee that it will *ever* happen otherwise.
> > > 
> > > This may indeed be the best we can do for events that are pending when
> > > the CRTC is disabled[0], but I can't see anything that would prevent new
> > > events from getting scheduled (or synchronous vblank waits from timing
> > > out) while the CRTC is disabled?
> > > 
> > > [0] Though it might unnecessarily send events prematurely when the CRTC
> > > is just disabled temporarily, e.g. as part of a modeset.
> > > 
> > > 
> > > Also, this patch won't seem to help at all for other drivers which don't
> > > call drm_vblank_off() directly when disabling a CRTC.
> > 
> > This is true.  On the other hand, the other drivers don't wedge the
> > vblank code into a state where vblanks cannot be re-enabled.  So it's
> > only a problem when disabling one of 2+ monitors on those drivers,
> 
> And with DPMS?
> 
> > whereas it's easily triggerable on single monitor systems on intel. 
> 
> Anyway, this patch is probably good at least as a preliminary fix for
> the inconsistent vblank state with the intel driver.
> 
> 
> > > Maybe it would be possible to move those calls to core code, and/or only
> > > force sending out events when the CRTC isn't just getting disabled
> > > temporarily.
> > > 
> > 
> > As in: have the core modesetting code call drm_vblank_off before making
> > the driver-specific calls when disabling a crtc?  I'll look into it -
> > that would appear to be a more general solution.
> 
> Yeah, something like that, thanks.
> 

Ok.  This appears to be surprisingly difficult.  Particularly, the
vblank code indexes crtcs based on the driver-private numbering, and
there doesn't appear to be a generic interface to grab this number;
Intel uses the DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID ioctl, radeon uses
something different.

I'll see what I can come up with, but I don't think I'm sufficiently
familiar with the kms code to quickly come up with a nice API.
Jesse Barnes April 28, 2011, 8:34 p.m. UTC | #6
On Wed, 27 Apr 2011 16:10:57 +1000
christopher.halse.rogers@canonical.com wrote:

> From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> 
> This is the least-bad behaviour.  It means that we signal the
> vblank event before it actually happens, but since we're disabling
> vblanks there's no guarantee that it will *ever* happen otherwise.
> 
> This prevents GL applications which use WaitMSC from hanging
> indefinitely.
> 
> Signed-off-by: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> ---
>  drivers/gpu/drm/drm_irq.c |   23 +++++++++++++++++++++++
>  1 files changed, 23 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
> index 741457b..a1f12cb 100644
> --- a/drivers/gpu/drm/drm_irq.c
> +++ b/drivers/gpu/drm/drm_irq.c
> @@ -932,11 +932,34 @@ EXPORT_SYMBOL(drm_vblank_put);
>  
>  void drm_vblank_off(struct drm_device *dev, int crtc)
>  {
> +	struct drm_pending_vblank_event *e, *t;
> +	struct timeval now;
>  	unsigned long irqflags;
> +	unsigned int seq;
>  
>  	spin_lock_irqsave(&dev->vbl_lock, irqflags);
>  	vblank_disable_and_save(dev, crtc);
>  	DRM_WAKEUP(&dev->vbl_queue[crtc]);
> +
> +	/* Send any queued vblank events, lest the natives grow disquiet */
> +	seq = drm_vblank_count_and_time(dev, crtc, &now);
> +	list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
> +		if (e->pipe != crtc)
> +			continue;
> +		DRM_DEBUG("Sending premature vblank event on disable: \
> +			  wanted %d, current %d\n",
> +			  e->event.sequence, seq);
> +
> +		e->event.sequence = seq;
> +		e->event.tv_sec = now.tv_sec;
> +		e->event.tv_usec = now.tv_usec;
> +		drm_vblank_put(dev, e->pipe);
> +		list_move_tail(&e->base.link, &e->base.file_priv->event_list);
> +		wake_up_interruptible(&e->base.file_priv->event_wait);
> +		trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
> +						 e->event.sequence);
> +	}
> +
>  	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
>  }
>  EXPORT_SYMBOL(drm_vblank_off);

Yeah, this matches what we do for the blocking waits, and it's probably
a good idea.  Userspace can decide what to do with apps running against
a disabled CRTC.

Would be nice to share the code with drm_handle_vblank_events though
somehow.  Looks like

		e->event.sequence = seq;
		e->event.tv_sec = now.tv_sec;
		e->event.tv_usec = now.tv_usec;
		drm_vblank_put(dev, e->pipe);
		list_move_tail(&e->base.link, &e->base.file_priv->event_list);
		wake_up_interruptible(&e->base.file_priv->event_wait);
		trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
						 e->event.sequence);

could be pulled out into a separate function for both to use.
Jesse Barnes April 28, 2011, 8:42 p.m. UTC | #7
On Wed, 27 Apr 2011 10:32:36 +0200
Michel Dänzer <michel@daenzer.net> wrote:

> On Mit, 2011-04-27 at 16:10 +1000, christopher.halse.rogers@canonical.com wrote:
> > From: Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> > 
> > This is the least-bad behaviour.  It means that we signal the
> > vblank event before it actually happens, but since we're disabling
> > vblanks there's no guarantee that it will *ever* happen otherwise.
> 
> This may indeed be the best we can do for events that are pending when
> the CRTC is disabled[0], but I can't see anything that would prevent new
> events from getting scheduled (or synchronous vblank waits from timing
> out) while the CRTC is disabled?
> 
> [0] Though it might unnecessarily send events prematurely when the CRTC
> is just disabled temporarily, e.g. as part of a modeset.

We should return -EINVAL in that case from drm_wait_vblank due to
drm_vblank_get failing (i.e. the driver enable_vblank hook should fail
if the corresponding crtc is off).  At least that's how it's supposed
to work.
Jesse Barnes April 28, 2011, 8:46 p.m. UTC | #8
On Thu, 28 Apr 2011 18:09:58 +1000
Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
wrote:
> Ok.  This appears to be surprisingly difficult.  Particularly, the
> vblank code indexes crtcs based on the driver-private numbering, and
> there doesn't appear to be a generic interface to grab this number;
> Intel uses the DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID ioctl, radeon uses
> something different.
> 
> I'll see what I can come up with, but I don't think I'm sufficiently
> familiar with the kms code to quickly come up with a nice API.

Yeah, unfortunately the vblank code pre-dates the KMS code by quite a
bit, so the IDs don't match.

But with the events emitted as in your previous patch, this should be a
harder case to hit, but it sounds like we need to make sure the flip
waits are dealt with too to avoid this from triggering at all on
Intel.  Or did you see other cases where the refcount was nonzero at
this point?

Thanks,
Jesse Barnes April 28, 2011, 8:53 p.m. UTC | #9
On Thu, 28 Apr 2011 13:46:30 -0700
Jesse Barnes <jbarnes@virtuousgeek.org> wrote:

> On Thu, 28 Apr 2011 18:09:58 +1000
> Christopher James Halse Rogers <christopher.halse.rogers@canonical.com>
> wrote:
> > Ok.  This appears to be surprisingly difficult.  Particularly, the
> > vblank code indexes crtcs based on the driver-private numbering, and
> > there doesn't appear to be a generic interface to grab this number;
> > Intel uses the DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID ioctl, radeon uses
> > something different.
> > 
> > I'll see what I can come up with, but I don't think I'm sufficiently
> > familiar with the kms code to quickly come up with a nice API.
> 
> Yeah, unfortunately the vblank code pre-dates the KMS code by quite a
> bit, so the IDs don't match.
> 
> But with the events emitted as in your previous patch, this should be a
> harder case to hit, but it sounds like we need to make sure the flip
> waits are dealt with too to avoid this from triggering at all on
> Intel.  Or did you see other cases where the refcount was nonzero at
> this point?

Actually it looks like we wait for any outstanding flips before
disabling so that seems correct (though I didn't check the locking,
it's possible we could race a completion and a new flip if the flip
ioctl and the dpms code don't exclude each other).
diff mbox

Patch

diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 741457b..a1f12cb 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -932,11 +932,34 @@  EXPORT_SYMBOL(drm_vblank_put);
 
 void drm_vblank_off(struct drm_device *dev, int crtc)
 {
+	struct drm_pending_vblank_event *e, *t;
+	struct timeval now;
 	unsigned long irqflags;
+	unsigned int seq;
 
 	spin_lock_irqsave(&dev->vbl_lock, irqflags);
 	vblank_disable_and_save(dev, crtc);
 	DRM_WAKEUP(&dev->vbl_queue[crtc]);
+
+	/* Send any queued vblank events, lest the natives grow disquiet */
+	seq = drm_vblank_count_and_time(dev, crtc, &now);
+	list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) {
+		if (e->pipe != crtc)
+			continue;
+		DRM_DEBUG("Sending premature vblank event on disable: \
+			  wanted %d, current %d\n",
+			  e->event.sequence, seq);
+
+		e->event.sequence = seq;
+		e->event.tv_sec = now.tv_sec;
+		e->event.tv_usec = now.tv_usec;
+		drm_vblank_put(dev, e->pipe);
+		list_move_tail(&e->base.link, &e->base.file_priv->event_list);
+		wake_up_interruptible(&e->base.file_priv->event_wait);
+		trace_drm_vblank_event_delivered(e->base.pid, e->pipe,
+						 e->event.sequence);
+	}
+
 	spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
 EXPORT_SYMBOL(drm_vblank_off);