Merge drm-fixes into drm-next.
Nouveau wanted this to avoid some worse conflicts when I merge that.
This commit is contained in:
@@ -224,6 +224,64 @@ static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
|
||||
diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
|
||||
* interval? If so then vblank irqs keep running and it will likely
|
||||
* happen that the hardware vblank counter is not trustworthy as it
|
||||
* might reset at some point in that interval and vblank timestamps
|
||||
* are not trustworthy either in that interval. Iow. this can result
|
||||
* in a bogus diff >> 1 which must be avoided as it would cause
|
||||
* random large forward jumps of the software vblank counter.
|
||||
*/
|
||||
if (diff > 1 && (vblank->inmodeset & 0x2)) {
|
||||
DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u"
|
||||
" due to pre-modeset.\n", pipe, diff);
|
||||
diff = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIMXE: Need to replace this hack with proper seqlocks.
|
||||
*
|
||||
* Restrict the bump of the software vblank counter to a safe maximum
|
||||
* value of +1 whenever there is the possibility that concurrent readers
|
||||
* of vblank timestamps could be active at the moment, as the current
|
||||
* implementation of the timestamp caching and updating is not safe
|
||||
* against concurrent readers for calls to store_vblank() with a bump
|
||||
* of anything but +1. A bump != 1 would very likely return corrupted
|
||||
* timestamps to userspace, because the same slot in the cache could
|
||||
* be concurrently written by store_vblank() and read by one of those
|
||||
* readers without the read-retry logic detecting the collision.
|
||||
*
|
||||
* Concurrent readers can exist when we are called from the
|
||||
* drm_vblank_off() or drm_vblank_on() functions and other non-vblank-
|
||||
* irq callers. However, all those calls to us are happening with the
|
||||
* vbl_lock locked to prevent drm_vblank_get(), so the vblank refcount
|
||||
* can't increase while we are executing. Therefore a zero refcount at
|
||||
* this point is safe for arbitrary counter bumps if we are called
|
||||
* outside vblank irq, a non-zero count is not 100% safe. Unfortunately
|
||||
* we must also accept a refcount of 1, as whenever we are called from
|
||||
* drm_vblank_get() -> drm_vblank_enable() the refcount will be 1 and
|
||||
* we must let that one pass through in order to not lose vblank counts
|
||||
* during vblank irq off - which would completely defeat the whole
|
||||
* point of this routine.
|
||||
*
|
||||
* Whenever we are called from vblank irq, we have to assume concurrent
|
||||
* readers exist or can show up any time during our execution, even if
|
||||
* the refcount is currently zero, as vblank irqs are usually only
|
||||
* enabled due to the presence of readers, and because when we are called
|
||||
* from vblank irq we can't hold the vbl_lock to protect us from sudden
|
||||
* bumps in vblank refcount. Therefore also restrict bumps to +1 when
|
||||
* called from vblank irq.
|
||||
*/
|
||||
if ((diff > 1) && (atomic_read(&vblank->refcount) > 1 ||
|
||||
(flags & DRM_CALLED_FROM_VBLIRQ))) {
|
||||
DRM_DEBUG_VBL("clamping vblank bump to 1 on crtc %u: diffr=%u "
|
||||
"refcount %u, vblirq %u\n", pipe, diff,
|
||||
atomic_read(&vblank->refcount),
|
||||
(flags & DRM_CALLED_FROM_VBLIRQ) != 0);
|
||||
diff = 1;
|
||||
}
|
||||
|
||||
DRM_DEBUG_VBL("updating vblank count on crtc %u:"
|
||||
" current=%u, diff=%u, hw=%u hw_last=%u\n",
|
||||
pipe, vblank->count, diff, cur_vblank, vblank->last);
|
||||
@@ -1313,7 +1371,13 @@ void drm_vblank_off(struct drm_device *dev, unsigned int pipe)
|
||||
spin_lock_irqsave(&dev->event_lock, irqflags);
|
||||
|
||||
spin_lock(&dev->vbl_lock);
|
||||
vblank_disable_and_save(dev, pipe);
|
||||
DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
|
||||
pipe, vblank->enabled, vblank->inmodeset);
|
||||
|
||||
/* Avoid redundant vblank disables without previous drm_vblank_on(). */
|
||||
if (drm_core_check_feature(dev, DRIVER_ATOMIC) || !vblank->inmodeset)
|
||||
vblank_disable_and_save(dev, pipe);
|
||||
|
||||
wake_up(&vblank->queue);
|
||||
|
||||
/*
|
||||
@@ -1415,6 +1479,9 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
DRM_DEBUG_VBL("crtc %d, vblank enabled %d, inmodeset %d\n",
|
||||
pipe, vblank->enabled, vblank->inmodeset);
|
||||
|
||||
/* Drop our private "prevent drm_vblank_get" refcount */
|
||||
if (vblank->inmodeset) {
|
||||
atomic_dec(&vblank->refcount);
|
||||
@@ -1427,8 +1494,7 @@ void drm_vblank_on(struct drm_device *dev, unsigned int pipe)
|
||||
* re-enable interrupts if there are users left, or the
|
||||
* user wishes vblank interrupts to be enabled all the time.
|
||||
*/
|
||||
if (atomic_read(&vblank->refcount) != 0 ||
|
||||
(!dev->vblank_disable_immediate && drm_vblank_offdelay == 0))
|
||||
if (atomic_read(&vblank->refcount) != 0 || drm_vblank_offdelay == 0)
|
||||
WARN_ON(drm_vblank_enable(dev, pipe));
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
}
|
||||
@@ -1523,6 +1589,7 @@ void drm_vblank_post_modeset(struct drm_device *dev, unsigned int pipe)
|
||||
if (vblank->inmodeset) {
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
dev->vblank_disable_allowed = true;
|
||||
drm_reset_vblank_timestamp(dev, pipe);
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
|
||||
if (vblank->inmodeset & 0x2)
|
||||
|
Reference in New Issue
Block a user