Message ID | 1350001756-5460-1-git-send-email-rob.clark@linaro.org |
---|---|
State | New |
Headers | show |
On Thu, Oct 11, 2012 at 07:29:15PM -0500, Rob Clark wrote: > From: Rob Clark <rob@ti.com> > > A helper that drivers can use to send vblank event after a pageflip. > If the driver doesn't support proper vblank irq based time/seqn then > just pass -1 for the pipe # to get do_gettimestamp() behavior (since > there are a lot of drivers that don't use drm_vblank_count_and_time()) > > Also an internal send_vblank_event() helper for the various other code > paths within drm_irq that also need to send vblank events. > > v1: original > v2: add back 'vblwait->reply.sequence = seq' which should not have > been deleted > v3: add WARN_ON() in case lock is not held and comments > > Signed-off-by: Rob Clark <rob@ti.com> > --- > drivers/gpu/drm/drm_irq.c | 74 +++++++++++++++++++++++++++++++-------------- > include/drm/drmP.h | 2 ++ > 2 files changed, 54 insertions(+), 22 deletions(-) > > diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c > index 076c4a8..d623a06 100644 > --- a/drivers/gpu/drm/drm_irq.c > +++ b/drivers/gpu/drm/drm_irq.c > @@ -802,6 +802,46 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, > } > EXPORT_SYMBOL(drm_vblank_count_and_time); > > +static void send_vblank_event(struct drm_device *dev, > + struct drm_pending_vblank_event *e, > + unsigned long seq, struct timeval *now) > +{ > + WARN_ON(!spin_is_locked(&dev->event_lock)); This should be WARN_ON_SMP - on !SMP && !DEBUG_SPINLOCK spin_is_locked always returns 0. > + e->event.sequence = seq; > + e->event.tv_sec = now->tv_sec; > + e->event.tv_usec = now->tv_usec; > + > + list_add_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); > +} > + > +/** > + * drm_send_vblank_event - helper to send vblank event after pageflip > + * @dev: DRM device > + * @crtc: CRTC in question > + * @e: the event to send > + * > + * Updates sequence # and timestamp on event, and sends it to userspace. > + * Caller must hold event lock. > + */ > +void drm_send_vblank_event(struct drm_device *dev, int crtc, > + struct drm_pending_vblank_event *e) > +{ > + struct timeval now; > + unsigned int seq; > + if (crtc >= 0) { > + seq = drm_vblank_count_and_time(dev, crtc, &now); > + } else { > + seq = 0; > + do_gettimeofday(&now); > + } > + send_vblank_event(dev, e, seq, &now); > +} > +EXPORT_SYMBOL(drm_send_vblank_event); > + > /** > * drm_update_vblank_count - update the master vblank counter > * @dev: DRM device > @@ -936,6 +976,13 @@ void drm_vblank_put(struct drm_device *dev, int crtc) > } > EXPORT_SYMBOL(drm_vblank_put); > > +/** > + * drm_vblank_off - disable vblank events on a CRTC > + * @dev: DRM device > + * @crtc: CRTC in question > + * > + * Caller must hold event lock. > + */ > void drm_vblank_off(struct drm_device *dev, int crtc) > { > struct drm_pending_vblank_event *e, *t; > @@ -955,15 +1002,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) > 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; > + list_del(&e->base.link); > 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); > + send_vblank_event(dev, e, seq, &now); > } > > spin_unlock_irqrestore(&dev->vbl_lock, irqflags); > @@ -1107,15 +1148,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, > > e->event.sequence = vblwait->request.sequence; > if ((seq - vblwait->request.sequence) <= (1 << 23)) { > - e->event.sequence = seq; > - e->event.tv_sec = now.tv_sec; > - e->event.tv_usec = now.tv_usec; > drm_vblank_put(dev, pipe); > - list_add_tail(&e->base.link, &e->base.file_priv->event_list); > - wake_up_interruptible(&e->base.file_priv->event_wait); > + send_vblank_event(dev, e, seq, &now); > vblwait->reply.sequence = seq; > - trace_drm_vblank_event_delivered(current->pid, pipe, > - vblwait->request.sequence); > } else { > /* drm_handle_vblank_events will call drm_vblank_put */ > list_add_tail(&e->base.link, &dev->vblank_event_list); > @@ -1256,14 +1291,9 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) > DRM_DEBUG("vblank event on %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; > + list_del(&e->base.link); > 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); > + send_vblank_event(dev, e, seq, &now); > } > > spin_unlock_irqrestore(&dev->event_lock, flags); > diff --git a/include/drm/drmP.h b/include/drm/drmP.h > index 05af0e7..ee8f927 100644 > --- a/include/drm/drmP.h > +++ b/include/drm/drmP.h > @@ -1437,6 +1437,8 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); > extern u32 drm_vblank_count(struct drm_device *dev, int crtc); > extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, > struct timeval *vblanktime); > +extern void drm_send_vblank_event(struct drm_device *dev, int crtc, > + struct drm_pending_vblank_event *e); > extern bool drm_handle_vblank(struct drm_device *dev, int crtc); > extern int drm_vblank_get(struct drm_device *dev, int crtc); > extern void drm_vblank_put(struct drm_device *dev, int crtc); > --
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 076c4a8..d623a06 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -802,6 +802,46 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, } EXPORT_SYMBOL(drm_vblank_count_and_time); +static void send_vblank_event(struct drm_device *dev, + struct drm_pending_vblank_event *e, + unsigned long seq, struct timeval *now) +{ + WARN_ON(!spin_is_locked(&dev->event_lock)); + e->event.sequence = seq; + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_add_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); +} + +/** + * drm_send_vblank_event - helper to send vblank event after pageflip + * @dev: DRM device + * @crtc: CRTC in question + * @e: the event to send + * + * Updates sequence # and timestamp on event, and sends it to userspace. + * Caller must hold event lock. + */ +void drm_send_vblank_event(struct drm_device *dev, int crtc, + struct drm_pending_vblank_event *e) +{ + struct timeval now; + unsigned int seq; + if (crtc >= 0) { + seq = drm_vblank_count_and_time(dev, crtc, &now); + } else { + seq = 0; + do_gettimeofday(&now); + } + send_vblank_event(dev, e, seq, &now); +} +EXPORT_SYMBOL(drm_send_vblank_event); + /** * drm_update_vblank_count - update the master vblank counter * @dev: DRM device @@ -936,6 +976,13 @@ void drm_vblank_put(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_put); +/** + * drm_vblank_off - disable vblank events on a CRTC + * @dev: DRM device + * @crtc: CRTC in question + * + * Caller must hold event lock. + */ void drm_vblank_off(struct drm_device *dev, int crtc) { struct drm_pending_vblank_event *e, *t; @@ -955,15 +1002,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) 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; + list_del(&e->base.link); 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); + send_vblank_event(dev, e, seq, &now); } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -1107,15 +1148,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, e->event.sequence = vblwait->request.sequence; if ((seq - vblwait->request.sequence) <= (1 << 23)) { - e->event.sequence = seq; - e->event.tv_sec = now.tv_sec; - e->event.tv_usec = now.tv_usec; drm_vblank_put(dev, pipe); - list_add_tail(&e->base.link, &e->base.file_priv->event_list); - wake_up_interruptible(&e->base.file_priv->event_wait); + send_vblank_event(dev, e, seq, &now); vblwait->reply.sequence = seq; - trace_drm_vblank_event_delivered(current->pid, pipe, - vblwait->request.sequence); } else { /* drm_handle_vblank_events will call drm_vblank_put */ list_add_tail(&e->base.link, &dev->vblank_event_list); @@ -1256,14 +1291,9 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) DRM_DEBUG("vblank event on %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; + list_del(&e->base.link); 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); + send_vblank_event(dev, e, seq, &now); } spin_unlock_irqrestore(&dev->event_lock, flags); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 05af0e7..ee8f927 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1437,6 +1437,8 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); extern u32 drm_vblank_count(struct drm_device *dev, int crtc); extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, struct timeval *vblanktime); +extern void drm_send_vblank_event(struct drm_device *dev, int crtc, + struct drm_pending_vblank_event *e); extern bool drm_handle_vblank(struct drm_device *dev, int crtc); extern int drm_vblank_get(struct drm_device *dev, int crtc); extern void drm_vblank_put(struct drm_device *dev, int crtc);