aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_irq.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-03-13 19:42:34 -0400
committerDave Airlie <airlied@redhat.com>2016-03-13 19:46:02 -0400
commit9b61c0fcdf0cfd20a85d9856d46142e7f297de0a (patch)
treed4abe6aa3f4e1e088f9da1d0597e078b1fe58912 /drivers/gpu/drm/drm_irq.c
parent550e3b23a53c88adfa46e64f9d442743e65d47da (diff)
parent125234dc8b1cc862f52d8bd5b37c36cc59b2cb86 (diff)
Merge drm-fixes into drm-next.
Nouveau wanted this to avoid some worse conflicts when I merge that.
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 96d03ac38ef7..881c5a6c180c 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);
@@ -1313,7 +1371,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
1313 spin_lock_irqsave(&dev->event_lock, irqflags); 1371 spin_lock_irqsave(&dev->event_lock, irqflags);
1314 1372
1315 spin_lock(&dev->vbl_lock); 1373 spin_lock(&dev->vbl_lock);
1316 vblank_disable_and_save(dev, pipe); 1374 DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
1375 pipe, vblank->enabled, vblank->inmodeset);
1376
1377 /* Avoid redundant vblank disables without previous drm_vblank_on(). */
1378 if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset)
1379 vblank_disable_and_save(dev, pipe);
1380
1317 wake_up(&vblank->queue); 1381 wake_up(&vblank->queue);
1318 1382
1319 /* 1383 /*
@@ -1415,6 +1479,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
1415 return; 1479 return;
1416 1480
1417 spin_lock_irqsave(&dev->vbl_lock, irqflags); 1481 spin_lock_irqsave(&dev->vbl_lock, irqflags);
1482 DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
1483 pipe, vblank->enabled, vblank->inmodeset);
1484
1418 /* Drop our private "prevent drm_vblank_get" refcount */ 1485 /* Drop our private "prevent drm_vblank_get" refcount */
1419 if (vblank->inmodeset) { 1486 if (vblank->inmodeset) {
1420 atomic_dec(&vblank->refcount); 1487 atomic_dec(&vblank->refcount);
@@ -1427,8 +1494,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
1427 * re-enable interrupts if there are users left, or the 1494 * re-enable interrupts if there are users left, or the
1428 * user wishes vblank interrupts to be enabled all the time. 1495 * user wishes vblank interrupts to be enabled all the time.
1429 */ 1496 */
1430 if (atomic_read(&vblank->refcount) != 0 || 1497 if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0)
1431 (!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
1432 WARN_ON(drm_vblank_enable(dev, pipe)); 1498 WARN_ON(drm_vblank_enable(dev, pipe));
1433 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 1499 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
1434} 1500}
@@ -1523,6 +1589,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe)
1523 if (vblank->inmodeset) { 1589 if (vblank->inmodeset) {
1524 spin_lock_irqsave(&dev->vbl_lock, irqflags); 1590 spin_lock_irqsave(&dev->vbl_lock, irqflags);
1525 dev->vblank_disable_allowed = true; 1591 dev->vblank_disable_allowed = true;
1592 drm_reset_vblank_timestamp(dev, pipe);
1526 spin_unlock_irqrestore(&dev->vbl_lock, irqflags); 1593 spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
1527 1594
1528 if (vblank->inmodeset & 0x2) 1595 if (vblank->inmodeset & 0x2)