aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-10-16 18:48:40 -0400
committerDave Airlie <airlied@redhat.com>2012-11-20 00:47:21 -0500
commitc6eefa1750ec0308956895027c3a79eee2ef9726 (patch)
tree9bff1495c1be215c41d956578262575723c19895
parentedec4af4c3d6d225578290a9acc38c78147df55b (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.tmpl20
-rw-r--r--drivers/gpu/drm/drm_irq.c74
-rw-r--r--include/drm/drmP.h2
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}
803EXPORT_SYMBOL(drm_vblank_count_and_time); 803EXPORT_SYMBOL(drm_vblank_count_and_time);
804 804
805static 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 */
830void 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}
843EXPORT_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}
937EXPORT_SYMBOL(drm_vblank_put); 977EXPORT_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 */
939void drm_vblank_off(struct drm_device *dev, int crtc) 986void 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);
1431extern u32 drm_vblank_count(struct drm_device *dev, int crtc); 1431extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
1432extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, 1432extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
1433 struct timeval *vblanktime); 1433 struct timeval *vblanktime);
1434extern void drm_send_vblank_event(struct drm_device *dev, int crtc,
1435 struct drm_pending_vblank_event *e);
1434extern bool drm_handle_vblank(struct drm_device *dev, int crtc); 1436extern bool drm_handle_vblank(struct drm_device *dev, int crtc);
1435extern int drm_vblank_get(struct drm_device *dev, int crtc); 1437extern int drm_vblank_get(struct drm_device *dev, int crtc);
1436extern void drm_vblank_put(struct drm_device *dev, int crtc); 1438extern void drm_vblank_put(struct drm_device *dev, int crtc);