diff options
author | Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | 2008-08-13 10:04:21 +0200 |
---|---|---|
committer | Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> | 2008-08-13 10:04:21 +0200 |
commit | af12ef4f6b4ca111d9a2ef45263ad89610498724 (patch) | |
tree | 9794799de029ef303f3145f12738c680d033d80e /linux-core/drm_irq.c | |
parent | b0e68829462aad00ce68be998da6313bca754e9a (diff) |
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.
Diffstat (limited to 'linux-core/drm_irq.c')
-rw-r--r-- | linux-core/drm_irq.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/linux-core/drm_irq.c b/linux-core/drm_irq.c index 5b9f474b..57419ca1 100644 --- a/linux-core/drm_irq.c +++ b/linux-core/drm_irq.c @@ -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); } /** |