Don't call the vblank tasklet with irqs disabled.
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Wed, 13 Aug 2008 08:04:21 +0000 (10:04 +0200)
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>
Wed, 13 Aug 2008 08:04:21 +0000 (10:04 +0200)
If a specific tasklet shares data with irq context,
it needs to take a private irq-blocking spinlock within
the tasklet itself.

linux-core/drm_irq.c
linux-core/drm_lock.c

index 5b9f474..57419ca 100644 (file)
@@ -705,27 +705,31 @@ static void drm_locked_tasklet_func(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
        unsigned long irqflags;
-
+       void (*tasklet_func)(struct drm_device *);
+       
        spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+       tasklet_func = dev->locked_tasklet_func;
+       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
 
-       if (!dev->locked_tasklet_func ||
+       if (!tasklet_func ||
            !drm_lock_take(&dev->lock,
                           DRM_KERNEL_CONTEXT)) {
-               spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
                return;
        }
 
        dev->lock.lock_time = jiffies;
        atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
 
-       dev->locked_tasklet_func(dev);
+       spin_lock_irqsave(&dev->tasklet_lock, irqflags);
+       tasklet_func = dev->locked_tasklet_func;
+       dev->locked_tasklet_func = NULL;
+       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+       
+       if (tasklet_func != NULL)
+               tasklet_func(dev);
 
        drm_lock_free(&dev->lock,
                      DRM_KERNEL_CONTEXT);
-
-       dev->locked_tasklet_func = NULL;
-
-       spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
 }
 
 /**
index a2966ef..cad2e44 100644 (file)
@@ -155,6 +155,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
        struct drm_lock *lock = data;
        unsigned long irqflags;
+       void (*tasklet_func)(struct drm_device *);
 
        if (lock->context == DRM_KERNEL_CONTEXT) {
                DRM_ERROR("Process %d using kernel context %d\n",
@@ -163,14 +164,11 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
        }
 
        spin_lock_irqsave(&dev->tasklet_lock, irqflags);
-
-       if (dev->locked_tasklet_func) {
-               dev->locked_tasklet_func(dev);
-
-               dev->locked_tasklet_func = NULL;
-       }
-
+       tasklet_func = dev->locked_tasklet_func;
+       dev->locked_tasklet_func = NULL;
        spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
+       if (tasklet_func != NULL)
+               tasklet_func(dev);
 
        atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);