diff options
author | Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | 2008-08-24 17:00:00 +1000 |
---|---|---|
committer | Dave Airlie <airlied@linux.ie> | 2008-08-25 06:35:21 +1000 |
commit | e5b4f19417b75a2d7c1e36934f60a3e836c4337e (patch) | |
tree | 1daed2d024ce8f1b0ce586ceb29159d908a9bb4b /drivers | |
parent | 649ffc06a62bf487b78440669bdfeb637f1d675b (diff) | |
download | linux-e5b4f19417b75a2d7c1e36934f60a3e836c4337e.tar.gz linux-e5b4f19417b75a2d7c1e36934f60a3e836c4337e.tar.bz2 linux-e5b4f19417b75a2d7c1e36934f60a3e836c4337e.zip |
drm: don't call the vblank tasklet with irqs disabled.
If a specific tasklet shares data with irq context,
it needs to take a private irq-blocking spinlock within
the tasklet itself.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/drm_irq.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_lock.c | 12 |
2 files changed, 17 insertions, 15 deletions
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 089c015c01d1..53f0e5af1cc8 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -400,27 +400,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); } /** diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index 0998723cde79..d78e0dc18245 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -150,6 +150,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", @@ -158,14 +159,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]); |