aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2017-03-17 16:20:27 -0400
committerVille Syrjälä <ville.syrjala@linux.intel.com>2017-03-29 06:51:49 -0400
commit43dc7fe2b2118c76fbc2808dec0c57b3158e6dc0 (patch)
tree7259066e9a9a9a7ea41c81f5b637484459ab0c51
parent75cff0837c14eaf632efabb8d7ab9eec6394d20d (diff)
drm: Mark up accesses of vblank->enabled outside of its spinlock
Order the update to vblank->enabled after the timestamp is primed so that a concurrent unlocked reader will only see the vblank->enabled with the current timestamp. v2: vblank->enable is guarded by dev->vbl_lock not dev->vblank_time_lock, update the READ_ONCE accordingly. Do not add a READ_ONCE(vblank->enabled) inside the interrupt handler to avoid missing an interrupt whilst racing with enable_vblank() Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/20170317202030.24410-1-chris@chris-wilson.co.uk Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
-rw-r--r--drivers/gpu/drm/drm_irq.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 290e65b93a65..372085561f02 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -325,6 +325,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
325 struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 325 struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
326 unsigned long irqflags; 326 unsigned long irqflags;
327 327
328 assert_spin_locked(&dev->vbl_lock);
329
328 /* Prevent vblank irq processing while disabling vblank irqs, 330 /* Prevent vblank irq processing while disabling vblank irqs,
329 * so no updates of timestamps or count can happen after we've 331 * so no updates of timestamps or count can happen after we've
330 * disabled. Needed to prevent races in case of delayed irq's. 332 * disabled. Needed to prevent races in case of delayed irq's.
@@ -336,10 +338,8 @@ static void vblank_disable_and_save(struct drm_device *dev, unsigned int pipe)
336 * calling the ->disable_vblank() operation in atomic context with the 338 * calling the ->disable_vblank() operation in atomic context with the
337 * hardware potentially runtime suspended. 339 * hardware potentially runtime suspended.
338 */ 340 */
339 if (vblank->enabled) { 341 if (cmpxchg_relaxed(&vblank->enabled, true, false))
340 __disable_vblank(dev, pipe); 342 __disable_vblank(dev, pipe);
341 vblank->enabled = false;
342 }
343 343
344 /* 344 /*
345 * Always update the count and timestamp to maintain the 345 * Always update the count and timestamp to maintain the
@@ -384,7 +384,7 @@ void drm_vblank_cleanup(struct drm_device *dev)
384 for (pipe = 0; pipe < dev->num_crtcs; pipe++) { 384 for (pipe = 0; pipe < dev->num_crtcs; pipe++) {
385 struct drm_vblank_crtc *vblank = &dev->vblank[pipe]; 385 struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
386 386
387 WARN_ON(vblank->enabled && 387 WARN_ON(READ_ONCE(vblank->enabled) &&
388 drm_core_check_feature(dev, DRIVER_MODESET)); 388 drm_core_check_feature(dev, DRIVER_MODESET));
389 389
390 del_timer_sync(&vblank->disable_timer); 390 del_timer_sync(&vblank->disable_timer);
@@ -1097,11 +1097,16 @@ static int drm_vblank_enable(struct drm_device *dev, unsigned int pipe)
1097 */ 1097 */
1098 ret = __enable_vblank(dev, pipe); 1098 ret = __enable_vblank(dev, pipe);
1099 DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret); 1099 DRM_DEBUG("enabling vblank on crtc %u, ret: %d\n", pipe, ret);
1100 if (ret) 1100 if (ret) {
1101 atomic_dec(&vblank->refcount); 1101 atomic_dec(&vblank->refcount);
1102 else { 1102 } else {
1103 vblank->enabled = true;
1104 drm_update_vblank_count(dev, pipe, 0); 1103 drm_update_vblank_count(dev, pipe, 0);
1104 /* drm_update_vblank_count() includes a wmb so we just
1105 * need to ensure that the compiler emits the write
1106 * to mark the vblank as enabled after the call
1107 * to drm_update_vblank_count().
1108 */
1109 WRITE_ONCE(vblank->enabled, true);
1105 } 1110 }
1106 } 1111 }
1107 1112
@@ -1509,7 +1514,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
1509 * vblank disable, so no need for further locking. The reference from 1514 * vblank disable, so no need for further locking. The reference from
1510 * drm_vblank_get() protects against vblank disable from another source. 1515 * drm_vblank_get() protects against vblank disable from another source.
1511 */ 1516 */
1512 if (!vblank->enabled) { 1517 if (!READ_ONCE(vblank->enabled)) {
1513 ret = -EINVAL; 1518 ret = -EINVAL;
1514 goto err_unlock; 1519 goto err_unlock;
1515 } 1520 }
@@ -1636,7 +1641,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data,
1636 DRM_WAIT_ON(ret, vblank->queue, 3 * HZ, 1641 DRM_WAIT_ON(ret, vblank->queue, 3 * HZ,
1637 (((drm_vblank_count(dev, pipe) - 1642 (((drm_vblank_count(dev, pipe) -
1638 vblwait->request.sequence) <= (1 << 23)) || 1643 vblwait->request.sequence) <= (1 << 23)) ||
1639 !vblank->enabled || 1644 !READ_ONCE(vblank->enabled) ||
1640 !dev->irq_enabled)); 1645 !dev->irq_enabled));
1641 } 1646 }
1642 1647