Additional vblank cleanups.
authorHasso Tepper <hasso@estpak.ee>
Thu, 25 Jun 2009 18:28:47 +0000 (21:28 +0300)
committerHasso Tepper <hasso@estpak.ee>
Thu, 25 Jun 2009 21:27:58 +0000 (00:27 +0300)
Use the vbl_lock when manipulating the refcount.  Eventually I want to
convert this to use our internal refcount code.  Continue to use atomic
ops for manipulating vblank count since we access it often just for
reading.

Obtained-from: FreeBSD

sys/dev/drm/drm_irq.c

index 7d5a2e1..c805240 100644 (file)
@@ -123,13 +123,14 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
        DRM_DEBUG("\n");
 
        /* Zero per-crtc vblank stuff */
+       DRM_SPINLOCK(&dev->vbl_lock);
        for (i = 0; i < num_crtcs; i++) {
                DRM_INIT_WAITQUEUE(&dev->vblank[i].queue);
-               atomic_set(&dev->vblank[i].count, 0);
-               atomic_set(&dev->vblank[i].refcount, 0);
+               dev->vblank[i].refcount = 0;
+               atomic_set_rel_32(&dev->vblank[i].count, 0);
        }
-
        dev->vblank_disable_allowed = 0;
+       DRM_SPINUNLOCK(&dev->vbl_lock);
 
        return 0;
 
@@ -256,7 +257,7 @@ int drm_control(struct drm_device *dev, void *data, struct drm_file *file_priv)
 
 u32 drm_vblank_count(struct drm_device *dev, int crtc)
 {
-       return atomic_read(&dev->vblank[crtc].count);
+       return atomic_load_acq_32(&dev->vblank[crtc].count);
 }
 
 static void drm_update_vblank_count(struct drm_device *dev, int crtc)
@@ -282,45 +283,44 @@ static 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[crtc].count);
+       atomic_add_rel_32(&dev->vblank[crtc].count, diff);
 }
 
 int drm_vblank_get(struct drm_device *dev, int crtc)
 {
        int ret = 0;
 
-       DRM_SPINLOCK(&dev->vbl_lock);
+       /* Make sure that we are called with the lock held */
+       KKASSERT(lockstatus(&dev->vbl_lock, curthread) != 0);
+
        /* Going from 0->1 means we have to enable interrupts again */
-       atomic_add_acq_int(&dev->vblank[crtc].refcount, 1);
-       if (dev->vblank[crtc].refcount == 1 &&
+       if (++dev->vblank[crtc].refcount == 1 &&
            !dev->vblank[crtc].enabled) {
                ret = dev->driver->enable_vblank(dev, crtc);
                DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret);
                if (ret)
-                       atomic_dec(&dev->vblank[crtc].refcount);
+                       --dev->vblank[crtc].refcount;
                else {
                        dev->vblank[crtc].enabled = 1;
                        drm_update_vblank_count(dev, crtc);
                }
        }
-       DRM_SPINUNLOCK(&dev->vbl_lock);
 
        return ret;
 }
 
 void drm_vblank_put(struct drm_device *dev, int crtc)
 {
-       KASSERT(atomic_read(&dev->vblank[crtc].refcount) > 0,
+       /* Make sure that we are called with the lock held */
+       KKASSERT(lockstatus(&dev->vbl_lock, curthread) != 0);
+
+       KASSERT(dev->vblank[crtc].refcount > 0,
            ("invalid refcount"));
 
        /* Last user schedules interrupt disable */
-       atomic_subtract_acq_int(&dev->vblank[crtc].refcount, 1);
-
-       DRM_SPINLOCK(&dev->vbl_lock);
-       if (dev->vblank[crtc].refcount == 0)
+       if (--dev->vblank[crtc].refcount == 0)
            callout_reset(&dev->vblank_disable_timer, 5 * DRM_HZ,
                (timeout_t *)vblank_disable_fn, (void *)dev);
-       DRM_SPINUNLOCK(&dev->vbl_lock);
 }
 
 int drm_modeset_ctl(struct drm_device *dev, void *data,
@@ -329,13 +329,11 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
        struct drm_modeset_ctl *modeset = data;
        int crtc, ret = 0;
 
-       DRM_DEBUG("num_crtcs=%d\n", dev->num_crtcs);
        /* If drm_vblank_init() hasn't been called yet, just no-op */
        if (!dev->num_crtcs)
                goto out;
 
        crtc = modeset->crtc;
-       DRM_DEBUG("crtc=%d\n", crtc);
        if (crtc >= dev->num_crtcs) {
                ret = EINVAL;
                goto out;
@@ -350,25 +348,25 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
         */
        switch (modeset->cmd) {
        case _DRM_PRE_MODESET:
-               DRM_DEBUG("pre-modeset\n");
+               DRM_DEBUG("pre-modeset, crtc %d\n", crtc);
+               DRM_SPINLOCK(&dev->vbl_lock);
                if (!dev->vblank[crtc].inmodeset) {
                        dev->vblank[crtc].inmodeset = 0x1;
                        if (drm_vblank_get(dev, crtc) == 0)
                                dev->vblank[crtc].inmodeset |= 0x2;
                }
+               DRM_SPINUNLOCK(&dev->vbl_lock);
                break;
        case _DRM_POST_MODESET:
-               DRM_DEBUG("post-modeset\n");
+               DRM_DEBUG("post-modeset, crtc %d\n", crtc);
+               DRM_SPINLOCK(&dev->vbl_lock);
                if (dev->vblank[crtc].inmodeset) {
-                       DRM_SPINLOCK(&dev->vbl_lock);
-                       dev->vblank_disable_allowed = 1;
-                       DRM_SPINUNLOCK(&dev->vbl_lock);
-
                        if (dev->vblank[crtc].inmodeset & 0x2)
                                drm_vblank_put(dev, crtc);
-
                        dev->vblank[crtc].inmodeset = 0;
                }
+               dev->vblank_disable_allowed = 1;
+               DRM_SPINUNLOCK(&dev->vbl_lock);
                break;
        default:
                ret = EINVAL;
@@ -402,7 +400,9 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
        if (crtc >= dev->num_crtcs)
                return EINVAL;
 
+       DRM_SPINLOCK(&dev->vbl_lock);
        ret = drm_vblank_get(dev, crtc);
+       DRM_SPINUNLOCK(&dev->vbl_lock);
        if (ret) {
                DRM_ERROR("failed to acquire vblank counter, %d\n", ret);
                return ret;
@@ -459,13 +459,16 @@ int drm_wait_vblank(struct drm_device *dev, void *data, struct drm_file *file_pr
        }
 
 done:
+       DRM_SPINLOCK(&dev->vbl_lock);
        drm_vblank_put(dev, crtc);
+       DRM_SPINUNLOCK(&dev->vbl_lock);
+
        return ret;
 }
 
 void drm_handle_vblank(struct drm_device *dev, int crtc)
 {
-       atomic_inc(&dev->vblank[crtc].count);
+       atomic_add_rel_32(&dev->vblank[crtc].count, 1);
        DRM_WAKEUP(&dev->vblank[crtc].queue);
 }