diff options
Diffstat (limited to 'linux-core/drm_lock.c')
| -rw-r--r-- | linux-core/drm_lock.c | 58 | 
1 files changed, 58 insertions, 0 deletions
diff --git a/linux-core/drm_lock.c b/linux-core/drm_lock.c index 6bbf1444..d2fb1feb 100644 --- a/linux-core/drm_lock.c +++ b/linux-core/drm_lock.c @@ -384,6 +384,64 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)  }  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, 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; + +	/* If the client has the lock, we're already done. */ +	if (drm_i_have_hw_lock(dev, file_priv)) +		return 0; + +	mutex_unlock (&dev->struct_mutex); +	/* Client doesn't hold the lock.  Block taking the lock with the kernel +	 * context on behalf of the client, and return whether we were +	 * successful. +	 */ +	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(&master->lock.spinlock, irqflags); +	master->lock.user_waiters--; +	if (ret != 0) { +		spin_unlock_irqrestore(&master->lock.spinlock, irqflags); +	} else { +		master->lock.file_priv = file_priv; +		master->lock.lock_time = jiffies; +		master->lock.kernel_held = 1; +		file_priv->lock_count++; +		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, struct drm_file *file_priv) +{ +	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)  {  | 
