diff options
author | Dave Airlie <airlied@redhat.com> | 2016-03-13 19:42:34 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-03-13 19:46:02 -0400 |
commit | 9b61c0fcdf0cfd20a85d9856d46142e7f297de0a (patch) | |
tree | d4abe6aa3f4e1e088f9da1d0597e078b1fe58912 /drivers/gpu/drm/drm_irq.c | |
parent | 550e3b23a53c88adfa46e64f9d442743e65d47da (diff) | |
parent | 125234dc8b1cc862f52d8bd5b37c36cc59b2cb86 (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.c | 73 |
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) |