aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_irq.c')
-rw-r--r--drivers/gpu/drm/drm_irq.c109
1 files changed, 65 insertions, 44 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index af9662e58272..b50fa0afd907 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -74,6 +74,36 @@ module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
74module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); 74module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
75module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); 75module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
76 76
77static void store_vblank(struct drm_device *dev, int crtc,
78 u32 vblank_count_inc,
79 struct timeval *t_vblank)
80{
81 struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
82 u32 tslot;
83
84 assert_spin_locked(&dev->vblank_time_lock);
85
86 if (t_vblank) {
87 /* All writers hold the spinlock, but readers are serialized by
88 * the latching of vblank->count below.
89 */
90 tslot = vblank->count + vblank_count_inc;
91 vblanktimestamp(dev, crtc, tslot) = *t_vblank;
92 }
93
94 /*
95 * vblank timestamp updates are protected on the write side with
96 * vblank_time_lock, but on the read side done locklessly using a
97 * sequence-lock on the vblank counter. Ensure correct ordering using
98 * memory barrriers. We need the barrier both before and also after the
99 * counter update to synchronize with the next timestamp write.
100 * The read-side barriers for this are in drm_vblank_count_and_time.
101 */
102 smp_wmb();
103 vblank->count += vblank_count_inc;
104 smp_wmb();
105}
106
77/** 107/**
78 * drm_update_vblank_count - update the master vblank counter 108 * drm_update_vblank_count - update the master vblank counter
79 * @dev: DRM device 109 * @dev: DRM device
@@ -93,14 +123,14 @@ module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
93static void drm_update_vblank_count(struct drm_device *dev, int crtc) 123static void drm_update_vblank_count(struct drm_device *dev, int crtc)
94{ 124{
95 struct drm_vblank_crtc *vblank = &dev->vblank[crtc]; 125 struct drm_vblank_crtc *vblank = &dev->vblank[crtc];
96 u32 cur_vblank, diff, tslot; 126 u32 cur_vblank, diff;
97 bool rc; 127 bool rc;
98 struct timeval t_vblank; 128 struct timeval t_vblank;
99 129
100 /* 130 /*
101 * Interrupts were disabled prior to this call, so deal with counter 131 * Interrupts were disabled prior to this call, so deal with counter
102 * wrap if needed. 132 * wrap if needed.
103 * NOTE! It's possible we lost a full dev->max_vblank_count events 133 * NOTE! It's possible we lost a full dev->max_vblank_count + 1 events
104 * here if the register is small or we had vblank interrupts off for 134 * here if the register is small or we had vblank interrupts off for
105 * a long time. 135 * a long time.
106 * 136 *
@@ -117,7 +147,7 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
117 /* Deal with counter wrap */ 147 /* Deal with counter wrap */
118 diff = cur_vblank - vblank->last; 148 diff = cur_vblank - vblank->last;
119 if (cur_vblank < vblank->last) { 149 if (cur_vblank < vblank->last) {
120 diff += dev->max_vblank_count; 150 diff += dev->max_vblank_count + 1;
121 151
122 DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n", 152 DRM_DEBUG("last_vblank[%d]=0x%x, cur_vblank=0x%x => diff=0x%x\n",
123 crtc, vblank->last, cur_vblank, diff); 153 crtc, vblank->last, cur_vblank, diff);
@@ -129,17 +159,15 @@ static void drm_update_vblank_count(struct drm_device *dev, int crtc)
129 if (diff == 0) 159 if (diff == 0)
130 return; 160 return;
131 161
132 /* Reinitialize corresponding vblank timestamp if high-precision query 162 /*
133 * available. Skip this step if query unsupported or failed. Will 163 * Only reinitialize corresponding vblank timestamp if high-precision query
134 * reinitialize delayed at next vblank interrupt in that case and 164 * available and didn't fail. Otherwise reinitialize delayed at next vblank
135 * assign 0 for now, to mark the vblanktimestamp as invalid. 165 * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid.
136 */ 166 */
137 tslot = atomic_read(&vblank->count) + diff; 167 if (!rc)
138 vblanktimestamp(dev, crtc, tslot) = rc ? t_vblank : (struct timeval) {0, 0}; 168 t_vblank = (struct timeval) {0, 0};
139 169
140 smp_mb__before_atomic(); 170 store_vblank(dev, crtc, diff, &t_vblank);
141 atomic_add(diff, &vblank->count);
142 smp_mb__after_atomic();
143} 171}
144 172
145/* 173/*
@@ -217,7 +245,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
217 /* Compute time difference to stored timestamp of last vblank 245 /* Compute time difference to stored timestamp of last vblank
218 * as updated by last invocation of drm_handle_vblank() in vblank irq. 246 * as updated by last invocation of drm_handle_vblank() in vblank irq.
219 */ 247 */
220 vblcount = atomic_read(&vblank->count); 248 vblcount = vblank->count;
221 diff_ns = timeval_to_ns(&tvblank) - 249 diff_ns = timeval_to_ns(&tvblank) -
222 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); 250 timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount));
223 251
@@ -233,17 +261,8 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
233 * available. In that case we can't account for this and just 261 * available. In that case we can't account for this and just
234 * hope for the best. 262 * hope for the best.
235 */ 263 */
236 if (vblrc && (abs64(diff_ns) > 1000000)) { 264 if (vblrc && (abs64(diff_ns) > 1000000))
237 /* Store new timestamp in ringbuffer. */ 265 store_vblank(dev, crtc, 1, &tvblank);
238 vblanktimestamp(dev, crtc, vblcount + 1) = tvblank;
239
240 /* Increment cooked vblank count. This also atomically commits
241 * the timestamp computed above.
242 */
243 smp_mb__before_atomic();
244 atomic_inc(&vblank->count);
245 smp_mb__after_atomic();
246 }
247 266
248 spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); 267 spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
249} 268}
@@ -336,6 +355,13 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
336 else 355 else
337 DRM_INFO("No driver support for vblank timestamp query.\n"); 356 DRM_INFO("No driver support for vblank timestamp query.\n");
338 357
358 /* Must have precise timestamping for reliable vblank instant disable */
359 if (dev->vblank_disable_immediate && !dev->driver->get_vblank_timestamp) {
360 dev->vblank_disable_immediate = false;
361 DRM_INFO("Setting vblank_disable_immediate to false because "
362 "get_vblank_timestamp == NULL\n");
363 }
364
339 dev->vblank_disable_allowed = false; 365 dev->vblank_disable_allowed = false;
340 366
341 return 0; 367 return 0;
@@ -851,7 +877,7 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc)
851 877
852 if (WARN_ON(crtc >= dev->num_crtcs)) 878 if (WARN_ON(crtc >= dev->num_crtcs))
853 return 0; 879 return 0;
854 return atomic_read(&vblank->count); 880 return vblank->count;
855} 881}
856EXPORT_SYMBOL(drm_vblank_count); 882EXPORT_SYMBOL(drm_vblank_count);
857 883
@@ -896,16 +922,17 @@ u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc,
896 if (WARN_ON(crtc >= dev->num_crtcs)) 922 if (WARN_ON(crtc >= dev->num_crtcs))
897 return 0; 923 return 0;
898 924
899 /* Read timestamp from slot of _vblank_time ringbuffer 925 /*
900 * that corresponds to current vblank count. Retry if 926 * Vblank timestamps are read lockless. To ensure consistency the vblank
901 * count has incremented during readout. This works like 927 * counter is rechecked and ordering is ensured using memory barriers.
902 * a seqlock. 928 * This works like a seqlock. The write-side barriers are in store_vblank.
903 */ 929 */
904 do { 930 do {
905 cur_vblank = atomic_read(&vblank->count); 931 cur_vblank = vblank->count;
932 smp_rmb();
906 *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); 933 *vblanktime = vblanktimestamp(dev, crtc, cur_vblank);
907 smp_rmb(); 934 smp_rmb();
908 } while (cur_vblank != atomic_read(&vblank->count)); 935 } while (cur_vblank != vblank->count);
909 936
910 return cur_vblank; 937 return cur_vblank;
911} 938}
@@ -1029,6 +1056,9 @@ int drm_vblank_get(struct drm_device *dev, int crtc)
1029 unsigned long irqflags; 1056 unsigned long irqflags;
1030 int ret = 0; 1057 int ret = 0;
1031 1058
1059 if (!dev->num_crtcs)
1060 return -EINVAL;
1061
1032 if (WARN_ON(crtc >= dev->num_crtcs)) 1062 if (WARN_ON(crtc >= dev->num_crtcs))
1033 return -EINVAL; 1063 return -EINVAL;
1034 1064
@@ -1714,7 +1744,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
1714 */ 1744 */
1715 1745
1716 /* Get current timestamp and count. */ 1746 /* Get current timestamp and count. */
1717 vblcount = atomic_read(&vblank->count); 1747 vblcount = vblank->count;
1718 drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); 1748 drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ);
1719 1749
1720 /* Compute time difference to timestamp of last vblank */ 1750 /* Compute time difference to timestamp of last vblank */
@@ -1730,20 +1760,11 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
1730 * e.g., due to spurious vblank interrupts. We need to 1760 * e.g., due to spurious vblank interrupts. We need to
1731 * ignore those for accounting. 1761 * ignore those for accounting.
1732 */ 1762 */
1733 if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { 1763 if (abs64(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS)
1734 /* Store new timestamp in ringbuffer. */ 1764 store_vblank(dev, crtc, 1, &tvblank);
1735 vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; 1765 else
1736
1737 /* Increment cooked vblank count. This also atomically commits
1738 * the timestamp computed above.
1739 */
1740 smp_mb__before_atomic();
1741 atomic_inc(&vblank->count);
1742 smp_mb__after_atomic();
1743 } else {
1744 DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", 1766 DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n",
1745 crtc, (int) diff_ns); 1767 crtc, (int) diff_ns);
1746 }
1747 1768
1748 spin_unlock(&dev->vblank_time_lock); 1769 spin_unlock(&dev->vblank_time_lock);
1749 1770