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.main
parent
b0e6882946
commit
af12ef4f6b
|
@ -705,27 +705,31 @@ static void drm_locked_tasklet_func(unsigned long data)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = (struct drm_device *)data;
|
struct drm_device *dev = (struct drm_device *)data;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
void (*tasklet_func)(struct drm_device *);
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
|
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_lock_take(&dev->lock,
|
||||||
DRM_KERNEL_CONTEXT)) {
|
DRM_KERNEL_CONTEXT)) {
|
||||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->lock.lock_time = jiffies;
|
dev->lock.lock_time = jiffies;
|
||||||
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
|
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_lock_free(&dev->lock,
|
||||||
DRM_KERNEL_CONTEXT);
|
DRM_KERNEL_CONTEXT);
|
||||||
|
|
||||||
dev->locked_tasklet_func = NULL;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -155,6 +155,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
struct drm_lock *lock = data;
|
struct drm_lock *lock = data;
|
||||||
unsigned long irqflags;
|
unsigned long irqflags;
|
||||||
|
void (*tasklet_func)(struct drm_device *);
|
||||||
|
|
||||||
if (lock->context == DRM_KERNEL_CONTEXT) {
|
if (lock->context == DRM_KERNEL_CONTEXT) {
|
||||||
DRM_ERROR("Process %d using kernel context %d\n",
|
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);
|
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
|
||||||
|
tasklet_func = dev->locked_tasklet_func;
|
||||||
if (dev->locked_tasklet_func) {
|
dev->locked_tasklet_func = NULL;
|
||||||
dev->locked_tasklet_func(dev);
|
|
||||||
|
|
||||||
dev->locked_tasklet_func = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
|
||||||
|
if (tasklet_func != NULL)
|
||||||
|
tasklet_func(dev);
|
||||||
|
|
||||||
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
|
atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue