diff options
-rw-r--r-- | Documentation/DocBook/drm.tmpl | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_drv.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 379 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_display.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_pm.c | 2 | ||||
-rw-r--r-- | include/drm/drmP.h | 18 |
9 files changed, 286 insertions, 155 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1fce7dc46d87..ca44d9fe7d7d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl | |||
@@ -3385,6 +3385,13 @@ void (*disable_vblank) (struct drm_device *dev, int crtc);</synopsis> | |||
3385 | by scheduling a timer. The delay is accessible through the vblankoffdelay | 3385 | by scheduling a timer. The delay is accessible through the vblankoffdelay |
3386 | module parameter or the <varname>drm_vblank_offdelay</varname> global | 3386 | module parameter or the <varname>drm_vblank_offdelay</varname> global |
3387 | variable and expressed in milliseconds. Its default value is 5000 ms. | 3387 | variable and expressed in milliseconds. Its default value is 5000 ms. |
3388 | Zero means never disable, and a negative value means disable immediately. | ||
3389 | Drivers may override the behaviour by setting the | ||
3390 | <structname>drm_device</structname> | ||
3391 | <structfield>vblank_disable_immediate</structfield> flag, which when set | ||
3392 | causes vblank interrupts to be disabled immediately regardless of the | ||
3393 | drm_vblank_offdelay value. The flag should only be set if there's a | ||
3394 | properly working hardware vblank counter present. | ||
3388 | </para> | 3395 | </para> |
3389 | <para> | 3396 | <para> |
3390 | When a vertical blanking interrupt occurs drivers only need to call the | 3397 | When a vertical blanking interrupt occurs drivers only need to call the |
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 66456698447e..970613c5a1eb 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c | |||
@@ -39,7 +39,7 @@ | |||
39 | unsigned int drm_debug = 0; /* 1 to enable debug output */ | 39 | unsigned int drm_debug = 0; /* 1 to enable debug output */ |
40 | EXPORT_SYMBOL(drm_debug); | 40 | EXPORT_SYMBOL(drm_debug); |
41 | 41 | ||
42 | unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ | 42 | int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ |
43 | 43 | ||
44 | unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ | 44 | unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ |
45 | 45 | ||
@@ -53,7 +53,7 @@ MODULE_AUTHOR(CORE_AUTHOR); | |||
53 | MODULE_DESCRIPTION(CORE_DESC); | 53 | MODULE_DESCRIPTION(CORE_DESC); |
54 | MODULE_LICENSE("GPL and additional rights"); | 54 | MODULE_LICENSE("GPL and additional rights"); |
55 | MODULE_PARM_DESC(debug, "Enable debug output"); | 55 | MODULE_PARM_DESC(debug, "Enable debug output"); |
56 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); | 56 | MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)"); |
57 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); | 57 | MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); |
58 | MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); | 58 | MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); |
59 | 59 | ||
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 5708c056fa1b..034297640b48 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c | |||
@@ -55,12 +55,74 @@ | |||
55 | */ | 55 | */ |
56 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 | 56 | #define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 |
57 | 57 | ||
58 | /* | 58 | static bool |
59 | * Clear vblank timestamp buffer for a crtc. | 59 | drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, |
60 | struct timeval *tvblank, unsigned flags); | ||
61 | |||
62 | /** | ||
63 | * drm_update_vblank_count - update the master vblank counter | ||
64 | * @dev: DRM device | ||
65 | * @crtc: counter to update | ||
66 | * | ||
67 | * Call back into the driver to update the appropriate vblank counter | ||
68 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
69 | * update the last read value so we can deal with wraparound on the next | ||
70 | * call if necessary. | ||
71 | * | ||
72 | * Only necessary when going from off->on, to account for frames we | ||
73 | * didn't get an interrupt for. | ||
74 | * | ||
75 | * Note: caller must hold dev->vbl_lock since this reads & writes | ||
76 | * device vblank fields. | ||
60 | */ | 77 | */ |
61 | static void clear_vblank_timestamps(struct drm_device *dev, int crtc) | 78 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) |
62 | { | 79 | { |
63 | memset(dev->vblank[crtc].time, 0, sizeof(dev->vblank[crtc].time)); | 80 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
81 | u32 cur_vblank, diff, tslot; | ||
82 | bool rc; | ||
83 | struct timeval t_vblank; | ||
84 | |||
85 | /* | ||
86 | * Interrupts were disabled prior to this call, so deal with counter | ||
87 | * wrap if needed. | ||
88 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
89 | * here if the register is small or we had vblank interrupts off for | ||
90 | * a long time. | ||
91 | * | ||
92 | * We repeat the hardware vblank counter & timestamp query until | ||
93 | * we get consistent results. This to prevent races between gpu | ||
94 | * updating its hardware counter while we are retrieving the | ||
95 | * corresponding vblank timestamp. | ||
96 | */ | ||
97 | do { | ||
98 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
99 | rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); | ||
100 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); | ||
101 | |||
102 | /* Deal with counter wrap */ | ||
103 | diff = cur_vblank - vblank->last; | ||
104 | if (cur_vblank < vblank->last) { | ||
105 | diff += dev->max_vblank_count; | ||
106 | |||
107 | DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", | ||
108 | crtc, vblank->last, cur_vblank, diff); | ||
109 | } | ||
110 | |||
111 | DRM_DEBUG("updating vblank count on crtc %d, missed %d\n", | ||
112 | crtc, diff); | ||
113 | |||
114 | /* Reinitialize corresponding vblank timestamp if high-precision query | ||
115 | * available. Skip this step if query unsupported or failed. Will | ||
116 | * reinitialize delayed at next vblank interrupt in that case. | ||
117 | */ | ||
118 | if (rc) { | ||
119 | tslot = atomic_read(&vblank->count) + diff; | ||
120 | vblanktimestamp(dev, crtc, tslot) = t_vblank; | ||
121 | } | ||
122 | |||
123 | smp_mb__before_atomic(); | ||
124 | atomic_add(diff, &vblank->count); | ||
125 | smp_mb__after_atomic(); | ||
64 | } | 126 | } |
65 | 127 | ||
66 | /* | 128 | /* |
@@ -71,10 +133,11 @@ static void clear_vblank_timestamps(struct drm_device *dev, int crtc) | |||
71 | */ | 133 | */ |
72 | static void vblank_disable_and_save(struct drm_device *dev, int crtc) | 134 | static void vblank_disable_and_save(struct drm_device *dev, int crtc) |
73 | { | 135 | { |
136 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
74 | unsigned long irqflags; | 137 | unsigned long irqflags; |
75 | u32 vblcount; | 138 | u32 vblcount; |
76 | s64 diff_ns; | 139 | s64 diff_ns; |
77 | int vblrc; | 140 | bool vblrc; |
78 | struct timeval tvblank; | 141 | struct timeval tvblank; |
79 | int count = DRM_TIMESTAMP_MAXRETRIES; | 142 | int count = DRM_TIMESTAMP_MAXRETRIES; |
80 | 143 | ||
@@ -84,8 +147,28 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
84 | */ | 147 | */ |
85 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | 148 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); |
86 | 149 | ||
150 | /* | ||
151 | * If the vblank interrupt was already disbled update the count | ||
152 | * and timestamp to maintain the appearance that the counter | ||
153 | * has been ticking all along until this time. This makes the | ||
154 | * count account for the entire time between drm_vblank_on() and | ||
155 | * drm_vblank_off(). | ||
156 | * | ||
157 | * But only do this if precise vblank timestamps are available. | ||
158 | * Otherwise we might read a totally bogus timestamp since drivers | ||
159 | * lacking precise timestamp support rely upon sampling the system clock | ||
160 | * at vblank interrupt time. Which obviously won't work out well if the | ||
161 | * vblank interrupt is disabled. | ||
162 | */ | ||
163 | if (!vblank->enabled && | ||
164 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0)) { | ||
165 | drm_update_vblank_count(dev, crtc); | ||
166 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | ||
167 | return; | ||
168 | } | ||
169 | |||
87 | dev->driver->disable_vblank(dev, crtc); | 170 | dev->driver->disable_vblank(dev, crtc); |
88 | dev->vblank[crtc].enabled = false; | 171 | vblank->enabled = false; |
89 | 172 | ||
90 | /* No further vblank irq's will be processed after | 173 | /* No further vblank irq's will be processed after |
91 | * this point. Get current hardware vblank count and | 174 | * this point. Get current hardware vblank count and |
@@ -100,9 +183,9 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
100 | * delayed gpu counter increment. | 183 | * delayed gpu counter increment. |
101 | */ | 184 | */ |
102 | do { | 185 | do { |
103 | dev->vblank[crtc].last = dev->driver->get_vblank_counter(dev, crtc); | 186 | vblank->last = dev->driver->get_vblank_counter(dev, crtc); |
104 | vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); | 187 | vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); |
105 | } while (dev->vblank[crtc].last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); | 188 | } while (vblank->last != dev->driver->get_vblank_counter(dev, crtc) && (--count) && vblrc); |
106 | 189 | ||
107 | if (!count) | 190 | if (!count) |
108 | vblrc = 0; | 191 | vblrc = 0; |
@@ -110,7 +193,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) | |||
110 | /* Compute time difference to stored timestamp of last vblank | 193 | /* Compute time difference to stored timestamp of last vblank |
111 | * as updated by last invocation of drm_handle_vblank() in vblank irq. | 194 | * as updated by last invocation of drm_handle_vblank() in vblank irq. |
112 | */ | 195 | */ |
113 | vblcount = atomic_read(&dev->vblank[crtc].count); | 196 | vblcount = atomic_read(&vblank->count); |
114 | diff_ns = timeval_to_ns(&tvblank) - | 197 | diff_ns = timeval_to_ns(&tvblank) - |
115 | timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); | 198 | timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); |
116 | 199 | ||
@@ -126,14 +209,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 | 209 | * available. In that case we can't account for this and just |
127 | * hope for the best. | 210 | * hope for the best. |
128 | */ | 211 | */ |
129 | if ((vblrc > 0) && (abs64(diff_ns) > 1000000)) { | 212 | if (vblrc && (abs64(diff_ns) > 1000000)) { |
130 | atomic_inc(&dev->vblank[crtc].count); | 213 | /* Store new timestamp in ringbuffer. */ |
214 | vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; | ||
215 | |||
216 | /* Increment cooked vblank count. This also atomically commits | ||
217 | * the timestamp computed above. | ||
218 | */ | ||
219 | smp_mb__before_atomic(); | ||
220 | atomic_inc(&vblank->count); | ||
131 | smp_mb__after_atomic(); | 221 | smp_mb__after_atomic(); |
132 | } | 222 | } |
133 | 223 | ||
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); | 224 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); |
138 | } | 225 | } |
139 | 226 | ||
@@ -164,14 +251,20 @@ static void vblank_disable_fn(unsigned long arg) | |||
164 | void drm_vblank_cleanup(struct drm_device *dev) | 251 | void drm_vblank_cleanup(struct drm_device *dev) |
165 | { | 252 | { |
166 | int crtc; | 253 | int crtc; |
254 | unsigned long irqflags; | ||
167 | 255 | ||
168 | /* Bail if the driver didn't call drm_vblank_init() */ | 256 | /* Bail if the driver didn't call drm_vblank_init() */ |
169 | if (dev->num_crtcs == 0) | 257 | if (dev->num_crtcs == 0) |
170 | return; | 258 | return; |
171 | 259 | ||
172 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { | 260 | for (crtc = 0; crtc < dev->num_crtcs; crtc++) { |
173 | del_timer_sync(&dev->vblank[crtc].disable_timer); | 261 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
174 | vblank_disable_fn((unsigned long)&dev->vblank[crtc]); | 262 | |
263 | del_timer_sync(&vblank->disable_timer); | ||
264 | |||
265 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | ||
266 | vblank_disable_and_save(dev, crtc); | ||
267 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
175 | } | 268 | } |
176 | 269 | ||
177 | kfree(dev->vblank); | 270 | kfree(dev->vblank); |
@@ -204,11 +297,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
204 | goto err; | 297 | goto err; |
205 | 298 | ||
206 | for (i = 0; i < num_crtcs; i++) { | 299 | for (i = 0; i < num_crtcs; i++) { |
207 | dev->vblank[i].dev = dev; | 300 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
208 | dev->vblank[i].crtc = i; | 301 | |
209 | init_waitqueue_head(&dev->vblank[i].queue); | 302 | vblank->dev = dev; |
210 | setup_timer(&dev->vblank[i].disable_timer, vblank_disable_fn, | 303 | vblank->crtc = i; |
211 | (unsigned long)&dev->vblank[i]); | 304 | init_waitqueue_head(&vblank->queue); |
305 | setup_timer(&vblank->disable_timer, vblank_disable_fn, | ||
306 | (unsigned long)vblank); | ||
212 | } | 307 | } |
213 | 308 | ||
214 | DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); | 309 | DRM_INFO("Supports vblank timestamp caching Rev 2 (21.10.2013).\n"); |
@@ -224,7 +319,7 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) | |||
224 | return 0; | 319 | return 0; |
225 | 320 | ||
226 | err: | 321 | err: |
227 | drm_vblank_cleanup(dev); | 322 | dev->num_crtcs = 0; |
228 | return ret; | 323 | return ret; |
229 | } | 324 | } |
230 | EXPORT_SYMBOL(drm_vblank_init); | 325 | EXPORT_SYMBOL(drm_vblank_init); |
@@ -360,9 +455,11 @@ int drm_irq_uninstall(struct drm_device *dev) | |||
360 | if (dev->num_crtcs) { | 455 | if (dev->num_crtcs) { |
361 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 456 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
362 | for (i = 0; i < dev->num_crtcs; i++) { | 457 | for (i = 0; i < dev->num_crtcs; i++) { |
363 | wake_up(&dev->vblank[i].queue); | 458 | struct drm_vblank_crtc *vblank = &dev->vblank[i]; |
364 | dev->vblank[i].enabled = false; | 459 | |
365 | dev->vblank[i].last = | 460 | wake_up(&vblank->queue); |
461 | vblank->enabled = false; | ||
462 | vblank->last = | ||
366 | dev->driver->get_vblank_counter(dev, i); | 463 | dev->driver->get_vblank_counter(dev, i); |
367 | } | 464 | } |
368 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 465 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
@@ -617,7 +714,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
617 | * within vblank area, counting down the number of lines until | 714 | * within vblank area, counting down the number of lines until |
618 | * start of scanout. | 715 | * start of scanout. |
619 | */ | 716 | */ |
620 | invbl = vbl_status & DRM_SCANOUTPOS_INVBL; | 717 | invbl = vbl_status & DRM_SCANOUTPOS_IN_VBLANK; |
621 | 718 | ||
622 | /* Convert scanout position into elapsed time at raw_time query | 719 | /* Convert scanout position into elapsed time at raw_time query |
623 | * since start of scanout at first display scanline. delta_ns | 720 | * since start of scanout at first display scanline. delta_ns |
@@ -647,7 +744,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, | |||
647 | 744 | ||
648 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; | 745 | vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; |
649 | if (invbl) | 746 | if (invbl) |
650 | vbl_status |= DRM_VBLANKTIME_INVBL; | 747 | vbl_status |= DRM_VBLANKTIME_IN_VBLANK; |
651 | 748 | ||
652 | return vbl_status; | 749 | return vbl_status; |
653 | } | 750 | } |
@@ -679,10 +776,11 @@ static struct timeval get_drm_timestamp(void) | |||
679 | * call, i.e., it isn't very precisely locked to the true vblank. | 776 | * call, i.e., it isn't very precisely locked to the true vblank. |
680 | * | 777 | * |
681 | * Returns: | 778 | * Returns: |
682 | * Non-zero if timestamp is considered to be very precise, zero otherwise. | 779 | * True if timestamp is considered to be very precise, false otherwise. |
683 | */ | 780 | */ |
684 | u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | 781 | static bool |
685 | struct timeval *tvblank, unsigned flags) | 782 | drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, |
783 | struct timeval *tvblank, unsigned flags) | ||
686 | { | 784 | { |
687 | int ret; | 785 | int ret; |
688 | 786 | ||
@@ -694,7 +792,7 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | |||
694 | ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, | 792 | ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, |
695 | tvblank, flags); | 793 | tvblank, flags); |
696 | if (ret > 0) | 794 | if (ret > 0) |
697 | return (u32) ret; | 795 | return true; |
698 | } | 796 | } |
699 | 797 | ||
700 | /* GPU high precision timestamp query unsupported or failed. | 798 | /* GPU high precision timestamp query unsupported or failed. |
@@ -702,9 +800,8 @@ u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | |||
702 | */ | 800 | */ |
703 | *tvblank = get_drm_timestamp(); | 801 | *tvblank = get_drm_timestamp(); |
704 | 802 | ||
705 | return 0; | 803 | return false; |
706 | } | 804 | } |
707 | EXPORT_SYMBOL(drm_get_last_vbltimestamp); | ||
708 | 805 | ||
709 | /** | 806 | /** |
710 | * drm_vblank_count - retrieve "cooked" vblank counter value | 807 | * drm_vblank_count - retrieve "cooked" vblank counter value |
@@ -720,9 +817,11 @@ EXPORT_SYMBOL(drm_get_last_vbltimestamp); | |||
720 | */ | 817 | */ |
721 | u32 drm_vblank_count(struct drm_device *dev, int crtc) | 818 | u32 drm_vblank_count(struct drm_device *dev, int crtc) |
722 | { | 819 | { |
820 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
821 | |||
723 | if (WARN_ON(crtc >= dev->num_crtcs)) | 822 | if (WARN_ON(crtc >= dev->num_crtcs)) |
724 | return 0; | 823 | return 0; |
725 | return atomic_read(&dev->vblank[crtc].count); | 824 | return atomic_read(&vblank->count); |
726 | } | 825 | } |
727 | EXPORT_SYMBOL(drm_vblank_count); | 826 | EXPORT_SYMBOL(drm_vblank_count); |
728 | 827 | ||
@@ -742,6 +841,7 @@ EXPORT_SYMBOL(drm_vblank_count); | |||
742 | u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | 841 | u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, |
743 | struct timeval *vblanktime) | 842 | struct timeval *vblanktime) |
744 | { | 843 | { |
844 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
745 | u32 cur_vblank; | 845 | u32 cur_vblank; |
746 | 846 | ||
747 | if (WARN_ON(crtc >= dev->num_crtcs)) | 847 | if (WARN_ON(crtc >= dev->num_crtcs)) |
@@ -753,10 +853,10 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, | |||
753 | * a seqlock. | 853 | * a seqlock. |
754 | */ | 854 | */ |
755 | do { | 855 | do { |
756 | cur_vblank = atomic_read(&dev->vblank[crtc].count); | 856 | cur_vblank = atomic_read(&vblank->count); |
757 | *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); | 857 | *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); |
758 | smp_rmb(); | 858 | smp_rmb(); |
759 | } while (cur_vblank != atomic_read(&dev->vblank[crtc].count)); | 859 | } while (cur_vblank != atomic_read(&vblank->count)); |
760 | 860 | ||
761 | return cur_vblank; | 861 | return cur_vblank; |
762 | } | 862 | } |
@@ -805,83 +905,20 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc, | |||
805 | EXPORT_SYMBOL(drm_send_vblank_event); | 905 | EXPORT_SYMBOL(drm_send_vblank_event); |
806 | 906 | ||
807 | /** | 907 | /** |
808 | * drm_update_vblank_count - update the master vblank counter | ||
809 | * @dev: DRM device | ||
810 | * @crtc: counter to update | ||
811 | * | ||
812 | * Call back into the driver to update the appropriate vblank counter | ||
813 | * (specified by @crtc). Deal with wraparound, if it occurred, and | ||
814 | * update the last read value so we can deal with wraparound on the next | ||
815 | * call if necessary. | ||
816 | * | ||
817 | * Only necessary when going from off->on, to account for frames we | ||
818 | * didn't get an interrupt for. | ||
819 | * | ||
820 | * Note: caller must hold dev->vbl_lock since this reads & writes | ||
821 | * device vblank fields. | ||
822 | */ | ||
823 | static void drm_update_vblank_count(struct drm_device *dev, int crtc) | ||
824 | { | ||
825 | u32 cur_vblank, diff, tslot, rc; | ||
826 | struct timeval t_vblank; | ||
827 | |||
828 | /* | ||
829 | * Interrupts were disabled prior to this call, so deal with counter | ||
830 | * wrap if needed. | ||
831 | * NOTE! It's possible we lost a full dev->max_vblank_count events | ||
832 | * here if the register is small or we had vblank interrupts off for | ||
833 | * a long time. | ||
834 | * | ||
835 | * We repeat the hardware vblank counter & timestamp query until | ||
836 | * we get consistent results. This to prevent races between gpu | ||
837 | * updating its hardware counter while we are retrieving the | ||
838 | * corresponding vblank timestamp. | ||
839 | */ | ||
840 | do { | ||
841 | cur_vblank = dev->driver->get_vblank_counter(dev, crtc); | ||
842 | rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); | ||
843 | } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); | ||
844 | |||
845 | /* Deal with counter wrap */ | ||
846 | diff = cur_vblank - dev->vblank[crtc].last; | ||
847 | if (cur_vblank < dev->vblank[crtc].last) { | ||
848 | diff += dev->max_vblank_count; | ||
849 | |||
850 | DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", | ||
851 | crtc, dev->vblank[crtc].last, cur_vblank, diff); | ||
852 | } | ||
853 | |||
854 | DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", | ||
855 | crtc, diff); | ||
856 | |||
857 | /* Reinitialize corresponding vblank timestamp if high-precision query | ||
858 | * available. Skip this step if query unsupported or failed. Will | ||
859 | * reinitialize delayed at next vblank interrupt in that case. | ||
860 | */ | ||
861 | if (rc) { | ||
862 | tslot = atomic_read(&dev->vblank[crtc].count) + diff; | ||
863 | vblanktimestamp(dev, crtc, tslot) = t_vblank; | ||
864 | } | ||
865 | |||
866 | smp_mb__before_atomic(); | ||
867 | atomic_add(diff, &dev->vblank[crtc].count); | ||
868 | smp_mb__after_atomic(); | ||
869 | } | ||
870 | |||
871 | /** | ||
872 | * drm_vblank_enable - enable the vblank interrupt on a CRTC | 908 | * drm_vblank_enable - enable the vblank interrupt on a CRTC |
873 | * @dev: DRM device | 909 | * @dev: DRM device |
874 | * @crtc: CRTC in question | 910 | * @crtc: CRTC in question |
875 | */ | 911 | */ |
876 | static int drm_vblank_enable(struct drm_device *dev, int crtc) | 912 | static int drm_vblank_enable(struct drm_device *dev, int crtc) |
877 | { | 913 | { |
914 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
878 | int ret = 0; | 915 | int ret = 0; |
879 | 916 | ||
880 | assert_spin_locked(&dev->vbl_lock); | 917 | assert_spin_locked(&dev->vbl_lock); |
881 | 918 | ||
882 | spin_lock(&dev->vblank_time_lock); | 919 | spin_lock(&dev->vblank_time_lock); |
883 | 920 | ||
884 | if (!dev->vblank[crtc].enabled) { | 921 | if (!vblank->enabled) { |
885 | /* | 922 | /* |
886 | * Enable vblank irqs under vblank_time_lock protection. | 923 | * Enable vblank irqs under vblank_time_lock protection. |
887 | * All vblank count & timestamp updates are held off | 924 | * All vblank count & timestamp updates are held off |
@@ -892,9 +929,9 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) | |||
892 | ret = dev->driver->enable_vblank(dev, crtc); | 929 | ret = dev->driver->enable_vblank(dev, crtc); |
893 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); | 930 | DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); |
894 | if (ret) | 931 | if (ret) |
895 | atomic_dec(&dev->vblank[crtc].refcount); | 932 | atomic_dec(&vblank->refcount); |
896 | else { | 933 | else { |
897 | dev->vblank[crtc].enabled = true; | 934 | vblank->enabled = true; |
898 | drm_update_vblank_count(dev, crtc); | 935 | drm_update_vblank_count(dev, crtc); |
899 | } | 936 | } |
900 | } | 937 | } |
@@ -919,6 +956,7 @@ static int drm_vblank_enable(struct drm_device *dev, int crtc) | |||
919 | */ | 956 | */ |
920 | int drm_vblank_get(struct drm_device *dev, int crtc) | 957 | int drm_vblank_get(struct drm_device *dev, int crtc) |
921 | { | 958 | { |
959 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
922 | unsigned long irqflags; | 960 | unsigned long irqflags; |
923 | int ret = 0; | 961 | int ret = 0; |
924 | 962 | ||
@@ -927,11 +965,11 @@ int drm_vblank_get(struct drm_device *dev, int crtc) | |||
927 | 965 | ||
928 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 966 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
929 | /* Going from 0->1 means we have to enable interrupts again */ | 967 | /* Going from 0->1 means we have to enable interrupts again */ |
930 | if (atomic_add_return(1, &dev->vblank[crtc].refcount) == 1) { | 968 | if (atomic_add_return(1, &vblank->refcount) == 1) { |
931 | ret = drm_vblank_enable(dev, crtc); | 969 | ret = drm_vblank_enable(dev, crtc); |
932 | } else { | 970 | } else { |
933 | if (!dev->vblank[crtc].enabled) { | 971 | if (!vblank->enabled) { |
934 | atomic_dec(&dev->vblank[crtc].refcount); | 972 | atomic_dec(&vblank->refcount); |
935 | ret = -EINVAL; | 973 | ret = -EINVAL; |
936 | } | 974 | } |
937 | } | 975 | } |
@@ -971,16 +1009,23 @@ EXPORT_SYMBOL(drm_crtc_vblank_get); | |||
971 | */ | 1009 | */ |
972 | void drm_vblank_put(struct drm_device *dev, int crtc) | 1010 | void drm_vblank_put(struct drm_device *dev, int crtc) |
973 | { | 1011 | { |
974 | BUG_ON(atomic_read(&dev->vblank[crtc].refcount) == 0); | 1012 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; |
1013 | |||
1014 | BUG_ON(atomic_read(&vblank->refcount) == 0); | ||
975 | 1015 | ||
976 | if (WARN_ON(crtc >= dev->num_crtcs)) | 1016 | if (WARN_ON(crtc >= dev->num_crtcs)) |
977 | return; | 1017 | return; |
978 | 1018 | ||
979 | /* Last user schedules interrupt disable */ | 1019 | /* Last user schedules interrupt disable */ |
980 | if (atomic_dec_and_test(&dev->vblank[crtc].refcount) && | 1020 | if (atomic_dec_and_test(&vblank->refcount)) { |
981 | (drm_vblank_offdelay > 0)) | 1021 | if (drm_vblank_offdelay == 0) |
982 | mod_timer(&dev->vblank[crtc].disable_timer, | 1022 | return; |
983 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); | 1023 | else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) |
1024 | vblank_disable_fn((unsigned long)vblank); | ||
1025 | else | ||
1026 | mod_timer(&vblank->disable_timer, | ||
1027 | jiffies + ((drm_vblank_offdelay * HZ)/1000)); | ||
1028 | } | ||
984 | } | 1029 | } |
985 | EXPORT_SYMBOL(drm_vblank_put); | 1030 | EXPORT_SYMBOL(drm_vblank_put); |
986 | 1031 | ||
@@ -1059,6 +1104,7 @@ EXPORT_SYMBOL(drm_crtc_wait_one_vblank); | |||
1059 | */ | 1104 | */ |
1060 | void drm_vblank_off(struct drm_device *dev, int crtc) | 1105 | void drm_vblank_off(struct drm_device *dev, int crtc) |
1061 | { | 1106 | { |
1107 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1062 | struct drm_pending_vblank_event *e, *t; | 1108 | struct drm_pending_vblank_event *e, *t; |
1063 | struct timeval now; | 1109 | struct timeval now; |
1064 | unsigned long irqflags; | 1110 | unsigned long irqflags; |
@@ -1067,14 +1113,25 @@ void drm_vblank_off(struct drm_device *dev, int crtc) | |||
1067 | if (WARN_ON(crtc >= dev->num_crtcs)) | 1113 | if (WARN_ON(crtc >= dev->num_crtcs)) |
1068 | return; | 1114 | return; |
1069 | 1115 | ||
1070 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1116 | spin_lock_irqsave(&dev->event_lock, irqflags); |
1117 | |||
1118 | spin_lock(&dev->vbl_lock); | ||
1071 | vblank_disable_and_save(dev, crtc); | 1119 | vblank_disable_and_save(dev, crtc); |
1072 | wake_up(&dev->vblank[crtc].queue); | 1120 | wake_up(&vblank->queue); |
1121 | |||
1122 | /* | ||
1123 | * Prevent subsequent drm_vblank_get() from re-enabling | ||
1124 | * the vblank interrupt by bumping the refcount. | ||
1125 | */ | ||
1126 | if (!vblank->inmodeset) { | ||
1127 | atomic_inc(&vblank->refcount); | ||
1128 | vblank->inmodeset = 1; | ||
1129 | } | ||
1130 | spin_unlock(&dev->vbl_lock); | ||
1073 | 1131 | ||
1074 | /* Send any queued vblank events, lest the natives grow disquiet */ | 1132 | /* Send any queued vblank events, lest the natives grow disquiet */ |
1075 | seq = drm_vblank_count_and_time(dev, crtc, &now); | 1133 | seq = drm_vblank_count_and_time(dev, crtc, &now); |
1076 | 1134 | ||
1077 | spin_lock(&dev->event_lock); | ||
1078 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { | 1135 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { |
1079 | if (e->pipe != crtc) | 1136 | if (e->pipe != crtc) |
1080 | continue; | 1137 | continue; |
@@ -1085,9 +1142,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc) | |||
1085 | drm_vblank_put(dev, e->pipe); | 1142 | drm_vblank_put(dev, e->pipe); |
1086 | send_vblank_event(dev, e, seq, &now); | 1143 | send_vblank_event(dev, e, seq, &now); |
1087 | } | 1144 | } |
1088 | spin_unlock(&dev->event_lock); | 1145 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
1089 | |||
1090 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | ||
1091 | } | 1146 | } |
1092 | EXPORT_SYMBOL(drm_vblank_off); | 1147 | EXPORT_SYMBOL(drm_vblank_off); |
1093 | 1148 | ||
@@ -1124,14 +1179,35 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); | |||
1124 | */ | 1179 | */ |
1125 | void drm_vblank_on(struct drm_device *dev, int crtc) | 1180 | void drm_vblank_on(struct drm_device *dev, int crtc) |
1126 | { | 1181 | { |
1182 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1127 | unsigned long irqflags; | 1183 | unsigned long irqflags; |
1128 | 1184 | ||
1129 | if (WARN_ON(crtc >= dev->num_crtcs)) | 1185 | if (WARN_ON(crtc >= dev->num_crtcs)) |
1130 | return; | 1186 | return; |
1131 | 1187 | ||
1132 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1188 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
1133 | /* re-enable interrupts if there's are users left */ | 1189 | /* Drop our private "prevent drm_vblank_get" refcount */ |
1134 | if (atomic_read(&dev->vblank[crtc].refcount) != 0) | 1190 | if (vblank->inmodeset) { |
1191 | atomic_dec(&vblank->refcount); | ||
1192 | vblank->inmodeset = 0; | ||
1193 | } | ||
1194 | |||
1195 | /* | ||
1196 | * sample the current counter to avoid random jumps | ||
1197 | * when drm_vblank_enable() applies the diff | ||
1198 | * | ||
1199 | * -1 to make sure user will never see the same | ||
1200 | * vblank counter value before and after a modeset | ||
1201 | */ | ||
1202 | vblank->last = | ||
1203 | (dev->driver->get_vblank_counter(dev, crtc) - 1) & | ||
1204 | dev->max_vblank_count; | ||
1205 | /* | ||
1206 | * re-enable interrupts if there are users left, or the | ||
1207 | * user wishes vblank interrupts to be enabled all the time. | ||
1208 | */ | ||
1209 | if (atomic_read(&vblank->refcount) != 0 || | ||
1210 | (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0)) | ||
1135 | WARN_ON(drm_vblank_enable(dev, crtc)); | 1211 | WARN_ON(drm_vblank_enable(dev, crtc)); |
1136 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 1212 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
1137 | } | 1213 | } |
@@ -1179,6 +1255,8 @@ EXPORT_SYMBOL(drm_crtc_vblank_on); | |||
1179 | */ | 1255 | */ |
1180 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | 1256 | void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) |
1181 | { | 1257 | { |
1258 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1259 | |||
1182 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ | 1260 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1183 | if (!dev->num_crtcs) | 1261 | if (!dev->num_crtcs) |
1184 | return; | 1262 | return; |
@@ -1193,10 +1271,10 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc) | |||
1193 | * to avoid corrupting the count if multiple, mismatch calls occur), | 1271 | * to avoid corrupting the count if multiple, mismatch calls occur), |
1194 | * so that interrupts remain enabled in the interim. | 1272 | * so that interrupts remain enabled in the interim. |
1195 | */ | 1273 | */ |
1196 | if (!dev->vblank[crtc].inmodeset) { | 1274 | if (!vblank->inmodeset) { |
1197 | dev->vblank[crtc].inmodeset = 0x1; | 1275 | vblank->inmodeset = 0x1; |
1198 | if (drm_vblank_get(dev, crtc) == 0) | 1276 | if (drm_vblank_get(dev, crtc) == 0) |
1199 | dev->vblank[crtc].inmodeset |= 0x2; | 1277 | vblank->inmodeset |= 0x2; |
1200 | } | 1278 | } |
1201 | } | 1279 | } |
1202 | EXPORT_SYMBOL(drm_vblank_pre_modeset); | 1280 | EXPORT_SYMBOL(drm_vblank_pre_modeset); |
@@ -1211,21 +1289,22 @@ EXPORT_SYMBOL(drm_vblank_pre_modeset); | |||
1211 | */ | 1289 | */ |
1212 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) | 1290 | void drm_vblank_post_modeset(struct drm_device *dev, int crtc) |
1213 | { | 1291 | { |
1292 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1214 | unsigned long irqflags; | 1293 | unsigned long irqflags; |
1215 | 1294 | ||
1216 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ | 1295 | /* vblank is not initialized (IRQ not installed ?), or has been freed */ |
1217 | if (!dev->num_crtcs) | 1296 | if (!dev->num_crtcs) |
1218 | return; | 1297 | return; |
1219 | 1298 | ||
1220 | if (dev->vblank[crtc].inmodeset) { | 1299 | if (vblank->inmodeset) { |
1221 | spin_lock_irqsave(&dev->vbl_lock, irqflags); | 1300 | spin_lock_irqsave(&dev->vbl_lock, irqflags); |
1222 | dev->vblank_disable_allowed = true; | 1301 | dev->vblank_disable_allowed = true; |
1223 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); | 1302 | spin_unlock_irqrestore(&dev->vbl_lock, irqflags); |
1224 | 1303 | ||
1225 | if (dev->vblank[crtc].inmodeset & 0x2) | 1304 | if (vblank->inmodeset & 0x2) |
1226 | drm_vblank_put(dev, crtc); | 1305 | drm_vblank_put(dev, crtc); |
1227 | 1306 | ||
1228 | dev->vblank[crtc].inmodeset = 0; | 1307 | vblank->inmodeset = 0; |
1229 | } | 1308 | } |
1230 | } | 1309 | } |
1231 | EXPORT_SYMBOL(drm_vblank_post_modeset); | 1310 | EXPORT_SYMBOL(drm_vblank_post_modeset); |
@@ -1277,6 +1356,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
1277 | union drm_wait_vblank *vblwait, | 1356 | union drm_wait_vblank *vblwait, |
1278 | struct drm_file *file_priv) | 1357 | struct drm_file *file_priv) |
1279 | { | 1358 | { |
1359 | struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; | ||
1280 | struct drm_pending_vblank_event *e; | 1360 | struct drm_pending_vblank_event *e; |
1281 | struct timeval now; | 1361 | struct timeval now; |
1282 | unsigned long flags; | 1362 | unsigned long flags; |
@@ -1300,6 +1380,18 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, | |||
1300 | 1380 | ||
1301 | spin_lock_irqsave(&dev->event_lock, flags); | 1381 | spin_lock_irqsave(&dev->event_lock, flags); |
1302 | 1382 | ||
1383 | /* | ||
1384 | * drm_vblank_off() might have been called after we called | ||
1385 | * drm_vblank_get(). drm_vblank_off() holds event_lock | ||
1386 | * around the vblank disable, so no need for further locking. | ||
1387 | * The reference from drm_vblank_get() protects against | ||
1388 | * vblank disable from another source. | ||
1389 | */ | ||
1390 | if (!vblank->enabled) { | ||
1391 | ret = -EINVAL; | ||
1392 | goto err_unlock; | ||
1393 | } | ||
1394 | |||
1303 | if (file_priv->event_space < sizeof e->event) { | 1395 | if (file_priv->event_space < sizeof e->event) { |
1304 | ret = -EBUSY; | 1396 | ret = -EBUSY; |
1305 | goto err_unlock; | 1397 | goto err_unlock; |
@@ -1360,6 +1452,7 @@ err_put: | |||
1360 | int drm_wait_vblank(struct drm_device *dev, void *data, | 1452 | int drm_wait_vblank(struct drm_device *dev, void *data, |
1361 | struct drm_file *file_priv) | 1453 | struct drm_file *file_priv) |
1362 | { | 1454 | { |
1455 | struct drm_vblank_crtc *vblank; | ||
1363 | union drm_wait_vblank *vblwait = data; | 1456 | union drm_wait_vblank *vblwait = data; |
1364 | int ret; | 1457 | int ret; |
1365 | unsigned int flags, seq, crtc, high_crtc; | 1458 | unsigned int flags, seq, crtc, high_crtc; |
@@ -1389,6 +1482,8 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1389 | if (crtc >= dev->num_crtcs) | 1482 | if (crtc >= dev->num_crtcs) |
1390 | return -EINVAL; | 1483 | return -EINVAL; |
1391 | 1484 | ||
1485 | vblank = &dev->vblank[crtc]; | ||
1486 | |||
1392 | ret = drm_vblank_get(dev, crtc); | 1487 | ret = drm_vblank_get(dev, crtc); |
1393 | if (ret) { | 1488 | if (ret) { |
1394 | DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); | 1489 | DRM_DEBUG("failed to acquire vblank counter, %d\n", ret); |
@@ -1421,11 +1516,11 @@ int drm_wait_vblank(struct drm_device *dev, void *data, | |||
1421 | 1516 | ||
1422 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", | 1517 | DRM_DEBUG("waiting on vblank count %d, crtc %d\n", |
1423 | vblwait->request.sequence, crtc); | 1518 | vblwait->request.sequence, crtc); |
1424 | dev->vblank[crtc].last_wait = vblwait->request.sequence; | 1519 | vblank->last_wait = vblwait->request.sequence; |
1425 | DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ, | 1520 | DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, |
1426 | (((drm_vblank_count(dev, crtc) - | 1521 | (((drm_vblank_count(dev, crtc) - |
1427 | vblwait->request.sequence) <= (1 << 23)) || | 1522 | vblwait->request.sequence) <= (1 << 23)) || |
1428 | !dev->vblank[crtc].enabled || | 1523 | !vblank->enabled || |
1429 | !dev->irq_enabled)); | 1524 | !dev->irq_enabled)); |
1430 | 1525 | ||
1431 | if (ret != -EINTR) { | 1526 | if (ret != -EINTR) { |
@@ -1450,12 +1545,11 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
1450 | { | 1545 | { |
1451 | struct drm_pending_vblank_event *e, *t; | 1546 | struct drm_pending_vblank_event *e, *t; |
1452 | struct timeval now; | 1547 | struct timeval now; |
1453 | unsigned long flags; | ||
1454 | unsigned int seq; | 1548 | unsigned int seq; |
1455 | 1549 | ||
1456 | seq = drm_vblank_count_and_time(dev, crtc, &now); | 1550 | assert_spin_locked(&dev->event_lock); |
1457 | 1551 | ||
1458 | spin_lock_irqsave(&dev->event_lock, flags); | 1552 | seq = drm_vblank_count_and_time(dev, crtc, &now); |
1459 | 1553 | ||
1460 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { | 1554 | list_for_each_entry_safe(e, t, &dev->vblank_event_list, base.link) { |
1461 | if (e->pipe != crtc) | 1555 | if (e->pipe != crtc) |
@@ -1471,8 +1565,6 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
1471 | send_vblank_event(dev, e, seq, &now); | 1565 | send_vblank_event(dev, e, seq, &now); |
1472 | } | 1566 | } |
1473 | 1567 | ||
1474 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
1475 | |||
1476 | trace_drm_vblank_event(crtc, seq); | 1568 | trace_drm_vblank_event(crtc, seq); |
1477 | } | 1569 | } |
1478 | 1570 | ||
@@ -1486,6 +1578,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc) | |||
1486 | */ | 1578 | */ |
1487 | bool drm_handle_vblank(struct drm_device *dev, int crtc) | 1579 | bool drm_handle_vblank(struct drm_device *dev, int crtc) |
1488 | { | 1580 | { |
1581 | struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; | ||
1489 | u32 vblcount; | 1582 | u32 vblcount; |
1490 | s64 diff_ns; | 1583 | s64 diff_ns; |
1491 | struct timeval tvblank; | 1584 | struct timeval tvblank; |
@@ -1497,15 +1590,18 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1497 | if (WARN_ON(crtc >= dev->num_crtcs)) | 1590 | if (WARN_ON(crtc >= dev->num_crtcs)) |
1498 | return false; | 1591 | return false; |
1499 | 1592 | ||
1593 | spin_lock_irqsave(&dev->event_lock, irqflags); | ||
1594 | |||
1500 | /* Need timestamp lock to prevent concurrent execution with | 1595 | /* Need timestamp lock to prevent concurrent execution with |
1501 | * vblank enable/disable, as this would cause inconsistent | 1596 | * vblank enable/disable, as this would cause inconsistent |
1502 | * or corrupted timestamps and vblank counts. | 1597 | * or corrupted timestamps and vblank counts. |
1503 | */ | 1598 | */ |
1504 | spin_lock_irqsave(&dev->vblank_time_lock, irqflags); | 1599 | spin_lock(&dev->vblank_time_lock); |
1505 | 1600 | ||
1506 | /* Vblank irq handling disabled. Nothing to do. */ | 1601 | /* Vblank irq handling disabled. Nothing to do. */ |
1507 | if (!dev->vblank[crtc].enabled) { | 1602 | if (!vblank->enabled) { |
1508 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 1603 | spin_unlock(&dev->vblank_time_lock); |
1604 | spin_unlock_irqrestore(&dev->event_lock, irqflags); | ||
1509 | return false; | 1605 | return false; |
1510 | } | 1606 | } |
1511 | 1607 | ||
@@ -1514,7 +1610,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1514 | */ | 1610 | */ |
1515 | 1611 | ||
1516 | /* Get current timestamp and count. */ | 1612 | /* Get current timestamp and count. */ |
1517 | vblcount = atomic_read(&dev->vblank[crtc].count); | 1613 | vblcount = atomic_read(&vblank->count); |
1518 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); | 1614 | drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); |
1519 | 1615 | ||
1520 | /* Compute time difference to timestamp of last vblank */ | 1616 | /* Compute time difference to timestamp of last vblank */ |
@@ -1538,17 +1634,20 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc) | |||
1538 | * the timestamp computed above. | 1634 | * the timestamp computed above. |
1539 | */ | 1635 | */ |
1540 | smp_mb__before_atomic(); | 1636 | smp_mb__before_atomic(); |
1541 | atomic_inc(&dev->vblank[crtc].count); | 1637 | atomic_inc(&vblank->count); |
1542 | smp_mb__after_atomic(); | 1638 | smp_mb__after_atomic(); |
1543 | } else { | 1639 | } else { |
1544 | DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", | 1640 | DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", |
1545 | crtc, (int) diff_ns); | 1641 | crtc, (int) diff_ns); |
1546 | } | 1642 | } |
1547 | 1643 | ||
1548 | wake_up(&dev->vblank[crtc].queue); | 1644 | spin_unlock(&dev->vblank_time_lock); |
1645 | |||
1646 | wake_up(&vblank->queue); | ||
1549 | drm_handle_vblank_events(dev, crtc); | 1647 | drm_handle_vblank_events(dev, crtc); |
1550 | 1648 | ||
1551 | spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); | 1649 | spin_unlock_irqrestore(&dev->event_lock, irqflags); |
1650 | |||
1552 | return true; | 1651 | return true; |
1553 | } | 1652 | } |
1554 | EXPORT_SYMBOL(drm_handle_vblank); | 1653 | EXPORT_SYMBOL(drm_handle_vblank); |
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8b158f02bd0f..7391697c25e7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c | |||
@@ -1020,7 +1020,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, | |||
1020 | 1020 | ||
1021 | /* In vblank? */ | 1021 | /* In vblank? */ |
1022 | if (in_vbl) | 1022 | if (in_vbl) |
1023 | ret |= DRM_SCANOUTPOS_INVBL; | 1023 | ret |= DRM_SCANOUTPOS_IN_VBLANK; |
1024 | 1024 | ||
1025 | return ret; | 1025 | return ret; |
1026 | } | 1026 | } |
@@ -4701,6 +4701,14 @@ void intel_irq_init(struct drm_device *dev) | |||
4701 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ | 4701 | dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ |
4702 | } | 4702 | } |
4703 | 4703 | ||
4704 | /* | ||
4705 | * Opt out of the vblank disable timer on everything except gen2. | ||
4706 | * Gen2 doesn't have a hardware frame counter and so depends on | ||
4707 | * vblank interrupts to produce sane vblank seuquence numbers. | ||
4708 | */ | ||
4709 | if (!IS_GEN2(dev)) | ||
4710 | dev->vblank_disable_immediate = true; | ||
4711 | |||
4704 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 4712 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
4705 | dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; | 4713 | dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; |
4706 | dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; | 4714 | dev->driver->get_scanout_position = i915_get_crtc_scanoutpos; |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca8592e73644..0b327ebb2d9e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -1342,6 +1342,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv, | |||
1342 | } | 1342 | } |
1343 | } | 1343 | } |
1344 | 1344 | ||
1345 | static void assert_vblank_disabled(struct drm_crtc *crtc) | ||
1346 | { | ||
1347 | if (WARN_ON(drm_crtc_vblank_get(crtc) == 0)) | ||
1348 | drm_crtc_vblank_put(crtc); | ||
1349 | } | ||
1350 | |||
1345 | static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) | 1351 | static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv) |
1346 | { | 1352 | { |
1347 | u32 val; | 1353 | u32 val; |
@@ -3891,6 +3897,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) | |||
3891 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 3897 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
3892 | int pipe = intel_crtc->pipe; | 3898 | int pipe = intel_crtc->pipe; |
3893 | 3899 | ||
3900 | assert_vblank_disabled(crtc); | ||
3901 | |||
3894 | drm_vblank_on(dev, pipe); | 3902 | drm_vblank_on(dev, pipe); |
3895 | 3903 | ||
3896 | intel_enable_primary_hw_plane(crtc->primary, crtc); | 3904 | intel_enable_primary_hw_plane(crtc->primary, crtc); |
@@ -3940,6 +3948,8 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) | |||
3940 | intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); | 3948 | intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); |
3941 | 3949 | ||
3942 | drm_vblank_off(dev, pipe); | 3950 | drm_vblank_off(dev, pipe); |
3951 | |||
3952 | assert_vblank_disabled(crtc); | ||
3943 | } | 3953 | } |
3944 | 3954 | ||
3945 | static void ironlake_crtc_enable(struct drm_crtc *crtc) | 3955 | static void ironlake_crtc_enable(struct drm_crtc *crtc) |
@@ -12766,9 +12776,10 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) | |||
12766 | I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); | 12776 | I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); |
12767 | 12777 | ||
12768 | /* restore vblank interrupts to correct state */ | 12778 | /* restore vblank interrupts to correct state */ |
12769 | if (crtc->active) | 12779 | if (crtc->active) { |
12780 | update_scanline_offset(crtc); | ||
12770 | drm_vblank_on(dev, crtc->pipe); | 12781 | drm_vblank_on(dev, crtc->pipe); |
12771 | else | 12782 | } else |
12772 | drm_vblank_off(dev, crtc->pipe); | 12783 | drm_vblank_off(dev, crtc->pipe); |
12773 | 12784 | ||
12774 | /* We need to sanitize the plane -> pipe mapping first because this will | 12785 | /* We need to sanitize the plane -> pipe mapping first because this will |
@@ -12867,8 +12878,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) | |||
12867 | */ | 12878 | */ |
12868 | crtc->cpu_fifo_underrun_disabled = true; | 12879 | crtc->cpu_fifo_underrun_disabled = true; |
12869 | crtc->pch_fifo_underrun_disabled = true; | 12880 | crtc->pch_fifo_underrun_disabled = true; |
12870 | |||
12871 | update_scanline_offset(crtc); | ||
12872 | } | 12881 | } |
12873 | } | 12882 | } |
12874 | 12883 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index a9ec525c0994..6d0a3cdc752b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c | |||
@@ -126,7 +126,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, | |||
126 | if (etime) *etime = ns_to_ktime(args.scan.time[1]); | 126 | if (etime) *etime = ns_to_ktime(args.scan.time[1]); |
127 | 127 | ||
128 | if (*vpos < 0) | 128 | if (*vpos < 0) |
129 | ret |= DRM_SCANOUTPOS_INVBL; | 129 | ret |= DRM_SCANOUTPOS_IN_VBLANK; |
130 | return ret; | 130 | return ret; |
131 | } | 131 | } |
132 | 132 | ||
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index bc894c17b2f9..4eb37976f879 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -1914,7 +1914,7 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int fl | |||
1914 | 1914 | ||
1915 | /* In vblank? */ | 1915 | /* In vblank? */ |
1916 | if (in_vbl) | 1916 | if (in_vbl) |
1917 | ret |= DRM_SCANOUTPOS_INVBL; | 1917 | ret |= DRM_SCANOUTPOS_IN_VBLANK; |
1918 | 1918 | ||
1919 | /* Is vpos outside nominal vblank area, but less than | 1919 | /* Is vpos outside nominal vblank area, but less than |
1920 | * 1/100 of a frame height away from start of vblank? | 1920 | * 1/100 of a frame height away from start of vblank? |
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 164898b0010c..32522cc940a1 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c | |||
@@ -1556,7 +1556,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev) | |||
1556 | if (rdev->pm.active_crtcs & (1 << crtc)) { | 1556 | if (rdev->pm.active_crtcs & (1 << crtc)) { |
1557 | vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); | 1557 | vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0, &vpos, &hpos, NULL, NULL); |
1558 | if ((vbl_status & DRM_SCANOUTPOS_VALID) && | 1558 | if ((vbl_status & DRM_SCANOUTPOS_VALID) && |
1559 | !(vbl_status & DRM_SCANOUTPOS_INVBL)) | 1559 | !(vbl_status & DRM_SCANOUTPOS_IN_VBLANK)) |
1560 | in_vbl = false; | 1560 | in_vbl = false; |
1561 | } | 1561 | } |
1562 | } | 1562 | } |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index be1160fa5ebc..e748b42e4186 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -598,11 +598,11 @@ struct drm_master { | |||
598 | /* Flags and return codes for get_vblank_timestamp() driver function. */ | 598 | /* Flags and return codes for get_vblank_timestamp() driver function. */ |
599 | #define DRM_CALLED_FROM_VBLIRQ 1 | 599 | #define DRM_CALLED_FROM_VBLIRQ 1 |
600 | #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) | 600 | #define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) |
601 | #define DRM_VBLANKTIME_INVBL (1 << 1) | 601 | #define DRM_VBLANKTIME_IN_VBLANK (1 << 1) |
602 | 602 | ||
603 | /* get_scanout_position() return flags */ | 603 | /* get_scanout_position() return flags */ |
604 | #define DRM_SCANOUTPOS_VALID (1 << 0) | 604 | #define DRM_SCANOUTPOS_VALID (1 << 0) |
605 | #define DRM_SCANOUTPOS_INVBL (1 << 1) | 605 | #define DRM_SCANOUTPOS_IN_VBLANK (1 << 1) |
606 | #define DRM_SCANOUTPOS_ACCURATE (1 << 2) | 606 | #define DRM_SCANOUTPOS_ACCURATE (1 << 2) |
607 | 607 | ||
608 | /** | 608 | /** |
@@ -996,6 +996,16 @@ struct drm_device { | |||
996 | */ | 996 | */ |
997 | bool vblank_disable_allowed; | 997 | bool vblank_disable_allowed; |
998 | 998 | ||
999 | /* | ||
1000 | * If true, vblank interrupt will be disabled immediately when the | ||
1001 | * refcount drops to zero, as opposed to via the vblank disable | ||
1002 | * timer. | ||
1003 | * This can be set to true it the hardware has a working vblank | ||
1004 | * counter and the driver uses drm_vblank_on() and drm_vblank_off() | ||
1005 | * appropriately. | ||
1006 | */ | ||
1007 | bool vblank_disable_immediate; | ||
1008 | |||
999 | /* array of size num_crtcs */ | 1009 | /* array of size num_crtcs */ |
1000 | struct drm_vblank_crtc *vblank; | 1010 | struct drm_vblank_crtc *vblank; |
1001 | 1011 | ||
@@ -1182,8 +1192,6 @@ extern void drm_crtc_vblank_off(struct drm_crtc *crtc); | |||
1182 | extern void drm_crtc_vblank_on(struct drm_crtc *crtc); | 1192 | extern void drm_crtc_vblank_on(struct drm_crtc *crtc); |
1183 | extern void drm_vblank_cleanup(struct drm_device *dev); | 1193 | extern void drm_vblank_cleanup(struct drm_device *dev); |
1184 | 1194 | ||
1185 | extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, | ||
1186 | struct timeval *tvblank, unsigned flags); | ||
1187 | extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, | 1195 | extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, |
1188 | int crtc, int *max_error, | 1196 | int crtc, int *max_error, |
1189 | struct timeval *vblank_time, | 1197 | struct timeval *vblank_time, |
@@ -1224,7 +1232,7 @@ extern void drm_put_dev(struct drm_device *dev); | |||
1224 | extern void drm_unplug_dev(struct drm_device *dev); | 1232 | extern void drm_unplug_dev(struct drm_device *dev); |
1225 | extern unsigned int drm_debug; | 1233 | extern unsigned int drm_debug; |
1226 | 1234 | ||
1227 | extern unsigned int drm_vblank_offdelay; | 1235 | extern int drm_vblank_offdelay; |
1228 | extern unsigned int drm_timestamp_precision; | 1236 | extern unsigned int drm_timestamp_precision; |
1229 | extern unsigned int drm_timestamp_monotonic; | 1237 | extern unsigned int drm_timestamp_monotonic; |
1230 | 1238 | ||