Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / drm / drm_lock.c
blob6930a47e0317a5818d935946e8bb8e3dd8d9196d
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * lock.c -- IOCTLs for locking -*- linux-c -*-
8 * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
9 */
11 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
12 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13 * All Rights Reserved.
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
22 * The above copyright notice and this permission notice (including the next
23 * paragraph) shall be included in all copies or substantial portions of the
24 * Software.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 * OTHER DEALINGS IN THE SOFTWARE.
34 * Authors:
35 * Rickard E. (Rik) Faith <faith@valinux.com>
36 * Gareth Hughes <gareth@valinux.com>
40 #include "drmP.h"
42 int
43 drm_lock_take(drm_lock_data_t *lock_data, unsigned int context)
45 unsigned int old, new;
46 volatile unsigned int *lock = &lock_data->hw_lock->lock;
48 do {
49 old = *lock;
50 if (old & _DRM_LOCK_HELD)
51 new = old | _DRM_LOCK_CONT;
52 else
53 new = context | _DRM_LOCK_HELD;
54 } while (!atomic_cmpset_int(lock, old, new));
56 if (_DRM_LOCKING_CONTEXT(old) == context) {
57 if (old & _DRM_LOCK_HELD) {
58 if (context != DRM_KERNEL_CONTEXT) {
59 DRM_ERROR("%d holds heavyweight lock\n",
60 context);
62 return (0);
65 if (new == (context | _DRM_LOCK_HELD)) {
66 /* Have lock */
67 return (1);
69 return (0);
73 * This takes a lock forcibly and hands it to context. Should ONLY be used
74 * inside *_unlock to give lock to kernel before calling *_dma_schedule.
76 int
77 drm_lock_transfer(drm_device_t *dev, drm_lock_data_t *lock_data,
78 unsigned int context)
80 unsigned int old, new;
81 volatile unsigned int *lock = &lock_data->hw_lock->lock;
83 dev->lock.filp = NULL;
84 do {
85 old = *lock;
86 new = context | _DRM_LOCK_HELD;
87 } while (!atomic_cmpset_int(lock, old, new));
89 return (1);
92 int
93 drm_lock_free(drm_device_t *dev, volatile unsigned int *lock,
94 unsigned int context)
96 unsigned int old, new;
98 mutex_enter(&(dev->lock.lock_mutex));
99 dev->lock.filp = NULL;
100 do {
101 old = *lock;
102 new = 0;
103 } while (!atomic_cmpset_int(lock, old, new));
105 if (_DRM_LOCK_IS_HELD(old) &&
106 (_DRM_LOCKING_CONTEXT(old) != context)) {
107 DRM_ERROR("%d freed heavyweight lock held by %d\n",
108 context, _DRM_LOCKING_CONTEXT(old));
109 mutex_exit(&(dev->lock.lock_mutex));
110 return (1);
112 cv_broadcast(&(dev->lock.lock_cv));
113 mutex_exit(&(dev->lock.lock_mutex));
114 return (0);
117 /*ARGSUSED*/
119 drm_lock(DRM_IOCTL_ARGS)
121 DRM_DEVICE;
122 drm_lock_t lock;
123 int ret = 0;
125 DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
127 if (lock.context == DRM_KERNEL_CONTEXT) {
128 DRM_ERROR("Process %d using kernel context %d\n",
129 DRM_CURRENTPID, lock.context);
130 return (EINVAL);
133 DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
134 lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
135 lock.flags);
136 if (dev->driver->use_dma_queue && lock.context < 0)
137 return (EINVAL);
139 mutex_enter(&(dev->lock.lock_mutex));
140 for (;;) {
141 if (drm_lock_take(&dev->lock, lock.context)) {
142 dev->lock.filp = fpriv;
143 dev->lock.lock_time = ddi_get_lbolt();
144 break; /* Got lock */
146 ret = cv_wait_sig(&(dev->lock.lock_cv),
147 &(dev->lock.lock_mutex));
149 if (ret == 0) {
150 mutex_exit(&(dev->lock.lock_mutex));
151 return (EINTR);
154 mutex_exit(&(dev->lock.lock_mutex));
155 DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
157 if (dev->driver->dma_quiescent != NULL &&
158 (lock.flags & _DRM_LOCK_QUIESCENT))
159 dev->driver->dma_quiescent(dev);
161 return (0);
164 /*ARGSUSED*/
166 drm_unlock(DRM_IOCTL_ARGS)
168 DRM_DEVICE;
169 drm_lock_t lock;
171 DRM_COPYFROM_WITH_RETURN(&lock, (void *)data, sizeof (lock));
173 DRM_DEBUG("%d (pid %d) requests unlock (0x%08x), flags = 0x%08x\n",
174 lock.context, DRM_CURRENTPID, dev->lock.hw_lock->lock,
175 lock.flags);
177 if (lock.context == DRM_KERNEL_CONTEXT) {
178 DRM_ERROR("Process %d using kernel context %d\n",
179 DRM_CURRENTPID, lock.context);
180 return (EINVAL);
182 atomic_inc_32(&dev->counts[_DRM_STAT_UNLOCKS]);
184 DRM_LOCK();
185 if (drm_lock_free(dev, &dev->lock.hw_lock->lock, lock.context)) {
186 DRM_ERROR("drm_unlock\n");
188 DRM_UNLOCK();
189 return (0);