xref: /titanic_50/usr/src/uts/common/io/drm/drm_lock.c (revision d3d50737e566cade9a08d73d2af95105ac7cd960)
160405de4Skz151634 /*
2d0231070Smiao chen - Sun Microsystems - Beijing China  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
360405de4Skz151634  * Use is subject to license terms.
460405de4Skz151634  */
560405de4Skz151634 
660405de4Skz151634 /*
760405de4Skz151634  * lock.c -- IOCTLs for locking -*- linux-c -*-
860405de4Skz151634  * Created: Tue Feb  2 08:37:54 1999 by faith@valinux.com
960405de4Skz151634  */
1060405de4Skz151634 /*
1160405de4Skz151634  * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
1260405de4Skz151634  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
1360405de4Skz151634  * All Rights Reserved.
1460405de4Skz151634  *
1560405de4Skz151634  * Permission is hereby granted, free of charge, to any person obtaining a
1660405de4Skz151634  * copy of this software and associated documentation files (the "Software"),
1760405de4Skz151634  * to deal in the Software without restriction, including without limitation
1860405de4Skz151634  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1960405de4Skz151634  * and/or sell copies of the Software, and to permit persons to whom the
2060405de4Skz151634  * Software is furnished to do so, subject to the following conditions:
2160405de4Skz151634  *
2260405de4Skz151634  * The above copyright notice and this permission notice (including the next
2360405de4Skz151634  * paragraph) shall be included in all copies or substantial portions of the
2460405de4Skz151634  * Software.
2560405de4Skz151634  *
2660405de4Skz151634  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2760405de4Skz151634  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2860405de4Skz151634  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2960405de4Skz151634  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
3060405de4Skz151634  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
3160405de4Skz151634  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
3260405de4Skz151634  * OTHER DEALINGS IN THE SOFTWARE.
3360405de4Skz151634  *
3460405de4Skz151634  * Authors:
3560405de4Skz151634  *    Rickard E. (Rik) Faith <faith@valinux.com>
3660405de4Skz151634  *    Gareth Hughes <gareth@valinux.com>
3760405de4Skz151634  *
3860405de4Skz151634  */
3960405de4Skz151634 
4060405de4Skz151634 #include "drmP.h"
4160405de4Skz151634 
4260405de4Skz151634 int
drm_lock_take(drm_lock_data_t * lock_data,unsigned int context)43d0538f66Scg149915 drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
4460405de4Skz151634 {
45d0231070Smiao chen - Sun Microsystems - Beijing China 	unsigned int old, new;
46d0538f66Scg149915 	volatile unsigned int *lock = &lock_data->hw_lock->lock;
4760405de4Skz151634 
4860405de4Skz151634 	do {
4960405de4Skz151634 		old = *lock;
50d0538f66Scg149915 		if (old & _DRM_LOCK_HELD)
51d0538f66Scg149915 			new = old | _DRM_LOCK_CONT;
52d0538f66Scg149915 		else
53d0538f66Scg149915 			new = context | _DRM_LOCK_HELD;
54d0231070Smiao chen - Sun Microsystems - Beijing China 	} while (!atomic_cmpset_int(lock, old, new));
5560405de4Skz151634 
5660405de4Skz151634 	if (_DRM_LOCKING_CONTEXT(old) == context) {
5760405de4Skz151634 		if (old & _DRM_LOCK_HELD) {
5860405de4Skz151634 			if (context != DRM_KERNEL_CONTEXT) {
5960405de4Skz151634 				DRM_ERROR("%d holds heavyweight lock\n",
6060405de4Skz151634 				    context);
6160405de4Skz151634 			}
6260405de4Skz151634 			return (0);
6360405de4Skz151634 		}
6460405de4Skz151634 	}
65d0231070Smiao chen - Sun Microsystems - Beijing China 	if (new == (context | _DRM_LOCK_HELD)) {
6660405de4Skz151634 		/* Have lock */
6760405de4Skz151634 		return (1);
6860405de4Skz151634 	}
6960405de4Skz151634 	return (0);
7060405de4Skz151634 }
7160405de4Skz151634 
7260405de4Skz151634 /*
7360405de4Skz151634  * This takes a lock forcibly and hands it to context.	Should ONLY be used
7460405de4Skz151634  * inside *_unlock to give lock to kernel before calling *_dma_schedule.
7560405de4Skz151634  */
7660405de4Skz151634 int
drm_lock_transfer(drm_device_t * dev,drm_lock_data_t * lock_data,unsigned int context)77d0231070Smiao chen - Sun Microsystems - Beijing China drm_lock_transfer(drm_device_t *dev, drm_lock_data_t *lock_data,
7860405de4Skz151634 			unsigned int context)
7960405de4Skz151634 {
80d0231070Smiao chen - Sun Microsystems - Beijing China 	unsigned int old, new;
81d0231070Smiao chen - Sun Microsystems - Beijing China 	volatile unsigned int *lock = &lock_data->hw_lock->lock;
8260405de4Skz151634 
8360405de4Skz151634 	dev->lock.filp = NULL;
8460405de4Skz151634 	do {
8560405de4Skz151634 		old  = *lock;
8660405de4Skz151634 		new  = context | _DRM_LOCK_HELD;
87d0231070Smiao chen - Sun Microsystems - Beijing China 	} while (!atomic_cmpset_int(lock, old, new));
8860405de4Skz151634 
8960405de4Skz151634 	return (1);
9060405de4Skz151634 }
9160405de4Skz151634 
9260405de4Skz151634 int
drm_lock_free(drm_device_t * dev,volatile unsigned int * lock,unsigned int context)93d0538f66Scg149915 drm_lock_free(drm_device_t *dev, volatile unsigned int *lock,
9460405de4Skz151634     unsigned int context)
9560405de4Skz151634 {
96d0231070Smiao chen - Sun Microsystems - Beijing China 	unsigned int old, new;
9760405de4Skz151634 
9860405de4Skz151634 	mutex_enter(&(dev->lock.lock_mutex));
9960405de4Skz151634 	dev->lock.filp = NULL;
10060405de4Skz151634 	do {
10160405de4Skz151634 		old  = *lock;
10260405de4Skz151634 		new = 0;
103d0231070Smiao chen - Sun Microsystems - Beijing China 	} while (!atomic_cmpset_int(lock, old, new));
10460405de4Skz151634 
105d0538f66Scg149915 	if (_DRM_LOCK_IS_HELD(old) &&
106d0538f66Scg149915 	    (_DRM_LOCKING_CONTEXT(old) != context)) {
10760405de4Skz151634 		DRM_ERROR("%d freed heavyweight lock held by %d\n",
10860405de4Skz151634 		    context, _DRM_LOCKING_CONTEXT(old));
109d0538f66Scg149915 		mutex_exit(&(dev->lock.lock_mutex));
11060405de4Skz151634 		return (1);
11160405de4Skz151634 	}
11260405de4Skz151634 	cv_broadcast(&(dev->lock.lock_cv));
11360405de4Skz151634 	mutex_exit(&(dev->lock.lock_mutex));
11460405de4Skz151634 	return (0);
11560405de4Skz151634 }
11660405de4Skz151634 
11760405de4Skz151634 /*ARGSUSED*/
11860405de4Skz151634 int
drm_lock(DRM_IOCTL_ARGS)11960405de4Skz151634 drm_lock(DRM_IOCTL_ARGS)
12060405de4Skz151634 {
12160405de4Skz151634 	DRM_DEVICE;
12260405de4Skz151634 	drm_lock_t lock;
12360405de4Skz151634 	int ret = 0;
12460405de4Skz151634 
125d0538f66Scg149915 	DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
12660405de4Skz151634 
12760405de4Skz151634 	if (lock.context == DRM_KERNEL_CONTEXT) {
128d0231070Smiao chen - Sun Microsystems - Beijing China 		DRM_ERROR("Process %d using kernel context %d\n",
129d0231070Smiao chen - Sun Microsystems - Beijing China 		    DRM_CURRENTPID, lock.context);
130d0538f66Scg149915 		return (EINVAL);
13160405de4Skz151634 	}
13260405de4Skz151634 
133d0231070Smiao chen - Sun Microsystems - Beijing China 	DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
134d0231070Smiao chen - Sun Microsystems - Beijing China 	    lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
135d0231070Smiao chen - Sun Microsystems - Beijing China 	    lock.flags);
136d0538f66Scg149915 	if (dev->driver->use_dma_queue && lock.context < 0)
137d0538f66Scg149915 		return (EINVAL);
13860405de4Skz151634 
13960405de4Skz151634 	mutex_enter(&(dev->lock.lock_mutex));
14060405de4Skz151634 	for (;;) {
141d0538f66Scg149915 		if (drm_lock_take(&dev->lock, lock.context)) {
142d0538f66Scg149915 			dev->lock.filp = fpriv;
143*d3d50737SRafael Vanoni 			dev->lock.lock_time = ddi_get_lbolt();
14460405de4Skz151634 			break;  /* Got lock */
14560405de4Skz151634 		}
14660405de4Skz151634 		ret = cv_wait_sig(&(dev->lock.lock_cv),
14760405de4Skz151634 		    &(dev->lock.lock_mutex));
14860405de4Skz151634 
14960405de4Skz151634 		if (ret == 0) {
15060405de4Skz151634 			mutex_exit(&(dev->lock.lock_mutex));
151d0538f66Scg149915 			return (EINTR);
15260405de4Skz151634 		}
15360405de4Skz151634 	}
15460405de4Skz151634 	mutex_exit(&(dev->lock.lock_mutex));
155d0231070Smiao chen - Sun Microsystems - Beijing China 	DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
15660405de4Skz151634 
157d0538f66Scg149915 	if (dev->driver->dma_quiescent != NULL &&
15860405de4Skz151634 	    (lock.flags & _DRM_LOCK_QUIESCENT))
159d0538f66Scg149915 		dev->driver->dma_quiescent(dev);
16060405de4Skz151634 
16160405de4Skz151634 	return (0);
16260405de4Skz151634 }
16360405de4Skz151634 
16460405de4Skz151634 /*ARGSUSED*/
16560405de4Skz151634 int
drm_unlock(DRM_IOCTL_ARGS)16660405de4Skz151634 drm_unlock(DRM_IOCTL_ARGS)
16760405de4Skz151634 {
16860405de4Skz151634 	DRM_DEVICE;
16960405de4Skz151634 	drm_lock_t lock;
17060405de4Skz151634 
171d0538f66Scg149915 	DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
17260405de4Skz151634 
173d0231070Smiao chen - Sun Microsystems - Beijing China 	DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n",
174d0231070Smiao chen - Sun Microsystems - Beijing China 	    lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
175d0231070Smiao chen - Sun Microsystems - Beijing China 	    lock.flags);
176d0231070Smiao chen - Sun Microsystems - Beijing China 
17760405de4Skz151634 	if (lock.context == DRM_KERNEL_CONTEXT) {
17860405de4Skz151634 		DRM_ERROR("Process %d using kernel context %d\n",
17960405de4Skz151634 		    DRM_CURRENTPID, lock.context);
180d0538f66Scg149915 		return (EINVAL);
18160405de4Skz151634 	}
18260405de4Skz151634 	atomic_inc_32(&dev->counts[_DRM_STAT_UNLOCKS]);
18360405de4Skz151634 
18460405de4Skz151634 	DRM_LOCK();
185d0538f66Scg149915 	if (drm_lock_free(dev, &dev->lock.hw_lock->lock, lock.context)) {
18660405de4Skz151634 		DRM_ERROR("drm_unlock\n");
18760405de4Skz151634 	}
18860405de4Skz151634 	DRM_UNLOCK();
18960405de4Skz151634 	return (0);
19060405de4Skz151634 }
191