diff options
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 463 |
1 files changed, 324 insertions, 139 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 08ba1209228e..5ef03c216a27 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -34,6 +34,7 @@ | |||
34 | 34 | ||
35 | #include <drm/drmP.h> | 35 | #include <drm/drmP.h> |
36 | #include "drm_trace.h" | 36 | #include "drm_trace.h" |
37 | #include "drm_internal.h" | ||
37 | 38 | ||
38 | #include <linux/interrupt.h> /* For task queue support */ | 39 | #include <linux/interrupt.h> /* For task queue support */ |
39 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
@@ -55,12 +56,91 @@ | |||
55 | */ | 56 | */ |
56 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 | 57 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 |
57 | 58 | ||
59 | static bool | ||
60 | drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | ||
61 | struct timeval *tvblank, unsigned flags); | ||
62 | |||
63 | static unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ | ||
64 | |||
58 | /* | 65 | /* |
59 | * Clear vblank timestamp buffer for a crtc. | 66 | * Default to use monotonic timestamps for wait-for-vblank and page-flip |
67 | * complete events. | ||
68 | */ | ||
69 | unsigned int drm_timestamp_monotonic = 1; | ||
70 | |||
71 | static int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ | ||
72 | |||
73 | module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); | ||
74 | module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); | ||
75 | module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); | ||
76 | |||
77 | /** | ||
78 | * drm_update_vblank_count - update the master vblank counter | ||
79 | * @dev: DRM device | ||
80 | * @crtc: counter to update | ||
81 | * | ||
82 | * Call back into the driver to update the appropriate vblank counter | ||
83 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
84 | * update the last read value so we can deal with wraparound on the next | ||
85 | * call if necessary. | ||
86 | * | ||
87 | * Only necessary when going from off->on, to account for frames we | ||
88 | * didn't get an interrupt for. | ||
89 | * | ||
90 | * Note: caller must hold dev->vbl_lock since this reads & writes | ||
91 | * device vblank fields. | ||
60 | */ | 92 | */ |
61 | static void clear_vblank_timestamps(struct drm_device *dev, int crtc) | 93 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) |
62 | { | 94 | { |
63 | memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time)); | 95 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
96 | u32 cur_vblank, diff, tslot; | ||
97 | bool rc; | ||
98 | struct timeval t_vblank; | ||
99 | |||
100 | /* | ||
101 | * Interrupts were disabled prior to this call, so deal with counter | ||
102 | * wrap if needed. | ||
103 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
104 | * here if the register is small or we had vblank interrupts off for | ||
105 | * a long time. | ||
106 | * | ||
107 | * We repeat the hardware vblank counter & timestamp query until | ||
108 | * we get consistent results. This to prevent races between gpu | ||
109 | * updating its hardware counter while we are retrieving the | ||
110 | * corresponding vblank timestamp. | ||
111 | */ | ||
112 | do { | ||
113 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
114 | rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); | ||
115 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); | ||
116 | |||
117 | /* Deal with counter wrap */ | ||
118 | diff = cur_vblank - vblank->last; | ||
119 | if (cur_vblank < vblank->last) { | ||
120 | diff += dev->max_vblank_count; | ||
121 | |||
122 | DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", | ||
123 | crtc, vblank->last, cur_vblank, diff); | ||
124 | } | ||
125 | |||
126 | DRM_DEBUG("updating vblank count on crtc %d, missed %d\n", | ||
127 | crtc, diff); | ||
128 | |||
129 | if (diff == 0) | ||
130 | return; | ||
131 | |||
132 | /* Reinitialize corresponding vblank timestamp if high-precision query | ||
133 | * available. Skip this step if query unsupported or failed. Will | ||
134 | * reinitialize delayed at next vblank interrupt in that case. | ||
135 | */ | ||
136 | if (rc) { | ||
137 | tslot = atomic_read(&vblank->count) + diff; | ||
138 | vblanktimestamp(dev, crtc, tslot) = t_vblank; | ||
139 | } | ||
140 | |||
141 | smp_mb__before_atomic(); | ||
142 | atomic_add(diff, &vblank->count); | ||
143 | smp_mb__after_atomic(); | ||
64 | } | 144 | } |
65 | 145 | ||
66 | /* | 146 | /* |
@@ -71,10 +151,11 @@ static void clear_vblank_timestamps(struct drm_device *dev, int crtc) | |||
71 | */ | 151 | */ |
72 | static void vblank_disable_and_save(struct drm_device *dev, int crtc) | 152 | static void vblank_disable_and_save(struct drm_device *dev, int crtc) |
73 | { | 153 | { |
154 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
74 | unsigned long irqflags; | 155 | unsigned long irqflags; |
75 | u32 vblcount; | 156 | u32 vblcount; |
76 | s64 diff_ns; | 157 | s64 diff_ns; |
77 | int vblrc; | 158 | bool vblrc; |
78 | struct timeval tvblank; | 159 | struct timeval tvblank; |
79 | int count = DRM_TIMESTAMP_MAXRETRIES; | 160 | int count = DRM_TIMESTAMP_MAXRETRIES; |
80 | 161 | ||
@@ -84,8 +165,28 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
84 | */ | 165 | */ |
85 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | 166 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); |
86 | 167 | ||
168 | /* | ||
169 | * If the vblank interrupt was already disbled update the count | ||
170 | * and timestamp to maintain the appearance that the counter | ||
171 | * has been ticking all along until this time. This makes the | ||
172 | * count account for the entire time between drm_vblank_on() and | ||
173 | * drm_vblank_off(). | ||
174 | * | ||
175 | * But only do this if precise vblank timestamps are available. | ||
176 | * Otherwise we might read a totally bogus timestamp since drivers | ||
177 | * lacking precise timestamp support rely upon sampling the system clock | ||
178 | * at vblank interrupt time. Which obviously won't work out well if the | ||
179 | * vblank interrupt is disabled. | ||
180 | */ | ||
181 | if (!vblank->enabled && | ||
182 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0)) { | ||
183 | drm_update_vblank_count(dev, crtc); | ||
184 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | ||
185 | return; | ||
186 | } | ||
187 | |||
87 | dev->driver->disable_vblank(dev, crtc); | 188 | dev->driver->disable_vblank(dev, crtc); |
88 | dev->vblank[crtc].enabled = false; | 189 | vblank->enabled = false; |
89 | 190 | ||
90 | /* No further vblank irq's will be processed after | 191 | /* No further vblank irq's will be processed after |
91 | * this point. Get current hardware vblank count and | 192 | * this point. Get current hardware vblank count and |
@@ -100,9 +201,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
100 | * delayed gpu counter increment. | 201 | * delayed gpu counter increment. |
101 | */ | 202 | */ |
102 | do { | 203 | do { |
103 | dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc); | 204 | vblank->last = dev->driver->get_vblank_counter(dev, crtc); |
104 | vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); | 205 | vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); |
105 | } while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); | 206 | } while (vblank->last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); |
106 | 207 | ||
107 | if (!count) | 208 | if (!count) |
108 | vblrc = 0; | 209 | vblrc = 0; |
@@ -110,7 +211,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
110 | /* Compute time difference to stored timestamp of last vblank | 211 | /* Compute time difference to stored timestamp of last vblank |
111 | * as updated by last invocation of drm_handle_vblank() in vblank irq. | 212 | * as updated by last invocation of drm_handle_vblank() in vblank irq. |
112 | */ | 213 | */ |
113 | vblcount = atomic_read(&dev->vblank[crtc].count); | 214 | vblcount = atomic_read(&vblank->count); |
114 | diff_ns = timeval_to_ns(&tvblank) - | 215 | diff_ns = timeval_to_ns(&tvblank) - |
115 | timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); | 216 | timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); |
116 | 217 | ||
@@ -126,14 +227,18 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
126 | * available. In that case we can't account for this and just | 227 | * available. In that case we can't account for this and just |
127 | * hope for the best. | 228 | * hope for the best. |
128 | */ | 229 | */ |
129 | if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { | 230 | if (vblrc && (abs64(diff_ns) > 1000000)) { |
130 | atomic_inc(&dev->vblank[crtc].count); | 231 | /* Store new timestamp in ringbuffer. */ |
232 | vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; | ||
233 | |||
234 | /* Increment cooked vblank count. This also atomically commits | ||
235 | * the timestamp computed above. | ||
236 | */ | ||
237 | smp_mb__before_atomic(); | ||
238 | atomic_inc(&vblank->count); | ||
131 | smp_mb__after_atomic(); | 239 | smp_mb__after_atomic(); |
132 | } | 240 | } |
133 | 241 | ||
134 | /* Invalidate all timestamps while vblank irq's are off. */ | ||
135 | clear_vblank_timestamps(dev, crtc); | ||
136 | |||
137 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 242 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); |
138 | } | 243 | } |
139 | 244 | ||
@@ -164,14 +269,20 @@ static void vblank_disable_fn(unsigned long arg) | |||
164 | void drm_vblank_cleanup(struct drm_device *dev) | 269 | void drm_vblank_cleanup(struct drm_device *dev) |
165 | { | 270 | { |
166 | int crtc; | 271 | int crtc; |
272 | unsigned long irqflags; | ||
167 | 273 | ||
168 | /* Bail if the driver didn't call drm_vblank_init() */ | 274 | /* Bail if the driver didn't call drm_vblank_init() */ |
169 | if (dev->num_crtcs == 0) | 275 | if (dev->num_crtcs == 0) |
170 | return; | 276 | return; |
171 | 277 | ||
172 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { | 278 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { |
173 | del_timer_sync(&dev->vblank[crtc].disable_timer); | 279 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
174 | vblank_disable_fn((unsigned long)&dev->vblank[crtc]); | 280 | |
281 | del_timer_sync(&vblank->disable_timer); | ||
282 | |||
283 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
284 | vblank_disable_and_save(dev, crtc); | ||
285 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
175 | } | 286 | } |
176 | 287 | ||
177 | kfree(dev->vblank); | 288 | kfree(dev->vblank); |
@@ -204,11 +315,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
204 | goto err; | 315 | goto err; |
205 | 316 | ||
206 | for (i = 0; i < num_crtcs; i++) { | 317 | for (i = 0; i < num_crtcs; i++) { |
207 | dev->vblank[i].dev = dev; | 318 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
208 | dev->vblank[i].crtc = i; | 319 | |
209 | init_waitqueue_head(&dev->vblank[i].queue); | 320 | vblank->dev = dev; |
210 | setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn, | 321 | vblank->crtc = i; |
211 | (unsigned long)&dev->vblank[i]); | 322 | init_waitqueue_head(&vblank->queue); |
323 | setup_timer(&vblank->disable_timer, vblank_disable_fn, | ||
324 | (unsigned long)vblank); | ||
212 | } | 325 | } |
213 | 326 | ||
214 | DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); | 327 | DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); |
@@ -224,7 +337,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
224 | return 0; | 337 | return 0; |
225 | 338 | ||
226 | err: | 339 | err: |
227 | drm_vblank_cleanup(dev); | 340 | dev->num_crtcs = 0; |
228 | return ret; | 341 | return ret; |
229 | } | 342 | } |
230 | EXPORT_SYMBOL(drm_vblank_init); | 343 | EXPORT_SYMBOL(drm_vblank_init); |
@@ -360,9 +473,11 @@ int drm_irq_uninstall(struct drm_device *dev) | |||
360 | if (dev->num_crtcs) { | 473 | if (dev->num_crtcs) { |
361 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 474 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
362 | for (i = 0; i < dev->num_crtcs; i++) { | 475 | for (i = 0; i < dev->num_crtcs; i++) { |
363 | wake_up(&dev->vblank[i].queue); | 476 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
364 | dev->vblank[i].enabled = false; | 477 | |
365 | dev->vblank[i].last = | 478 | wake_up(&vblank->queue); |
479 | vblank->enabled = false; | ||
480 | vblank->last = | ||
366 | dev->driver->get_vblank_counter(dev, i); | 481 | dev->driver->get_vblank_counter(dev, i); |
367 | } | 482 | } |
368 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 483 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
@@ -617,7 +732,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
617 | * within vblank area, counting down the number of lines until | 732 | * within vblank area, counting down the number of lines until |
618 | * start of scanout. | 733 | * start of scanout. |
619 | */ | 734 | */ |
620 | invbl = vbl_status & DRM_SCANOUTPOS_INVBL; | 735 | invbl = vbl_status & DRM_SCANOUTPOS_IN_VBLANK; |
621 | 736 | ||
622 | /* Convert scanout position into elapsed time at raw_time query | 737 | /* Convert scanout position into elapsed time at raw_time query |
623 | * since start of scanout at first display scanline. delta_ns | 738 | * since start of scanout at first display scanline. delta_ns |
@@ -647,7 +762,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
647 | 762 | ||
648 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | 763 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; |
649 | if (invbl) | 764 | if (invbl) |
650 | vbl_status |= DRM_VBLANKTIME_INVBL; | 765 | vbl_status |= DRM_VBLANKTIME_IN_VBLANK; |
651 | 766 | ||
652 | return vbl_status; | 767 | return vbl_status; |
653 | } | 768 | } |
@@ -679,10 +794,11 @@ static struct timeval get_drm_timestamp(void) | |||
679 | * call, i.e., it isn't very precisely locked to the true vblank. | 794 | * call, i.e., it isn't very precisely locked to the true vblank. |
680 | * | 795 | * |
681 | * Returns: | 796 | * Returns: |
682 | * Non-zero if timestamp is considered to be very precise, zero otherwise. | 797 | * True if timestamp is considered to be very precise, false otherwise. |
683 | */ | 798 | */ |
684 | u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | 799 | static bool |
685 | struct timeval *tvblank, unsigned flags) | 800 | drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, |
801 | struct timeval *tvblank, unsigned flags) | ||
686 | { | 802 | { |
687 | int ret; | 803 | int ret; |
688 | 804 | ||
@@ -694,7 +810,7 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | |||
694 | ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, | 810 | ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, |
695 | tvblank, flags); | 811 | tvblank, flags); |
696 | if (ret > 0) | 812 | if (ret > 0) |
697 | return (u32) ret; | 813 | return true; |
698 | } | 814 | } |
699 | 815 | ||
700 | /* GPU high precision timestamp query unsupported or failed. | 816 | /* GPU high precision timestamp query unsupported or failed. |
@@ -702,9 +818,8 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | |||
702 | */ | 818 | */ |
703 | *tvblank = get_drm_timestamp(); | 819 | *tvblank = get_drm_timestamp(); |
704 | 820 | ||
705 | return 0; | 821 | return false; |
706 | } | 822 | } |
707 | EXPORT_SYMBOL(drm_get_last_vbltimestamp); | ||
708 | 823 | ||
709 | /** | 824 | /** |
710 | * drm_vblank_count - retrieve "cooked" vblank counter value | 825 | * drm_vblank_count - retrieve "cooked" vblank counter value |
@@ -720,7 +835,11 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp); | |||
720 | */ | 835 | */ |
721 | u32 drm_vblank_count(struct drm_device *dev, int crtc) | 836 | u32 drm_vblank_count(struct drm_device *dev, int crtc) |
722 | { | 837 | { |
723 | return atomic_read(&dev->vblank[crtc].count); | 838 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
839 | |||
840 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
841 | return 0; | ||
842 | return atomic_read(&vblank->count); | ||
724 | } | 843 | } |
725 | EXPORT_SYMBOL(drm_vblank_count); | 844 | EXPORT_SYMBOL(drm_vblank_count); |
726 | 845 | ||
@@ -740,18 +859,22 @@ EXPORT_SYMBOL(drm_vblank_count); | |||
740 | u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | 859 | u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, |
741 | struct timeval *vblanktime) | 860 | struct timeval *vblanktime) |
742 | { | 861 | { |
862 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
743 | u32 cur_vblank; | 863 | u32 cur_vblank; |
744 | 864 | ||
865 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
866 | return 0; | ||
867 | |||
745 | /* Read timestamp from slot of _vblank_time ringbuffer | 868 | /* Read timestamp from slot of _vblank_time ringbuffer |
746 | * that corresponds to current vblank count. Retry if | 869 | * that corresponds to current vblank count. Retry if |
747 | * count has incremented during readout. This works like | 870 | * count has incremented during readout. This works like |
748 | * a seqlock. | 871 | * a seqlock. |
749 | */ | 872 | */ |
750 | do { | 873 | do { |
751 | cur_vblank = atomic_read(&dev->vblank[crtc].count); | 874 | cur_vblank = atomic_read(&vblank->count); |
752 | *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); | 875 | *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); |
753 | smp_rmb(); | 876 | smp_rmb(); |
754 | } while (cur_vblank != atomic_read(&dev->vblank[crtc].count)); | 877 | } while (cur_vblank != atomic_read(&vblank->count)); |
755 | 878 | ||
756 | return cur_vblank; | 879 | return cur_vblank; |
757 | } | 880 | } |
@@ -800,83 +923,20 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, | |||
800 | EXPORT_SYMBOL(drm_send_vblank_event); | 923 | EXPORT_SYMBOL(drm_send_vblank_event); |
801 | 924 | ||
802 | /** | 925 | /** |
803 | * drm_update_vblank_count - update the master vblank counter | ||
804 | * @dev: DRM device | ||
805 | * @crtc: counter to update | ||
806 | * | ||
807 | * Call back into the driver to update the appropriate vblank counter | ||
808 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
809 | * update the last read value so we can deal with wraparound on the next | ||
810 | * call if necessary. | ||
811 | * | ||
812 | * Only necessary when going from off->on, to account for frames we | ||
813 | * didn't get an interrupt for. | ||
814 | * | ||
815 | * Note: caller must hold dev->vbl_lock since this reads & writes | ||
816 | * device vblank fields. | ||
817 | */ | ||
818 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) | ||
819 | { | ||
820 | u32 cur_vblank, diff, tslot, rc; | ||
821 | struct timeval t_vblank; | ||
822 | |||
823 | /* | ||
824 | * Interrupts were disabled prior to this call, so deal with counter | ||
825 | * wrap if needed. | ||
826 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
827 | * here if the register is small or we had vblank interrupts off for | ||
828 | * a long time. | ||
829 | * | ||
830 | * We repeat the hardware vblank counter & timestamp query until | ||
831 | * we get consistent results. This to prevent races between gpu | ||
832 | * updating its hardware counter while we are retrieving the | ||
833 | * corresponding vblank timestamp. | ||
834 | */ | ||
835 | do { | ||
836 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
837 | rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); | ||
838 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); | ||
839 | |||
840 | /* Deal with counter wrap */ | ||
841 | diff = cur_vblank - dev->vblank[crtc].last; | ||
842 | if (cur_vblank < dev->vblank[crtc].last) { | ||
843 | diff += dev->max_vblank_count; | ||
844 | |||
845 | DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", | ||
846 | crtc, dev->vblank[crtc].last, cur_vblank, diff); | ||
847 | } | ||
848 | |||
849 | DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", | ||
850 | crtc, diff); | ||
851 | |||
852 | /* Reinitialize corresponding vblank timestamp if high-precision query | ||
853 | * available. Skip this step if query unsupported or failed. Will | ||
854 | * reinitialize delayed at next vblank interrupt in that case. | ||
855 | */ | ||
856 | if (rc) { | ||
857 | tslot = atomic_read(&dev->vblank[crtc].count) + diff; | ||
858 | vblanktimestamp(dev, crtc, tslot) = t_vblank; | ||
859 | } | ||
860 | |||
861 | smp_mb__before_atomic(); | ||
862 | atomic_add(diff, &dev->vblank[crtc].count); | ||
863 | smp_mb__after_atomic(); | ||
864 | } | ||
865 | |||
866 | /** | ||
867 | * drm_vblank_enable - enable the vblank interrupt on a CRTC | 926 | * drm_vblank_enable - enable the vblank interrupt on a CRTC |
868 | * @dev: DRM device | 927 | * @dev: DRM device |
869 | * @crtc: CRTC in question | 928 | * @crtc: CRTC in question |
870 | */ | 929 | */ |
871 | static int drm_vblank_enable(struct drm_device *dev, int crtc) | 930 | static int drm_vblank_enable(struct drm_device *dev, int crtc) |
872 | { | 931 | { |
932 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
873 | int ret = 0; | 933 | int ret = 0; |
874 | 934 | ||
875 | assert_spin_locked(&dev->vbl_lock); | 935 | assert_spin_locked(&dev->vbl_lock); |
876 | 936 | ||
877 | spin_lock(&dev->vblank_time_lock); | 937 | spin_lock(&dev->vblank_time_lock); |
878 | 938 | ||
879 | if (!dev->vblank[crtc].enabled) { | 939 | if (!vblank->enabled) { |
880 | /* | 940 | /* |
881 | * Enable vblank irqs under vblank_time_lock protection. | 941 | * Enable vblank irqs under vblank_time_lock protection. |
882 | * All vblank count & timestamp updates are held off | 942 | * All vblank count & timestamp updates are held off |
@@ -887,9 +947,9 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) | |||
887 | ret = dev->driver->enable_vblank(dev, crtc); | 947 | ret = dev->driver->enable_vblank(dev, crtc); |
888 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); | 948 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); |
889 | if (ret) | 949 | if (ret) |
890 | atomic_dec(&dev->vblank[crtc].refcount); | 950 | atomic_dec(&vblank->refcount); |
891 | else { | 951 | else { |
892 | dev->vblank[crtc].enabled = true; | 952 | vblank->enabled = true; |
893 | drm_update_vblank_count(dev, crtc); | 953 | drm_update_vblank_count(dev, crtc); |
894 | } | 954 | } |
895 | } | 955 | } |
@@ -914,16 +974,20 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) | |||
914 | */ | 974 | */ |
915 | int drm_vblank_get(struct drm_device *dev, int crtc) | 975 | int drm_vblank_get(struct drm_device *dev, int crtc) |
916 | { | 976 | { |
977 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
917 | unsigned long irqflags; | 978 | unsigned long irqflags; |
918 | int ret = 0; | 979 | int ret = 0; |
919 | 980 | ||
981 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
982 | return -EINVAL; | ||
983 | |||
920 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 984 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
921 | /* Going from 0->1 means we have to enable interrupts again */ | 985 | /* Going from 0->1 means we have to enable interrupts again */ |
922 | if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { | 986 | if (atomic_add_return(1, &vblank->refcount) == 1) { |
923 | ret = drm_vblank_enable(dev, crtc); | 987 | ret = drm_vblank_enable(dev, crtc); |
924 | } else { | 988 | } else { |
925 | if (!dev->vblank[crtc].enabled) { | 989 | if (!vblank->enabled) { |
926 | atomic_dec(&dev->vblank[crtc].refcount); | 990 | atomic_dec(&vblank->refcount); |
927 | ret = -EINVAL; | 991 | ret = -EINVAL; |
928 | } | 992 | } |
929 | } | 993 | } |
@@ -963,13 +1027,23 @@ EXPORT_SYMBOL(drm_crtc_vblank_get); | |||
963 | */ | 1027 | */ |
964 | void drm_vblank_put(struct drm_device *dev, int crtc) | 1028 | void drm_vblank_put(struct drm_device *dev, int crtc) |
965 | { | 1029 | { |
966 | BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); | 1030 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
1031 | |||
1032 | BUG_ON(atomic_read(&vblank->refcount) == 0); | ||
1033 | |||
1034 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1035 | return; | ||
967 | 1036 | ||
968 | /* Last user schedules interrupt disable */ | 1037 | /* Last user schedules interrupt disable */ |
969 | if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && | 1038 | if (atomic_dec_and_test(&vblank->refcount)) { |
970 | (drm_vblank_offdelay > 0)) | 1039 | if (drm_vblank_offdelay == 0) |
971 | mod_timer(&dev->vblank[crtc].disable_timer, | 1040 | return; |
972 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); | 1041 | else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) |
1042 | vblank_disable_fn((unsigned long)vblank); | ||
1043 | else | ||
1044 | mod_timer(&vblank->disable_timer, | ||
1045 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); | ||
1046 | } | ||
973 | } | 1047 | } |
974 | EXPORT_SYMBOL(drm_vblank_put); | 1048 | EXPORT_SYMBOL(drm_vblank_put); |
975 | 1049 | ||
@@ -989,6 +1063,50 @@ void drm_crtc_vblank_put(struct drm_crtc *crtc) | |||
989 | EXPORT_SYMBOL(drm_crtc_vblank_put); | 1063 | EXPORT_SYMBOL(drm_crtc_vblank_put); |
990 | 1064 | ||
991 | /** | 1065 | /** |
1066 | * drm_wait_one_vblank - wait for one vblank | ||
1067 | * @dev: DRM device | ||
1068 | * @crtc: crtc index | ||
1069 | * | ||
1070 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. | ||
1071 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. | ||
1072 | * due to lack of driver support or because the crtc is off. | ||
1073 | */ | ||
1074 | void drm_wait_one_vblank(struct drm_device *dev, int crtc) | ||
1075 | { | ||
1076 | int ret; | ||
1077 | u32 last; | ||
1078 | |||
1079 | ret = drm_vblank_get(dev, crtc); | ||
1080 | if (WARN(ret, "vblank not available on crtc %i, ret=%i\n", crtc, ret)) | ||
1081 | return; | ||
1082 | |||
1083 | last = drm_vblank_count(dev, crtc); | ||
1084 | |||
1085 | ret = wait_event_timeout(dev->vblank[crtc].queue, | ||
1086 | last != drm_vblank_count(dev, crtc), | ||
1087 | msecs_to_jiffies(100)); | ||
1088 | |||
1089 | WARN(ret == 0, "vblank wait timed out on crtc %i\n", crtc); | ||
1090 | |||
1091 | drm_vblank_put(dev, crtc); | ||
1092 | } | ||
1093 | EXPORT_SYMBOL(drm_wait_one_vblank); | ||
1094 | |||
1095 | /** | ||
1096 | * drm_crtc_wait_one_vblank - wait for one vblank | ||
1097 | * @crtc: DRM crtc | ||
1098 | * | ||
1099 | * This waits for one vblank to pass on @crtc, using the irq driver interfaces. | ||
1100 | * It is a failure to call this when the vblank irq for @crtc is disabled, e.g. | ||
1101 | * due to lack of driver support or because the crtc is off. | ||
1102 | */ | ||
1103 | void drm_crtc_wait_one_vblank(struct drm_crtc *crtc) | ||
1104 | { | ||
1105 | drm_wait_one_vblank(crtc->dev, drm_crtc_index(crtc)); | ||
1106 | } | ||
1107 | EXPORT_SYMBOL(drm_crtc_wait_one_vblank); | ||
1108 | |||
1109 | /** | ||
992 | * drm_vblank_off - disable vblank events on a CRTC | 1110 | * drm_vblank_off - disable vblank events on a CRTC |
993 | * @dev: DRM device | 1111 | * @dev: DRM device |
994 | * @crtc: CRTC in question | 1112 | * @crtc: CRTC in question |
@@ -1004,19 +1122,34 @@ EXPORT_SYMBOL(drm_crtc_vblank_put); | |||
1004 | */ | 1122 | */ |
1005 | void drm_vblank_off(struct drm_device *dev, int crtc) | 1123 | void drm_vblank_off(struct drm_device *dev, int crtc) |
1006 | { | 1124 | { |
1125 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1007 | struct drm_pending_vblank_event *e, *t; | 1126 | struct drm_pending_vblank_event *e, *t; |
1008 | struct timeval now; | 1127 | struct timeval now; |
1009 | unsigned long irqflags; | 1128 | unsigned long irqflags; |
1010 | unsigned int seq; | 1129 | unsigned int seq; |
1011 | 1130 | ||
1012 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1131 | if (WARN_ON(crtc >= dev->num_crtcs)) |
1132 | return; | ||
1133 | |||
1134 | spin_lock_irqsave(&dev->event_lock, irqflags); | ||
1135 | |||
1136 | spin_lock(&dev->vbl_lock); | ||
1013 | vblank_disable_and_save(dev, crtc); | 1137 | vblank_disable_and_save(dev, crtc); |
1014 | wake_up(&dev->vblank[crtc].queue); | 1138 | wake_up(&vblank->queue); |
1139 | |||
1140 | /* | ||
1141 | * Prevent subsequent drm_vblank_get() from re-enabling | ||
1142 | * the vblank interrupt by bumping the refcount. | ||
1143 | */ | ||
1144 | if (!vblank->inmodeset) { | ||
1145 | atomic_inc(&vblank->refcount); | ||
1146 | vblank->inmodeset = 1; | ||
1147 | } | ||
1148 | spin_unlock(&dev->vbl_lock); | ||
1015 | 1149 | ||
1016 | /* Send any queued vblank events, lest the natives grow disquiet */ | 1150 | /* Send any queued vblank events, lest the natives grow disquiet */ |
1017 | seq = drm_vblank_count_and_time(dev, crtc, &now); | 1151 | seq = drm_vblank_count_and_time(dev, crtc, &now); |
1018 | 1152 | ||
1019 | spin_lock(&dev->event_lock); | ||
1020 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { | 1153 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { |
1021 | if (e->pipe != crtc) | 1154 | if (e->pipe != crtc) |
1022 | continue; | 1155 | continue; |
@@ -1027,9 +1160,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc) | |||
1027 | drm_vblank_put(dev, e->pipe); | 1160 | drm_vblank_put(dev, e->pipe); |
1028 | send_vblank_event(dev, e, seq, &now); | 1161 | send_vblank_event(dev, e, seq, &now); |
1029 | } | 1162 | } |
1030 | spin_unlock(&dev->event_lock); | 1163 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
1031 | |||
1032 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
1033 | } | 1164 | } |
1034 | EXPORT_SYMBOL(drm_vblank_off); | 1165 | EXPORT_SYMBOL(drm_vblank_off); |
1035 | 1166 | ||
@@ -1066,11 +1197,35 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); | |||
1066 | */ | 1197 | */ |
1067 | void drm_vblank_on(struct drm_device *dev, int crtc) | 1198 | void drm_vblank_on(struct drm_device *dev, int crtc) |
1068 | { | 1199 | { |
1200 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1069 | unsigned long irqflags; | 1201 | unsigned long irqflags; |
1070 | 1202 | ||
1203 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1204 | return; | ||
1205 | |||
1071 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1206 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
1072 | /* re-enable interrupts if there's are users left */ | 1207 | /* Drop our private "prevent drm_vblank_get" refcount */ |
1073 | if (atomic_read(&dev->vblank[crtc].refcount) != 0) | 1208 | if (vblank->inmodeset) { |
1209 | atomic_dec(&vblank->refcount); | ||
1210 | vblank->inmodeset = 0; | ||
1211 | } | ||
1212 | |||
1213 | /* | ||
1214 | * sample the current counter to avoid random jumps | ||
1215 | * when drm_vblank_enable() applies the diff | ||
1216 | * | ||
1217 | * -1 to make sure user will never see the same | ||
1218 | * vblank counter value before and after a modeset | ||
1219 | */ | ||
1220 | vblank->last = | ||
1221 | (dev->driver->get_vblank_counter(dev, crtc) - 1) & | ||
1222 | dev->max_vblank_count; | ||
1223 | /* | ||
1224 | * re-enable interrupts if there are users left, or the | ||
1225 | * user wishes vblank interrupts to be enabled all the time. | ||
1226 | */ | ||
1227 | if (atomic_read(&vblank->refcount) != 0 || | ||
1228 | (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0)) | ||
1074 | WARN_ON(drm_vblank_enable(dev, crtc)); | 1229 | WARN_ON(drm_vblank_enable(dev, crtc)); |
1075 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 1230 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
1076 | } | 1231 | } |
@@ -1118,9 +1273,15 @@ EXPORT_SYMBOL(drm_crtc_vblank_on); | |||
1118 | */ | 1273 | */ |
1119 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | 1274 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) |
1120 | { | 1275 | { |
1276 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1277 | |||
1121 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ | 1278 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1122 | if (!dev->num_crtcs) | 1279 | if (!dev->num_crtcs) |
1123 | return; | 1280 | return; |
1281 | |||
1282 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1283 | return; | ||
1284 | |||
1124 | /* | 1285 | /* |
1125 | * To avoid all the problems that might happen if interrupts | 1286 | * To avoid all the problems that might happen if interrupts |
1126 | * were enabled/disabled around or between these calls, we just | 1287 | * were enabled/disabled around or between these calls, we just |
@@ -1128,10 +1289,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | |||
1128 | * to avoid corrupting the count if multiple, mismatch calls occur), | 1289 | * to avoid corrupting the count if multiple, mismatch calls occur), |
1129 | * so that interrupts remain enabled in the interim. | 1290 | * so that interrupts remain enabled in the interim. |
1130 | */ | 1291 | */ |
1131 | if (!dev->vblank[crtc].inmodeset) { | 1292 | if (!vblank->inmodeset) { |
1132 | dev->vblank[crtc].inmodeset = 0x1; | 1293 | vblank->inmodeset = 0x1; |
1133 | if (drm_vblank_get(dev, crtc) == 0) | 1294 | if (drm_vblank_get(dev, crtc) == 0) |
1134 | dev->vblank[crtc].inmodeset |= 0x2; | 1295 | vblank->inmodeset |= 0x2; |
1135 | } | 1296 | } |
1136 | } | 1297 | } |
1137 | EXPORT_SYMBOL(drm_vblank_pre_modeset); | 1298 | EXPORT_SYMBOL(drm_vblank_pre_modeset); |
@@ -1146,21 +1307,22 @@ EXPORT_SYMBOL(drm_vblank_pre_modeset); | |||
1146 | */ | 1307 | */ |
1147 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) | 1308 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) |
1148 | { | 1309 | { |
1310 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1149 | unsigned long irqflags; | 1311 | unsigned long irqflags; |
1150 | 1312 | ||
1151 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ | 1313 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1152 | if (!dev->num_crtcs) | 1314 | if (!dev->num_crtcs) |
1153 | return; | 1315 | return; |
1154 | 1316 | ||
1155 | if (dev->vblank[crtc].inmodeset) { | 1317 | if (vblank->inmodeset) { |
1156 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1318 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
1157 | dev->vblank_disable_allowed = true; | 1319 | dev->vblank_disable_allowed = true; |
1158 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 1320 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
1159 | 1321 | ||
1160 | if (dev->vblank[crtc].inmodeset & 0x2) | 1322 | if (vblank->inmodeset & 0x2) |
1161 | drm_vblank_put(dev, crtc); | 1323 | drm_vblank_put(dev, crtc); |
1162 | 1324 | ||
1163 | dev->vblank[crtc].inmodeset = 0; | 1325 | vblank->inmodeset = 0; |
1164 | } | 1326 | } |
1165 | } | 1327 | } |
1166 | EXPORT_SYMBOL(drm_vblank_post_modeset); | 1328 | EXPORT_SYMBOL(drm_vblank_post_modeset); |
@@ -1212,6 +1374,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
1212 | union drm_wait_vblank *vblwait, | 1374 | union drm_wait_vblank *vblwait, |
1213 | struct drm_file *file_priv) | 1375 | struct drm_file *file_priv) |
1214 | { | 1376 | { |
1377 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
1215 | struct drm_pending_vblank_event *e; | 1378 | struct drm_pending_vblank_event *e; |
1216 | struct timeval now; | 1379 | struct timeval now; |
1217 | unsigned long flags; | 1380 | unsigned long flags; |
@@ -1235,6 +1398,18 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
1235 | 1398 | ||
1236 | spin_lock_irqsave(&dev->event_lock, flags); | 1399 | spin_lock_irqsave(&dev->event_lock, flags); |
1237 | 1400 | ||
1401 | /* | ||
1402 | * drm_vblank_off() might have been called after we called | ||
1403 | * drm_vblank_get(). drm_vblank_off() holds event_lock | ||
1404 | * around the vblank disable, so no need for further locking. | ||
1405 | * The reference from drm_vblank_get() protects against | ||
1406 | * vblank disable from another source. | ||
1407 | */ | ||
1408 | if (!vblank->enabled) { | ||
1409 | ret = -EINVAL; | ||
1410 | goto err_unlock; | ||
1411 | } | ||
1412 | |||
1238 | if (file_priv->event_space < sizeof e->event) { | 1413 | if (file_priv->event_space < sizeof e->event) { |
1239 | ret = -EBUSY; | 1414 | ret = -EBUSY; |
1240 | goto err_unlock; | 1415 | goto err_unlock; |
@@ -1295,6 +1470,7 @@ err_put: | |||
1295 | int drm_wait_vblank(struct drm_device *dev, void *data, | 1470 | int drm_wait_vblank(struct drm_device *dev, void *data, |
1296 | struct drm_file *file_priv) | 1471 | struct drm_file *file_priv) |
1297 | { | 1472 | { |
1473 | struct drm_vblank_crtc *vblank; | ||
1298 | union drm_wait_vblank *vblwait = data; | 1474 | union drm_wait_vblank *vblwait = data; |
1299 | int ret; | 1475 | int ret; |
1300 | unsigned int flags, seq, crtc, high_crtc; | 1476 | unsigned int flags, seq, crtc, high_crtc; |
@@ -1324,6 +1500,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1324 | if (crtc >= dev->num_crtcs) | 1500 | if (crtc >= dev->num_crtcs) |
1325 | return -EINVAL; | 1501 | return -EINVAL; |
1326 | 1502 | ||
1503 | vblank = &dev->vblank[crtc]; | ||
1504 | |||
1327 | ret = drm_vblank_get(dev, crtc); | 1505 | ret = drm_vblank_get(dev, crtc); |
1328 | if (ret) { | 1506 | if (ret) { |
1329 | DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); | 1507 | DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); |
@@ -1356,11 +1534,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1356 | 1534 | ||
1357 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", | 1535 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", |
1358 | vblwait->request.sequence, crtc); | 1536 | vblwait->request.sequence, crtc); |
1359 | dev->vblank[crtc].last_wait = vblwait->request.sequence; | 1537 | vblank->last_wait = vblwait->request.sequence; |
1360 | DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ, | 1538 | DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, |
1361 | (((drm_vblank_count(dev, crtc) - | 1539 | (((drm_vblank_count(dev, crtc) - |
1362 | vblwait->request.sequence) <= (1 << 23)) || | 1540 | vblwait->request.sequence) <= (1 << 23)) || |
1363 | !dev->vblank[crtc].enabled || | 1541 | !vblank->enabled || |
1364 | !dev->irq_enabled)); | 1542 | !dev->irq_enabled)); |
1365 | 1543 | ||
1366 | if (ret != -EINTR) { | 1544 | if (ret != -EINTR) { |
@@ -1385,12 +1563,11 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
1385 | { | 1563 | { |
1386 | struct drm_pending_vblank_event *e, *t; | 1564 | struct drm_pending_vblank_event *e, *t; |
1387 | struct timeval now; | 1565 | struct timeval now; |
1388 | unsigned long flags; | ||
1389 | unsigned int seq; | 1566 | unsigned int seq; |
1390 | 1567 | ||
1391 | seq = drm_vblank_count_and_time(dev, crtc, &now); | 1568 | assert_spin_locked(&dev->event_lock); |
1392 | 1569 | ||
1393 | spin_lock_irqsave(&dev->event_lock, flags); | 1570 | seq = drm_vblank_count_and_time(dev, crtc, &now); |
1394 | 1571 | ||
1395 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { | 1572 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { |
1396 | if (e->pipe != crtc) | 1573 | if (e->pipe != crtc) |
@@ -1406,8 +1583,6 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
1406 | send_vblank_event(dev, e, seq, &now); | 1583 | send_vblank_event(dev, e, seq, &now); |
1407 | } | 1584 | } |
1408 | 1585 | ||
1409 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
1410 | |||
1411 | trace_drm_vblank_event(crtc, seq); | 1586 | trace_drm_vblank_event(crtc, seq); |
1412 | } | 1587 | } |
1413 | 1588 | ||
@@ -1421,6 +1596,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
1421 | */ | 1596 | */ |
1422 | bool drm_handle_vblank(struct drm_device *dev, int crtc) | 1597 | bool drm_handle_vblank(struct drm_device *dev, int crtc) |
1423 | { | 1598 | { |
1599 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1424 | u32 vblcount; | 1600 | u32 vblcount; |
1425 | s64 diff_ns; | 1601 | s64 diff_ns; |
1426 | struct timeval tvblank; | 1602 | struct timeval tvblank; |
@@ -1429,15 +1605,21 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1429 | if (!dev->num_crtcs) | 1605 | if (!dev->num_crtcs) |
1430 | return false; | 1606 | return false; |
1431 | 1607 | ||
1608 | if (WARN_ON(crtc >= dev->num_crtcs)) | ||
1609 | return false; | ||
1610 | |||
1611 | spin_lock_irqsave(&dev->event_lock, irqflags); | ||
1612 | |||
1432 | /* Need timestamp lock to prevent concurrent execution with | 1613 | /* Need timestamp lock to prevent concurrent execution with |
1433 | * vblank enable/disable, as this would cause inconsistent | 1614 | * vblank enable/disable, as this would cause inconsistent |
1434 | * or corrupted timestamps and vblank counts. | 1615 | * or corrupted timestamps and vblank counts. |
1435 | */ | 1616 | */ |
1436 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | 1617 | spin_lock(&dev->vblank_time_lock); |
1437 | 1618 | ||
1438 | /* Vblank irq handling disabled. Nothing to do. */ | 1619 | /* Vblank irq handling disabled. Nothing to do. */ |
1439 | if (!dev->vblank[crtc].enabled) { | 1620 | if (!vblank->enabled) { |
1440 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 1621 | spin_unlock(&dev->vblank_time_lock); |
1622 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | ||
1441 | return false; | 1623 | return false; |
1442 | } | 1624 | } |
1443 | 1625 | ||
@@ -1446,7 +1628,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1446 | */ | 1628 | */ |
1447 | 1629 | ||
1448 | /* Get current timestamp and count. */ | 1630 | /* Get current timestamp and count. */ |
1449 | vblcount = atomic_read(&dev->vblank[crtc].count); | 1631 | vblcount = atomic_read(&vblank->count); |
1450 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); | 1632 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); |
1451 | 1633 | ||
1452 | /* Compute time difference to timestamp of last vblank */ | 1634 | /* Compute time difference to timestamp of last vblank */ |
@@ -1470,17 +1652,20 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1470 | * the timestamp computed above. | 1652 | * the timestamp computed above. |
1471 | */ | 1653 | */ |
1472 | smp_mb__before_atomic(); | 1654 | smp_mb__before_atomic(); |
1473 | atomic_inc(&dev->vblank[crtc].count); | 1655 | atomic_inc(&vblank->count); |
1474 | smp_mb__after_atomic(); | 1656 | smp_mb__after_atomic(); |
1475 | } else { | 1657 | } else { |
1476 | DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", | 1658 | DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", |
1477 | crtc, (int) diff_ns); | 1659 | crtc, (int) diff_ns); |
1478 | } | 1660 | } |
1479 | 1661 | ||
1480 | wake_up(&dev->vblank[crtc].queue); | 1662 | spin_unlock(&dev->vblank_time_lock); |
1663 | |||
1664 | wake_up(&vblank->queue); | ||
1481 | drm_handle_vblank_events(dev, crtc); | 1665 | drm_handle_vblank_events(dev, crtc); |
1482 | 1666 | ||
1483 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 1667 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
1668 | |||
1484 | return true; | 1669 | return true; |
1485 | } | 1670 | } |
1486 | EXPORT_SYMBOL(drm_handle_vblank); | 1671 | EXPORT_SYMBOL(drm_handle_vblank); |