aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2008-08-24 03:00:00 -0400
committerDave Airlie <airlied@linux.ie>2008-08-24 16:35:21 -0400
commite5b4f19417b75a2d7c1e36934f60a3e836c4337e (patch)
tree1daed2d024ce8f1b0ce586ceb29159d908a9bb4b
parent649ffc06a62bf487b78440669bdfeb637f1d675b (diff)
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>
-rw-r--r--drivers/gpu/drm/drm_irq.c20
-rw-r--r--drivers/gpu/drm/drm_lock.c12
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)
400{ 400{
401 struct drm_device *dev = (struct drm_device *)data; 401 struct drm_device *dev = (struct drm_device *)data;
402 unsigned long irqflags; 402 unsigned long irqflags;
403 403 void (*tasklet_func)(struct drm_device *);
404
404 spin_lock_irqsave(&dev->tasklet_lock, irqflags); 405 spin_lock_irqsave(&dev->tasklet_lock, irqflags);
406 tasklet_func = dev->locked_tasklet_func;
407 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
405 408
406 if (!dev->locked_tasklet_func || 409 if (!tasklet_func ||
407 !drm_lock_take(&dev->lock, 410 !drm_lock_take(&dev->lock,
408 DRM_KERNEL_CONTEXT)) { 411 DRM_KERNEL_CONTEXT)) {
409 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
410 return; 412 return;
411 } 413 }
412 414
413 dev->lock.lock_time = jiffies; 415 dev->lock.lock_time = jiffies;
414 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); 416 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
415 417
416 dev->locked_tasklet_func(dev); 418 spin_lock_irqsave(&dev->tasklet_lock, irqflags);
419 tasklet_func = dev->locked_tasklet_func;
420 dev->locked_tasklet_func = NULL;
421 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
422
423 if (tasklet_func != NULL)
424 tasklet_func(dev);
417 425
418 drm_lock_free(&dev->lock, 426 drm_lock_free(&dev->lock,
419 DRM_KERNEL_CONTEXT); 427 DRM_KERNEL_CONTEXT);
420
421 dev->locked_tasklet_func = NULL;
422
423 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
424} 428}
425 429
426/** 430/**
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)
150{ 150{
151 struct drm_lock *lock = data; 151 struct drm_lock *lock = data;
152 unsigned long irqflags; 152 unsigned long irqflags;
153 void (*tasklet_func)(struct drm_device *);
153 154
154 if (lock->context == DRM_KERNEL_CONTEXT) { 155 if (lock->context == DRM_KERNEL_CONTEXT) {
155 DRM_ERROR("Process %d using kernel context %d\n", 156 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)
158 } 159 }
159 160
160 spin_lock_irqsave(&dev->tasklet_lock, irqflags); 161 spin_lock_irqsave(&dev->tasklet_lock, irqflags);
161 162 tasklet_func = dev->locked_tasklet_func;
162 if (dev->locked_tasklet_func) { 163 dev->locked_tasklet_func = NULL;
163 dev->locked_tasklet_func(dev);
164
165 dev->locked_tasklet_func = NULL;
166 }
167
168 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags); 164 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
165 if (tasklet_func != NULL)
166 tasklet_func(dev);
169 167
170 atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]); 168 atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
171 169