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.c73
1 files changed, 70 insertions, 3 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index d12a4efa651b..1fe14579e8c9 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -224,6 +224,64 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
224 diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0; 224 diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
225 } 225 }
226 226
227 /*
228 * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
229 * interval? If so then vblank irqs keep running and it will likely
230 * happen that the hardware vblank counter is not trustworthy as it
231 * might reset at some point in that interval and vblank timestamps
232 * are not trustworthy either in that interval. Iow. this can result
233 * in a bogus diff >> 1 which must be avoided as it would cause
234 * random large forward jumps of the software vblank counter.
235 */
236 if (diff > 1 && (vblank->inmodeset & 0x2)) {
237 DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u"
238 " due to pre-modeset.\n", pipe, diff);
239 diff = 1;
240 }
241
242 /*
243 * FIMXE: Need to replace this hack with proper seqlocks.
244 *
245 * Restrict the bump of the software vblank counter to a safe maximum
246 * value of +1 whenever there is the possibility that concurrent readers
247 * of vblank timestamps could be active at the moment, as the current
248 * implementation of the timestamp caching and updating is not safe
249 * against concurrent readers for calls to store_vblank() with a bump
250 * of anything but +1. A bump != 1 would very likely return corrupted
251 * timestamps to userspace, because the same slot in the cache could
252 * be concurrently written by store_vblank() and read by one of those
253 * readers without the read-retry logic detecting the collision.
254 *
255 * Concurrent readers can exist when we are called from the
256 * drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
257 * irq callers. However, all those calls to us are happening with the
258 * vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
259 * can't increase while we are executing. Therefore a zero refcount at
260 * this point is safe for arbitrary counter bumps if we are called
261 * outside vblank irq, a non-zero count is not 100% safe. Unfortunately
262 * we must also accept a refcount of 1, as whenever we are called from
263 * drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
264 * we must let that one pass through in order to not lose vblank counts
265 * during vblank irq off - which would completely defeat the whole
266 * point of this routine.
267 *
268 * Whenever we are called from vblank irq, we have to assume concurrent
269 * readers exist or can show up any time during our execution, even if
270 * the refcount is currently zero, as vblank irqs are usually only
271 * enabled due to the presence of readers, and because when we are called
272 * from vblank irq we can't hold the vbl_lock to protect us from sudden
273 * bumps in vblank refcount. Therefore also restrict bumps to +1 when
274 * called from vblank irq.
275 */
276 if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
277 (flags & DRM_CALLED_FROM_VBLIRQ))) {
278 DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
279 "refcount %u, vblirq %u\n", pipe, diff,
280 atomic_read(&vblank->refcount),
281 (flags & DRM_CALLED_FROM_VBLIRQ) != 0);
282 diff = 1;
283 }
284
227 DRM_DEBUG_VBL("updating vblank count on crtc %u:" 285 DRM_DEBUG_VBL("updating vblank count on crtc %u:"
228 " current=%u, diff=%u, hw=%u hw_last=%u\n", 286 " current=%u, diff=%u, hw=%u hw_last=%u\n",
229 pipe, vblank->count, diff, cur_vblank, vblank->last); 287 pipe, vblank->count, diff, cur_vblank, vblank->last);
@@ -1316,7 +1374,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
1316 spin_lock_irqsave(&dev->event_lock, irqflags); 1374 spin_lock_irqsave(&dev->event_lock, irqflags);
1317 1375
1318 spin_lock(&dev->vbl_lock); 1376 spin_lock(&dev->vbl_lock);
1319 vblank_disable_and_save(dev, pipe); 1377 DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
1378 pipe, vblank->enabled, vblank->inmodeset);
1379
1380 /* Avoid redundant vblank disables without previous drm_vblank_on(). */
1381 if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset)
1382 vblank_disable_and_save(dev, pipe);
1383
1320 wake_up(&vblank->queue); 1384 wake_up(&vblank->queue);
1321 1385
1322 /* 1386 /*
@@ -1418,6 +1482,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
1418 return; 1482 return;
1419 1483
1420 spin_lock_irqsave(&dev->vbl_lock, irqflags); 1484 spin_lock_irqsave(&dev->vbl_lock, irqflags);
1485 DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
1486 pipe, vblank->enabled, vblank->inmodeset);
1487
1421 /* Drop our private "prevent drm_vblank_get" refcount */ 1488 /* Drop our private "prevent drm_vblank_get" refcount */
1422 if (vblank->inmodeset) { 1489 if (vblank->inmodeset) {
1423 atomic_dec(&vblank->refcount); 1490 atomic_dec(&vblank->refcount);
@@ -1430,8 +1497,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
1430 * re-enable interrupts if there are users left, or the 1497 * re-enable interrupts if there are users left, or the
1431 * user wishes vblank interrupts to be enabled all the time. 1498 * user wishes vblank interrupts to be enabled all the time.
1432 */ 1499 */
1433 if (atomic_read(&vblank->refcount) != 0 || 1500 if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0)
1434 (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
1435 WARN_ON(drm_vblank_enable(dev, pipe)); 1501 WARN_ON(drm_vblank_enable(dev, pipe));
1436 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 1502 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
1437} 1503}
@@ -1526,6 +1592,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe)
1526 if (vblank->inmodeset) { 1592 if (vblank->inmodeset) {
1527 spin_lock_irqsave(&dev->vbl_lock, irqflags); 1593 spin_lock_irqsave(&dev->vbl_lock, irqflags);
1528 dev->vblank_disable_allowed = true; 1594 dev->vblank_disable_allowed = true;
1595 drm_reset_vblank_timestamp(dev, pipe);
1529 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 1596 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
1530 1597
1531 if (vblank->inmodeset & 0x2) 1598 if (vblank->inmodeset & 0x2)