diff options
Diffstat (limited to 'linux-core/drm_lock.c')
-rw-r--r-- | linux-core/drm_lock.c | 102 |
1 files changed, 57 insertions, 45 deletions
diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index e6eae42b..d2fb1feb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -52,6 +52,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) { DECLARE_WAITQUEUE(entry, current); struct drm_lock *lock = data; + struct drm_master *master = file_priv->master; int ret = 0; ++file_priv->lock_count; @@ -64,26 +65,27 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", lock->context, current->pid, - dev->lock.hw_lock->lock, lock->flags); + master->lock.hw_lock->lock, lock->flags); if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) if (lock->context < 0) return -EINVAL; - add_wait_queue(&dev->lock.lock_queue, &entry); - spin_lock_bh(&dev->lock.spinlock); - dev->lock.user_waiters++; - spin_unlock_bh(&dev->lock.spinlock); + add_wait_queue(&master->lock.lock_queue, &entry); + spin_lock_bh(&master->lock.spinlock); + master->lock.user_waiters++; + spin_unlock_bh(&master->lock.spinlock); + for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if (!dev->lock.hw_lock) { + if (!master->lock.hw_lock) { /* Device has been unregistered */ ret = -EINTR; break; } - if (drm_lock_take(&dev->lock, lock->context)) { - dev->lock.file_priv = file_priv; - dev->lock.lock_time = jiffies; + if (drm_lock_take(&master->lock, lock->context)) { + master->lock.file_priv = file_priv; + master->lock.lock_time = jiffies; atomic_inc(&dev->counts[_DRM_STAT_LOCKS]); break; /* Got lock */ } @@ -95,11 +97,11 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) break; } } - spin_lock_bh(&dev->lock.spinlock); - dev->lock.user_waiters--; - spin_unlock_bh(&dev->lock.spinlock); + spin_lock_bh(&master->lock.spinlock); + master->lock.user_waiters--; + spin_unlock_bh(&master->lock.spinlock); __set_current_state(TASK_RUNNING); - remove_wait_queue(&dev->lock.lock_queue, &entry); + remove_wait_queue(&master->lock.lock_queue, &entry); DRM_DEBUG("%d %s\n", lock->context, ret ? "interrupted" : "has lock"); @@ -111,7 +113,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) sigaddset(&dev->sigmask, SIGTTIN); sigaddset(&dev->sigmask, SIGTTOU); dev->sigdata.context = lock->context; - dev->sigdata.lock = dev->lock.hw_lock; + dev->sigdata.lock = master->lock.hw_lock; block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY)) @@ -149,6 +151,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) { struct drm_lock *lock = data; + struct drm_master *master = file_priv->master; unsigned long irqflags; if (lock->context == DRM_KERNEL_CONTEXT) { @@ -175,7 +178,7 @@ int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv) if (dev->driver->kernel_context_switch_unlock) dev->driver->kernel_context_switch_unlock(dev); else { - if (drm_lock_free(&dev->lock,lock->context)) { + if (drm_lock_free(&master->lock,lock->context)) { /* FIXME: Should really bail out here. */ } } @@ -213,16 +216,22 @@ int drm_lock_take(struct drm_lock_data *lock_data, } while (prev != old); spin_unlock_bh(&lock_data->spinlock); - /* Warn on recursive locking of user contexts. */ - if (_DRM_LOCKING_CONTEXT(old) == context && _DRM_LOCK_IS_HELD(old)) { - if (context != DRM_KERNEL_CONTEXT) { - DRM_ERROR("%d holds heavyweight lock\n", - context); + if (_DRM_LOCKING_CONTEXT(old) == context) { + if (old & _DRM_LOCK_HELD) { + if (context != DRM_KERNEL_CONTEXT) { + DRM_ERROR("%d holds heavyweight lock\n", + context); + } + return 0; } - return 0; } - return !_DRM_LOCK_IS_HELD(old); + if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) { + /* Have lock */ + + return 1; + } + return 0; } /** @@ -379,13 +388,15 @@ EXPORT_SYMBOL(drm_idlelock_release); * Takes the lock on behalf of the client if needed, using the kernel context. * * This allows us to hide the hardware lock when it's required for protection - * of data structures (such as command ringbuffer) shared with the X Server, and + * of data structures (such as command ringbuffer) shared with the X Server, an + * a way for us to transition to lockless for those requests when the X Server * stops accessing the ringbuffer directly, without having to update the * other userland clients. */ int drm_client_lock_take(struct drm_device *dev, struct drm_file *file_priv) { + struct drm_master *master = file_priv->master; int ret; unsigned long irqflags; @@ -398,45 +409,46 @@ int drm_client_lock_take(struct drm_device *dev, struct drm_file *file_priv) * context on behalf of the client, and return whether we were * successful. */ - spin_lock_irqsave(&dev->lock.spinlock, irqflags); - dev->lock.user_waiters++; - spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); - ret = wait_event_interruptible(dev->lock.lock_queue, - drm_lock_take(&dev->lock, + spin_lock_irqsave(&master->lock.spinlock, irqflags); + master->lock.user_waiters++; + spin_unlock_irqrestore(&master->lock.spinlock, irqflags); + ret = wait_event_interruptible(master->lock.lock_queue, + drm_lock_take(&master->lock, DRM_KERNEL_CONTEXT)); - spin_lock_irqsave(&dev->lock.spinlock, irqflags); - dev->lock.user_waiters--; + spin_lock_irqsave(&master->lock.spinlock, irqflags); + master->lock.user_waiters--; if (ret != 0) { - spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); + spin_unlock_irqrestore(&master->lock.spinlock, irqflags); } else { - dev->lock.file_priv = file_priv; - dev->lock.lock_time = jiffies; - dev->lock.kernel_held = 1; + master->lock.file_priv = file_priv; + master->lock.lock_time = jiffies; + master->lock.kernel_held = 1; file_priv->lock_count++; - spin_unlock_irqrestore(&dev->lock.spinlock, irqflags); + spin_unlock_irqrestore(&master->lock.spinlock, irqflags); } mutex_lock (&dev->struct_mutex); return ret; } EXPORT_SYMBOL(drm_client_lock_take); -void drm_client_lock_release(struct drm_device *dev) +void drm_client_lock_release(struct drm_device *dev, struct drm_file *file_priv) { - if (dev->lock.kernel_held) { - dev->lock.kernel_held = 0; - dev->lock.file_priv = NULL; - drm_lock_free(&dev->lock, DRM_KERNEL_CONTEXT); + struct drm_master *master = file_priv->master; + + if (master->lock.kernel_held) { + master->lock.kernel_held = 0; + master->lock.file_priv = NULL; + drm_lock_free(&master->lock, DRM_KERNEL_CONTEXT); } } EXPORT_SYMBOL(drm_client_lock_release); - int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv) { - - return (file_priv->lock_count && dev->lock.hw_lock && - _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) && - dev->lock.file_priv == file_priv); + struct drm_master *master = file_priv->master; + return (file_priv->lock_count && master->lock.hw_lock && + _DRM_LOCK_IS_HELD(master->lock.hw_lock->lock) && + master->lock.file_priv == file_priv); } EXPORT_SYMBOL(drm_i_have_hw_lock); |