OSDN Git Service

vblank: Clean up compensation for spurious wraparounds of driver counter.
authorMichel Dänzer <michel@tungstengraphics.com>
Tue, 3 Jun 2008 09:28:10 +0000 (11:28 +0200)
committerMichel Dänzer <michel@tungstengraphics.com>
Tue, 3 Jun 2008 09:28:10 +0000 (11:28 +0200)
Only compensate when the driver counter actually appears to have moved
backwards.

The compensation deltas need to be incremental instead of absolute; drop the
vblank_offset field and just use atomic_sub().

linux-core/drmP.h
linux-core/drm_irq.c

index 69d31e1..d7b1960 100644 (file)
@@ -840,13 +840,12 @@ struct drm_device {
        atomic_t *vblank_refcount;      /* number of users of vblank interrupts per crtc */
        u32 *last_vblank;               /* protected by dev->vbl_lock, used */
                                        /* for wraparound handling */
-       u32 *vblank_offset;             /* used to track how many vblanks */
        int *vblank_enabled;            /* so we don't call enable more than
                                           once per disable */
-       u32 *vblank_premodeset;         /*  were lost during modeset */
+       u32 *vblank_premodeset;         /* for compensation of spurious wraparounds */
        struct timer_list vblank_disable_timer;
 
-       unsigned long max_vblank_count; /**< size of vblank counter register */
+       u32 max_vblank_count;           /**< size of vblank counter register */
        spinlock_t tasklet_lock;        /**< For drm_locked_tasklet */
        void (*locked_tasklet_func)(struct drm_device *dev);
 
index ccb3ca8..3627a89 100644 (file)
@@ -112,8 +112,6 @@ static void drm_vblank_cleanup(struct drm_device *dev)
                 DRM_MEM_DRIVER);
        drm_free(dev->vblank_premodeset, sizeof(*dev->vblank_premodeset) *
                 dev->num_crtcs, DRM_MEM_DRIVER);
-       drm_free(dev->vblank_offset, sizeof(*dev->vblank_offset) * dev->num_crtcs,
-                DRM_MEM_DRIVER);
 
        dev->num_crtcs = 0;
 }
@@ -162,10 +160,6 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
        if (!dev->vblank_premodeset)
                goto err;
 
-       dev->vblank_offset = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER);
-       if (!dev->vblank_offset)
-               goto err;
-
        /* Zero per-crtc vblank stuff */
        for (i = 0; i < num_crtcs; i++) {
                init_waitqueue_head(&dev->vbl_queue[i]);
@@ -330,8 +324,7 @@ int drm_control(struct drm_device *dev, void *data,
  */
 u32 drm_vblank_count(struct drm_device *dev, int crtc)
 {
-       return atomic_read(&dev->_vblank_count[crtc]) +
-               dev->vblank_offset[crtc];
+       return atomic_read(&dev->_vblank_count[crtc]);
 }
 EXPORT_SYMBOL(drm_vblank_count);
 
@@ -457,7 +450,18 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
                break;
        case _DRM_POST_MODESET:
                new = dev->driver->get_vblank_counter(dev, crtc);
-               dev->vblank_offset[crtc] = dev->vblank_premodeset[crtc] - new;
+
+               /* 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]);
+               }
                break;
        default:
                ret = -EINVAL;