Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Rob Clark and committed by
Dave Airlie
c6eefa17 edec4af4

+59 -37
+5 -15
Documentation/DocBook/drm.tmpl
··· 1141 1141 the <methodname>page_flip</methodname> operation will be called with a 1142 1142 non-NULL <parameter>event</parameter> argument pointing to a 1143 1143 <structname>drm_pending_vblank_event</structname> instance. Upon page 1144 - flip completion the driver must fill the 1145 - <parameter>event</parameter>::<structfield>event</structfield> 1146 - <structfield>sequence</structfield>, <structfield>tv_sec</structfield> 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 1144 + flip completion the driver must call <methodname>drm_send_vblank_event</methodname> 1145 + to fill in the event and send to wake up any waiting processes. 1146 + This can be performed with 1151 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 1148 spin_lock_irqsave(&dev->event_lock, flags); 1159 - list_add_tail(&event->base.link, &event->base.file_priv->event_list); 1160 - wake_up_interruptible(&event->base.file_priv->event_wait); 1149 + ... 1150 + drm_send_vblank_event(dev, pipe, event); 1161 1151 spin_unlock_irqrestore(&dev->event_lock, flags); 1162 1152 ]]></programlisting> 1163 1153 </para>
+52 -22
drivers/gpu/drm/drm_irq.c
··· 802 802 } 803 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 846 * drm_update_vblank_count - update the master vblank counter 807 847 * @dev: DRM device ··· 976 936 } 977 937 EXPORT_SYMBOL(drm_vblank_put); 978 938 939 + /** 940 + * drm_vblank_off - disable vblank events on a CRTC 941 + * @dev: DRM device 942 + * @crtc: CRTC in question 943 + * 944 + * Caller must hold event lock. 945 + */ 979 946 void drm_vblank_off(struct drm_device *dev, int crtc) 980 947 { 981 948 struct drm_pending_vblank_event *e, *t; ··· 1002 955 DRM_DEBUG("Sending premature vblank event on disable: \ 1003 956 wanted %d, current %d\n", 1004 957 e->event.sequence, seq); 1005 - 1006 - e->event.sequence = seq; 1007 - e->event.tv_sec = now.tv_sec; 1008 - e->event.tv_usec = now.tv_usec; 958 + list_del(&e->base.link); 1009 959 drm_vblank_put(dev, e->pipe); 1010 - list_move_tail(&e->base.link, &e->base.file_priv->event_list); 1011 - wake_up_interruptible(&e->base.file_priv->event_wait); 1012 - trace_drm_vblank_event_delivered(e->base.pid, e->pipe, 1013 - e->event.sequence); 960 + send_vblank_event(dev, e, seq, &now); 1014 961 } 1015 962 1016 963 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); ··· 1148 1107 1149 1108 e->event.sequence = vblwait->request.sequence; 1150 1109 if ((seq - vblwait->request.sequence) <= (1 << 23)) { 1151 - e->event.sequence = seq; 1152 - e->event.tv_sec = now.tv_sec; 1153 - e->event.tv_usec = now.tv_usec; 1154 1110 drm_vblank_put(dev, pipe); 1155 - list_add_tail(&e->base.link, &e->base.file_priv->event_list); 1156 - wake_up_interruptible(&e->base.file_priv->event_wait); 1111 + send_vblank_event(dev, e, seq, &now); 1157 1112 vblwait->reply.sequence = seq; 1158 - trace_drm_vblank_event_delivered(current->pid, pipe, 1159 - vblwait->request.sequence); 1160 1113 } else { 1161 1114 /* drm_handle_vblank_events will call drm_vblank_put */ 1162 1115 list_add_tail(&e->base.link, &dev->vblank_event_list); ··· 1291 1256 DRM_DEBUG("vblank event on %d, current %d\n", 1292 1257 e->event.sequence, seq); 1293 1258 1294 - e->event.sequence = seq; 1295 - e->event.tv_sec = now.tv_sec; 1296 - e->event.tv_usec = now.tv_usec; 1259 + list_del(&e->base.link); 1297 1260 drm_vblank_put(dev, e->pipe); 1298 - list_move_tail(&e->base.link, &e->base.file_priv->event_list); 1299 - wake_up_interruptible(&e->base.file_priv->event_wait); 1300 - trace_drm_vblank_event_delivered(e->base.pid, e->pipe, 1301 - e->event.sequence); 1261 + send_vblank_event(dev, e, seq, &now); 1302 1262 } 1303 1263 1304 1264 spin_unlock_irqrestore(&dev->event_lock, flags);
+2
include/drm/drmP.h
··· 1431 1431 extern u32 drm_vblank_count(struct drm_device *dev, int crtc); 1432 1432 extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, 1433 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 1436 extern bool drm_handle_vblank(struct drm_device *dev, int crtc); 1435 1437 extern int drm_vblank_get(struct drm_device *dev, int crtc); 1436 1438 extern void drm_vblank_put(struct drm_device *dev, int crtc);