diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 75e53da..9f09221 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -343,29 +343,10 @@ u32 drm_vblank_count(struct drm_device *dev, int crtc) } EXPORT_SYMBOL(drm_vblank_count); -/** - * drm_update_vblank_count - update the master vblank counter - * @dev: DRM device - * @crtc: counter to update - * - * Call back into the driver to update the appropriate vblank counter - * (specified by @crtc). Deal with wraparound, if it occurred, and - * update the last read value so we can deal with wraparound on the next - * call if necessary. - * - * Only necessary when going from off->on, to account for frames we - * didn't get an interrupt for. - * - * Note: caller must hold dev->vbl_lock since this reads & writes - * device vblank fields. - */ -void drm_update_vblank_count(struct drm_device *dev, int crtc) +void do_update_vblank_count(struct drm_device *dev, int crtc) { u32 cur_vblank, diff; - if (dev->vblank_suspend[crtc]) - return; - /* * Interrupts were disabled prior to this call, so deal with counter * wrap if needed. @@ -392,11 +373,39 @@ void drm_update_vblank_count(struct drm_device *dev, int crtc) DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", crtc, diff); - atomic_add(diff, &dev->_vblank_count[crtc]); } /** + * drm_update_vblank_count - update the master vblank counter + * @dev: DRM device + * @crtc: counter to update + * + * Call back into the driver to update the appropriate vblank counter + * (specified by @crtc). Deal with wraparound, if it occurred, and + * update the last read value so we can deal with wraparound on the next + * call if necessary. + * + * Only necessary when going from off->on, to account for frames we + * didn't get an interrupt for. + * + * Note: caller must hold dev->vbl_lock since this reads & writes + * device vblank fields. + */ +void drm_update_vblank_count(struct drm_device *dev, int crtc) +{ + unsigned long irqflags; + + if (dev->vblank_suspend[crtc] || dev->vblank_enabled[crtc]) + return; + + spin_lock_irqsave(&dev->vbl_lock, irqflags); + do_update_vblank_count(dev, crtc); + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); +} +EXPORT_SYMBOL(drm_update_vblank_count); + +/** * drm_vblank_get - get a reference count on vblank events * @dev: DRM device * @crtc: which CRTC to own @@ -420,8 +429,8 @@ int drm_vblank_get(struct drm_device *dev, int crtc) if (ret) atomic_dec(&dev->vblank_refcount[crtc]); else { + do_update_vblank_count(dev, crtc); dev->vblank_enabled[crtc] = 1; - drm_update_vblank_count(dev, crtc); } } spin_unlock_irqrestore(&dev->vbl_lock, irqflags); @@ -462,8 +471,6 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_modeset_ctl *modeset = data; - unsigned long irqflags; - u32 new, diff; int crtc, ret = 0; crtc = modeset->crtc; @@ -474,28 +481,26 @@ int drm_modeset_ctl(struct drm_device *dev, void *data, switch (modeset->cmd) { case _DRM_PRE_MODESET: - spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - if (!dev->vblank_enabled[crtc]) { - dev->vblank_premodeset[crtc] = - dev->driver->get_vblank_counter(dev, crtc); - dev->vblank_suspend[crtc] = 1; - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + dev->vblank_premodeset[crtc] = + dev->driver->get_vblank_counter(dev, crtc); + dev->vblank_suspend[crtc] = 1; break; case _DRM_POST_MODESET: - spin_lock_irqsave(&dev->vbl_lock, irqflags); - dev->vblank_disable_allowed = 1; - new = dev->driver->get_vblank_counter(dev, crtc); - if (dev->vblank_suspend[crtc] && !dev->vblank_enabled[crtc]) { - if (new > dev->vblank_premodeset[crtc]) - diff = dev->vblank_premodeset[crtc] - new; - else - diff = new; - atomic_add(diff, &dev->_vblank_count[crtc]); + if (dev->vblank_suspend[crtc]) { + u32 new = dev->driver->get_vblank_counter(dev, crtc); + + /* Compensate for spurious wraparound */ + if (new < dev->vblank_premodeset[crtc]) { + atomic_sub(dev->max_vblank_count + new - + dev->vblank_premodeset[crtc], + &dev->_vblank_count[crtc]); + DRM_DEBUG("vblank_premodeset[%d]=0x%x, new=0x%x" + " => _vblank_count[%d]-=0x%x\n", crtc, + dev->vblank_premodeset[crtc], new, + crtc, dev->max_vblank_count + new - + dev->vblank_premodeset[crtc]); + } } - dev->vblank_suspend[crtc] = 0; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); break; default: ret = -EINVAL; @@ -549,6 +554,7 @@ int drm_wait_vblank(struct drm_device *dev, void *data, if (crtc >= dev->num_crtcs) return -EINVAL; + drm_update_vblank_count(dev, crtc); seq = drm_vblank_count(dev, crtc); switch (vblwait->request.type & _DRM_VBLANK_TYPES_MASK) { diff --git a/shared-core/i915_irq.c b/shared-core/i915_irq.c index ecb2d7f..713759e 100644 --- a/shared-core/i915_irq.c +++ b/shared-core/i915_irq.c @@ -769,6 +769,7 @@ int i915_vblank_swap(struct drm_device *dev, void *data, DRM_SPINUNLOCK_IRQRESTORE(&dev->drw_lock, irqflags); + drm_update_vblank_count(dev, pipe); curseq = drm_vblank_count(dev, pipe); if (seqtype == _DRM_VBLANK_RELATIVE)