[PATCH 01/11] drm: add drm_send_vblank_event() helper (v5)
From: Rob ClarkA 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 v4: use WARN_ON_SMP() instead to fix issue with !SMP && !DEBUG_SPINLOCK as pointed out by Marcin Slusarz v5: update docbook Signed-off-by: Rob Clark --- Documentation/DocBook/drm.tmpl | 20 +++ drivers/gpu/drm/drm_irq.c | 74 include/drm/drmP.h |2 ++ 3 files changed, 59 insertions(+), 37 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index b030052..c9cbb3f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1141,23 +1141,13 @@ int max_width, max_height; the page_flip operation will be called with a non-NULL event argument pointing to a drm_pending_vblank_event instance. Upon page -flip completion the driver must fill the -event::event -sequence, tv_sec -and tv_usec fields with the associated -vertical blanking count and timestamp, add the event to the -drm_file list of events to be signaled, and wake -up any waiting process. This can be performed with +flip completion the driver must call drm_send_vblank_event +to fill in the event and send to wake up any waiting processes. +This can be performed with diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 076c4a8..9bdcfd5 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_SMP(!spin_is_locked(>event_lock)); + e->event.sequence = seq; + e->event.tv_sec = now->tv_sec; + e->event.tv_usec = now->tv_usec; + + list_add_tail(>base.link, + >base.file_priv->event_list); + wake_up_interruptible(>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, ); + } else { + seq = 0; + do_gettimeofday(); + } + send_vblank_event(dev, e, seq, ); +} +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(>base.link); drm_vblank_put(dev, e->pipe); - list_move_tail(>base.link, >base.file_priv->event_list); - wake_up_interruptible(>base.file_priv->event_wait); - trace_drm_vblank_event_delivered(e->base.pid, e->pipe, -e->event.sequence); + send_vblank_event(dev, e, seq, ); } spin_unlock_irqrestore(>vbl_lock, irqflags); @@ -1107,15 +1148,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
[PATCH 01/11] drm: add drm_send_vblank_event() helper (v5)
From: Rob Clark r...@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 v4: use WARN_ON_SMP() instead to fix issue with !SMP !DEBUG_SPINLOCK as pointed out by Marcin Slusarz v5: update docbook Signed-off-by: Rob Clark r...@ti.com --- Documentation/DocBook/drm.tmpl | 20 +++ drivers/gpu/drm/drm_irq.c | 74 include/drm/drmP.h |2 ++ 3 files changed, 59 insertions(+), 37 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index b030052..c9cbb3f 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1141,23 +1141,13 @@ int max_width, max_height;/synopsis the methodnamepage_flip/methodname operation will be called with a non-NULL parameterevent/parameter argument pointing to a structnamedrm_pending_vblank_event/structname instance. Upon page -flip completion the driver must fill the -parameterevent/parameter::structfieldevent/structfield -structfieldsequence/structfield, structfieldtv_sec/structfield -and structfieldtv_usec/structfield fields with the associated -vertical blanking count and timestamp, add the event to the -parameterdrm_file/parameter list of events to be signaled, and wake -up any waiting process. This can be performed with +flip completion the driver must call methodnamedrm_send_vblank_event/methodname +to fill in the event and send to wake up any waiting processes. +This can be performed with programlisting![CDATA[ -struct timeval now; - -event-event.sequence = drm_vblank_count_and_time(..., now); -event-event.tv_sec = now.tv_sec; -event-event.tv_usec = now.tv_usec; - spin_lock_irqsave(dev-event_lock, flags); -list_add_tail(event-base.link, event-base.file_priv-event_list); -wake_up_interruptible(event-base.file_priv-event_wait); +... +drm_send_vblank_event(dev, pipe, event); spin_unlock_irqrestore(dev-event_lock, flags); ]]/programlisting /para diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 076c4a8..9bdcfd5 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_SMP(!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: \