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); | 
