Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[pandora-kernel.git] / drivers / char / drm / drm_lock.c
index b276ae8..e9993ba 100644 (file)
@@ -104,6 +104,10 @@ int drm_lock(struct inode *inode, struct file *filp,
        __set_current_state(TASK_RUNNING);
        remove_wait_queue(&dev->lock.lock_queue, &entry);
 
+       DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+       if (ret)
+               return ret;
+
        sigemptyset(&dev->sigmask);
        sigaddset(&dev->sigmask, SIGSTOP);
        sigaddset(&dev->sigmask, SIGTSTP);
@@ -116,21 +120,22 @@ int drm_lock(struct inode *inode, struct file *filp,
        if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
                dev->driver->dma_ready(dev);
 
-       if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT))
-               return dev->driver->dma_quiescent(dev);
+       if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT)) {
+               if (dev->driver->dma_quiescent(dev)) {
+                       DRM_DEBUG("%d waiting for DMA quiescent\n", lock.context);
+                       return DRM_ERR(EBUSY);
+               }
+       }
 
        /* dev->driver->kernel_context_switch isn't used by any of the x86
         *  drivers but is used by the Sparc driver.
         */
-
        if (dev->driver->kernel_context_switch &&
            dev->last_context != lock.context) {
                dev->driver->kernel_context_switch(dev, dev->last_context,
                                                   lock.context);
        }
-       DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
-
-       return ret;
+       return 0;
 }
 
 /**
@@ -150,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
        drm_file_t *priv = filp->private_data;
        drm_device_t *dev = priv->head->dev;
        drm_lock_t lock;
+       unsigned long irqflags;
 
        if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
                return -EFAULT;
@@ -160,13 +166,23 @@ int drm_unlock(struct inode *inode, struct file *filp,
                return -EINVAL;
        }
 
+       spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+
+       if (dev->locked_tasklet_func) {
+               dev->locked_tasklet_func(dev);
+
+               dev->locked_tasklet_func = NULL;
+       }
+
+       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+
        atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
 
        /* kernel_context_switch isn't used by any of the x86 drm
         * modules but is required by the Sparc driver.
         */
        if (dev->driver->kernel_context_switch_unlock)
-               dev->driver->kernel_context_switch_unlock(dev, &lock);
+               dev->driver->kernel_context_switch_unlock(dev);
        else {
                drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
                                  DRM_KERNEL_CONTEXT);