Merge branch 'upstream-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/linvil...
[pandora-kernel.git] / drivers / char / drm / drm_irq.c
index b08608a..9d00c51 100644 (file)
@@ -250,8 +250,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
        drm_wait_vblank_t vblwait;
        struct timeval now;
        int ret = 0;
-       unsigned int flags;
-       atomic_t *seq;
+       unsigned int flags, seq;
 
        if (!dev->irq)
                return -EINVAL;
@@ -273,12 +272,12 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
                                    DRIVER_IRQ_VBL2 : DRIVER_IRQ_VBL))
                return -EINVAL;
 
-       seq = (flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2 :
-             &dev->vbl_received;
+       seq = atomic_read((flags & _DRM_VBLANK_SECONDARY) ? &dev->vbl_received2
+                         : &dev->vbl_received);
 
        switch (vblwait.request.type & _DRM_VBLANK_TYPES_MASK) {
        case _DRM_VBLANK_RELATIVE:
-               vblwait.request.sequence += atomic_read(seq);
+               vblwait.request.sequence += seq;
                vblwait.request.type &= ~_DRM_VBLANK_RELATIVE;
        case _DRM_VBLANK_ABSOLUTE:
                break;
@@ -286,14 +285,17 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
                return -EINVAL;
        }
 
+       if ((flags & _DRM_VBLANK_NEXTONMISS) &&
+           (seq - vblwait.request.sequence) <= (1<<23)) {
+               vblwait.request.sequence = seq + 1;
+       }
+
        if (flags & _DRM_VBLANK_SIGNAL) {
                unsigned long irqflags;
                drm_vbl_sig_t *vbl_sigs = (flags & _DRM_VBLANK_SECONDARY)
                                      ? &dev->vbl_sigs2 : &dev->vbl_sigs;
                drm_vbl_sig_t *vbl_sig;
 
-               vblwait.reply.sequence = atomic_read(seq);
-
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
 
                /* Check if this task has already scheduled the same signal
@@ -306,6 +308,7 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
                            && vbl_sig->task == current) {
                                spin_unlock_irqrestore(&dev->vbl_lock,
                                                       irqflags);
+                               vblwait.reply.sequence = seq;
                                goto done;
                        }
                }
@@ -336,6 +339,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
                list_add_tail((struct list_head *)vbl_sig, &vbl_sigs->head);
 
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+
+               vblwait.reply.sequence = seq;
        } else {
                if (flags & _DRM_VBLANK_SECONDARY) {
                        if (dev->driver->vblank_wait2)