diff options
author | Rob Clark <rob@ti.com> | 2012-10-16 18:48:40 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-11-20 00:47:21 -0500 |
commit | c6eefa1750ec0308956895027c3a79eee2ef9726 (patch) | |
tree | 9bff1495c1be215c41d956578262575723c19895 | |
parent | edec4af4c3d6d225578290a9acc38c78147df55b (diff) |
drm: add drm_send_vblank_event() helper (v5)
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 <rob@ti.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | Documentation/DocBook/drm.tmpl | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 74 | ||||
-rw-r--r-- | 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 b0300529ab13..c9cbb3fe0e6a 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl | |||
@@ -1141,23 +1141,13 @@ int max_width, max_height;</synopsis> | |||
1141 | the <methodname>page_flip</methodname> operation will be called with a | 1141 | the <methodname>page_flip</methodname> operation will be called with a |
1142 | non-NULL <parameter>event</parameter> argument pointing to a | 1142 | non-NULL <parameter>event</parameter> argument pointing to a |
1143 | <structname>drm_pending_vblank_event</structname> instance. Upon page | 1143 | <structname>drm_pending_vblank_event</structname> instance. Upon page |
1144 | flip completion the driver must fill the | 1144 | flip completion the driver must call <methodname>drm_send_vblank_event</methodname> |
1145 | <parameter>event</parameter>::<structfield>event</structfield> | 1145 | to fill in the event and send to wake up any waiting processes. |
1146 | <structfield>sequence</structfield>, <structfield>tv_sec</structfield> | 1146 | This can be performed with |
1147 | and <structfield>tv_usec</structfield> fields with the associated | ||
1148 | vertical blanking count and timestamp, add the event to the | ||
1149 | <parameter>drm_file</parameter> list of events to be signaled, and wake | ||
1150 | up any waiting process. This can be performed with | ||
1151 | <programlisting><![CDATA[ | 1147 | <programlisting><![CDATA[ |
1152 | struct timeval now; | ||
1153 | |||
1154 | event->event.sequence = drm_vblank_count_and_time(..., &now); | ||
1155 | event->event.tv_sec = now.tv_sec; | ||
1156 | event->event.tv_usec = now.tv_usec; | ||
1157 | |||
1158 | spin_lock_irqsave(&dev->event_lock, flags); | 1148 | spin_lock_irqsave(&dev->event_lock, flags); |
1159 | list_add_tail(&event->base.link, &event->base.file_priv->event_list); | 1149 | ... |
1160 | wake_up_interruptible(&event->base.file_priv->event_wait); | 1150 | drm_send_vblank_event(dev, pipe, event); |
1161 | spin_unlock_irqrestore(&dev->event_lock, flags); | 1151 | spin_unlock_irqrestore(&dev->event_lock, flags); |
1162 | ]]></programlisting> | 1152 | ]]></programlisting> |
1163 | </para> | 1153 | </para> |
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 3a3d0ce891b9..44602ef55afc 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, | |||
802 | } | 802 | } |
803 | EXPORT_SYMBOL(drm_vblank_count_and_time); | 803 | EXPORT_SYMBOL(drm_vblank_count_and_time); |
804 | 804 | ||
805 | static void send_vblank_event(struct drm_device *dev, | ||
806 | struct drm_pending_vblank_event *e, | ||
807 | unsigned long seq, struct timeval *now) | ||
808 | { | ||
809 | WARN_ON_SMP(!spin_is_locked(&dev->event_lock)); | ||
810 | e->event.sequence = seq; | ||
811 | e->event.tv_sec = now->tv_sec; | ||
812 | e->event.tv_usec = now->tv_usec; | ||
813 | |||
814 | list_add_tail(&e->base.link, | ||
815 | &e->base.file_priv->event_list); | ||
816 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
817 | trace_drm_vblank_event_delivered(e->base.pid, e->pipe, | ||
818 | e->event.sequence); | ||
819 | } | ||
820 | |||
821 | /** | ||
822 | * drm_send_vblank_event - helper to send vblank event after pageflip | ||
823 | * @dev: DRM device | ||
824 | * @crtc: CRTC in question | ||
825 | * @e: the event to send | ||
826 | * | ||
827 | * Updates sequence # and timestamp on event, and sends it to userspace. | ||
828 | * Caller must hold event lock. | ||
829 | */ | ||
830 | void drm_send_vblank_event(struct drm_device *dev, int crtc, | ||
831 | struct drm_pending_vblank_event *e) | ||
832 | { | ||
833 | struct timeval now; | ||
834 | unsigned int seq; | ||
835 | if (crtc >= 0) { | ||
836 | seq = drm_vblank_count_and_time(dev, crtc, &now); | ||
837 | } else { | ||
838 | seq = 0; | ||
839 | do_gettimeofday(&now); | ||
840 | } | ||
841 | send_vblank_event(dev, e, seq, &now); | ||
842 | } | ||
843 | EXPORT_SYMBOL(drm_send_vblank_event); | ||
844 | |||
805 | /** | 845 | /** |
806 | * drm_update_vblank_count - update the master vblank counter | 846 | * drm_update_vblank_count - update the master vblank counter |
807 | * @dev: DRM device | 847 | * @dev: DRM device |
@@ -936,6 +976,13 @@ void drm_vblank_put(struct drm_device *dev, int crtc) | |||
936 | } | 976 | } |
937 | EXPORT_SYMBOL(drm_vblank_put); | 977 | EXPORT_SYMBOL(drm_vblank_put); |
938 | 978 | ||
979 | /** | ||
980 | * drm_vblank_off - disable vblank events on a CRTC | ||
981 | * @dev: DRM device | ||
982 | * @crtc: CRTC in question | ||
983 | * | ||
984 | * Caller must hold event lock. | ||
985 | */ | ||
939 | void drm_vblank_off(struct drm_device *dev, int crtc) | 986 | void drm_vblank_off(struct drm_device *dev, int crtc) |
940 | { | 987 | { |
941 | struct drm_pending_vblank_event *e, *t; | 988 | struct drm_pending_vblank_event *e, *t; |
@@ -955,15 +1002,9 @@ void drm_vblank_off(struct drm_device *dev, int crtc) | |||
955 | DRM_DEBUG("Sending premature vblank event on disable: \ | 1002 | DRM_DEBUG("Sending premature vblank event on disable: \ |
956 | wanted %d, current %d\n", | 1003 | wanted %d, current %d\n", |
957 | e->event.sequence, seq); | 1004 | e->event.sequence, seq); |
958 | 1005 | list_del(&e->base.link); | |
959 | e->event.sequence = seq; | ||
960 | e->event.tv_sec = now.tv_sec; | ||
961 | e->event.tv_usec = now.tv_usec; | ||
962 | drm_vblank_put(dev, e->pipe); | 1006 | drm_vblank_put(dev, e->pipe); |
963 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); | 1007 | send_vblank_event(dev, e, seq, &now); |
964 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
965 | trace_drm_vblank_event_delivered(e->base.pid, e->pipe, | ||
966 | e->event.sequence); | ||
967 | } | 1008 | } |
968 | 1009 | ||
969 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 1010 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
@@ -1107,15 +1148,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
1107 | 1148 | ||
1108 | e->event.sequence = vblwait->request.sequence; | 1149 | e->event.sequence = vblwait->request.sequence; |
1109 | if ((seq - vblwait->request.sequence) <= (1 << 23)) { | 1150 | if ((seq - vblwait->request.sequence) <= (1 << 23)) { |
1110 | e->event.sequence = seq; | ||
1111 | e->event.tv_sec = now.tv_sec; | ||
1112 | e->event.tv_usec = now.tv_usec; | ||
1113 | drm_vblank_put(dev, pipe); | 1151 | drm_vblank_put(dev, pipe); |
1114 | list_add_tail(&e->base.link, &e->base.file_priv->event_list); | 1152 | send_vblank_event(dev, e, seq, &now); |
1115 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
1116 | vblwait->reply.sequence = seq; | 1153 | vblwait->reply.sequence = seq; |
1117 | trace_drm_vblank_event_delivered(current->pid, pipe, | ||
1118 | vblwait->request.sequence); | ||
1119 | } else { | 1154 | } else { |
1120 | /* drm_handle_vblank_events will call drm_vblank_put */ | 1155 | /* drm_handle_vblank_events will call drm_vblank_put */ |
1121 | list_add_tail(&e->base.link, &dev->vblank_event_list); | 1156 | 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) | |||
1256 | DRM_DEBUG("vblank event on %d, current %d\n", | 1291 | DRM_DEBUG("vblank event on %d, current %d\n", |
1257 | e->event.sequence, seq); | 1292 | e->event.sequence, seq); |
1258 | 1293 | ||
1259 | e->event.sequence = seq; | 1294 | list_del(&e->base.link); |
1260 | e->event.tv_sec = now.tv_sec; | ||
1261 | e->event.tv_usec = now.tv_usec; | ||
1262 | drm_vblank_put(dev, e->pipe); | 1295 | drm_vblank_put(dev, e->pipe); |
1263 | list_move_tail(&e->base.link, &e->base.file_priv->event_list); | 1296 | send_vblank_event(dev, e, seq, &now); |
1264 | wake_up_interruptible(&e->base.file_priv->event_wait); | ||
1265 | trace_drm_vblank_event_delivered(e->base.pid, e->pipe, | ||
1266 | e->event.sequence); | ||
1267 | } | 1297 | } |
1268 | 1298 | ||
1269 | spin_unlock_irqrestore(&dev->event_lock, flags); | 1299 | spin_unlock_irqrestore(&dev->event_lock, flags); |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 3fd82809b2d4..29eb23799aa4 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -1431,6 +1431,8 @@ extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); | |||
1431 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); | 1431 | extern u32 drm_vblank_count(struct drm_device *dev, int crtc); |
1432 | extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | 1432 | extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, |
1433 | struct timeval *vblanktime); | 1433 | struct timeval *vblanktime); |
1434 | extern void drm_send_vblank_event(struct drm_device *dev, int crtc, | ||
1435 | struct drm_pending_vblank_event *e); | ||
1434 | extern bool drm_handle_vblank(struct drm_device *dev, int crtc); | 1436 | extern bool drm_handle_vblank(struct drm_device *dev, int crtc); |
1435 | extern int drm_vblank_get(struct drm_device *dev, int crtc); | 1437 | extern int drm_vblank_get(struct drm_device *dev, int crtc); |
1436 | extern void drm_vblank_put(struct drm_device *dev, int crtc); | 1438 | extern void drm_vblank_put(struct drm_device *dev, int crtc); |