aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/drm_lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/drm/drm_lock.c')
-rw-r--r--drivers/char/drm/drm_lock.c177
1 files changed, 88 insertions, 89 deletions
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index 4702d863bcc6..b276ae8a6633 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -1,7 +1,7 @@
1/** 1/**
2 * \file drm_lock.h 2 * \file drm_lock.c
3 * IOCTLs for locking 3 * IOCTLs for locking
4 * 4 *
5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Gareth Hughes <gareth@valinux.com> 6 * \author Gareth Hughes <gareth@valinux.com>
7 */ 7 */
@@ -35,12 +35,12 @@
35 35
36#include "drmP.h" 36#include "drmP.h"
37 37
38static int drm_lock_transfer(drm_device_t *dev, 38static int drm_lock_transfer(drm_device_t * dev,
39 __volatile__ unsigned int *lock, 39 __volatile__ unsigned int *lock,
40 unsigned int context); 40 unsigned int context);
41static int drm_notifier(void *priv); 41static int drm_notifier(void *priv);
42 42
43/** 43/**
44 * Lock ioctl. 44 * Lock ioctl.
45 * 45 *
46 * \param inode device inode. 46 * \param inode device inode.
@@ -51,91 +51,89 @@ static int drm_notifier(void *priv);
51 * 51 *
52 * Add the current task to the lock wait queue, and attempt to take to lock. 52 * Add the current task to the lock wait queue, and attempt to take to lock.
53 */ 53 */
54int drm_lock( struct inode *inode, struct file *filp, 54int drm_lock(struct inode *inode, struct file *filp,
55 unsigned int cmd, unsigned long arg ) 55 unsigned int cmd, unsigned long arg)
56{ 56{
57 drm_file_t *priv = filp->private_data; 57 drm_file_t *priv = filp->private_data;
58 drm_device_t *dev = priv->head->dev; 58 drm_device_t *dev = priv->head->dev;
59 DECLARE_WAITQUEUE( entry, current ); 59 DECLARE_WAITQUEUE(entry, current);
60 drm_lock_t lock; 60 drm_lock_t lock;
61 int ret = 0; 61 int ret = 0;
62 62
63 ++priv->lock_count; 63 ++priv->lock_count;
64 64
65 if ( copy_from_user( &lock, (drm_lock_t __user *)arg, sizeof(lock) ) ) 65 if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
66 return -EFAULT; 66 return -EFAULT;
67 67
68 if ( lock.context == DRM_KERNEL_CONTEXT ) { 68 if (lock.context == DRM_KERNEL_CONTEXT) {
69 DRM_ERROR( "Process %d using kernel context %d\n", 69 DRM_ERROR("Process %d using kernel context %d\n",
70 current->pid, lock.context ); 70 current->pid, lock.context);
71 return -EINVAL; 71 return -EINVAL;
72 } 72 }
73 73
74 DRM_DEBUG( "%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n", 74 DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
75 lock.context, current->pid, 75 lock.context, current->pid,
76 dev->lock.hw_lock->lock, lock.flags ); 76 dev->lock.hw_lock->lock, lock.flags);
77 77
78 if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE)) 78 if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
79 if ( lock.context < 0 ) 79 if (lock.context < 0)
80 return -EINVAL; 80 return -EINVAL;
81 81
82 add_wait_queue( &dev->lock.lock_queue, &entry ); 82 add_wait_queue(&dev->lock.lock_queue, &entry);
83 for (;;) { 83 for (;;) {
84 __set_current_state(TASK_INTERRUPTIBLE); 84 __set_current_state(TASK_INTERRUPTIBLE);
85 if ( !dev->lock.hw_lock ) { 85 if (!dev->lock.hw_lock) {
86 /* Device has been unregistered */ 86 /* Device has been unregistered */
87 ret = -EINTR; 87 ret = -EINTR;
88 break; 88 break;
89 } 89 }
90 if ( drm_lock_take( &dev->lock.hw_lock->lock, 90 if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) {
91 lock.context ) ) { 91 dev->lock.filp = filp;
92 dev->lock.filp = filp;
93 dev->lock.lock_time = jiffies; 92 dev->lock.lock_time = jiffies;
94 atomic_inc( &dev->counts[_DRM_STAT_LOCKS] ); 93 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
95 break; /* Got lock */ 94 break; /* Got lock */
96 } 95 }
97 96
98 /* Contention */ 97 /* Contention */
99 schedule(); 98 schedule();
100 if ( signal_pending( current ) ) { 99 if (signal_pending(current)) {
101 ret = -ERESTARTSYS; 100 ret = -ERESTARTSYS;
102 break; 101 break;
103 } 102 }
104 } 103 }
105 __set_current_state(TASK_RUNNING); 104 __set_current_state(TASK_RUNNING);
106 remove_wait_queue( &dev->lock.lock_queue, &entry ); 105 remove_wait_queue(&dev->lock.lock_queue, &entry);
107 106
108 sigemptyset( &dev->sigmask ); 107 sigemptyset(&dev->sigmask);
109 sigaddset( &dev->sigmask, SIGSTOP ); 108 sigaddset(&dev->sigmask, SIGSTOP);
110 sigaddset( &dev->sigmask, SIGTSTP ); 109 sigaddset(&dev->sigmask, SIGTSTP);
111 sigaddset( &dev->sigmask, SIGTTIN ); 110 sigaddset(&dev->sigmask, SIGTTIN);
112 sigaddset( &dev->sigmask, SIGTTOU ); 111 sigaddset(&dev->sigmask, SIGTTOU);
113 dev->sigdata.context = lock.context; 112 dev->sigdata.context = lock.context;
114 dev->sigdata.lock = dev->lock.hw_lock; 113 dev->sigdata.lock = dev->lock.hw_lock;
115 block_all_signals( drm_notifier, 114 block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
116 &dev->sigdata, &dev->sigmask ); 115
117
118 if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY)) 116 if (dev->driver->dma_ready && (lock.flags & _DRM_LOCK_READY))
119 dev->driver->dma_ready(dev); 117 dev->driver->dma_ready(dev);
120 118
121 if ( dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT )) 119 if (dev->driver->dma_quiescent && (lock.flags & _DRM_LOCK_QUIESCENT))
122 return dev->driver->dma_quiescent(dev); 120 return dev->driver->dma_quiescent(dev);
123 121
124 /* dev->driver->kernel_context_switch isn't used by any of the x86 122 /* dev->driver->kernel_context_switch isn't used by any of the x86
125 * drivers but is used by the Sparc driver. 123 * drivers but is used by the Sparc driver.
126 */ 124 */
127 125
128 if (dev->driver->kernel_context_switch && 126 if (dev->driver->kernel_context_switch &&
129 dev->last_context != lock.context) { 127 dev->last_context != lock.context) {
130 dev->driver->kernel_context_switch(dev, dev->last_context, 128 dev->driver->kernel_context_switch(dev, dev->last_context,
131 lock.context); 129 lock.context);
132 } 130 }
133 DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" ); 131 DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
134 132
135 return ret; 133 return ret;
136} 134}
137 135
138/** 136/**
139 * Unlock ioctl. 137 * Unlock ioctl.
140 * 138 *
141 * \param inode device inode. 139 * \param inode device inode.
@@ -146,23 +144,23 @@ int drm_lock( struct inode *inode, struct file *filp,
146 * 144 *
147 * Transfer and free the lock. 145 * Transfer and free the lock.
148 */ 146 */
149int drm_unlock( struct inode *inode, struct file *filp, 147int drm_unlock(struct inode *inode, struct file *filp,
150 unsigned int cmd, unsigned long arg ) 148 unsigned int cmd, unsigned long arg)
151{ 149{
152 drm_file_t *priv = filp->private_data; 150 drm_file_t *priv = filp->private_data;
153 drm_device_t *dev = priv->head->dev; 151 drm_device_t *dev = priv->head->dev;
154 drm_lock_t lock; 152 drm_lock_t lock;
155 153
156 if ( copy_from_user( &lock, (drm_lock_t __user *)arg, sizeof(lock) ) ) 154 if (copy_from_user(&lock, (drm_lock_t __user *) arg, sizeof(lock)))
157 return -EFAULT; 155 return -EFAULT;
158 156
159 if ( lock.context == DRM_KERNEL_CONTEXT ) { 157 if (lock.context == DRM_KERNEL_CONTEXT) {
160 DRM_ERROR( "Process %d using kernel context %d\n", 158 DRM_ERROR("Process %d using kernel context %d\n",
161 current->pid, lock.context ); 159 current->pid, lock.context);
162 return -EINVAL; 160 return -EINVAL;
163 } 161 }
164 162
165 atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] ); 163 atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
166 164
167 /* kernel_context_switch isn't used by any of the x86 drm 165 /* kernel_context_switch isn't used by any of the x86 drm
168 * modules but is required by the Sparc driver. 166 * modules but is required by the Sparc driver.
@@ -170,12 +168,12 @@ int drm_unlock( struct inode *inode, struct file *filp,
170 if (dev->driver->kernel_context_switch_unlock) 168 if (dev->driver->kernel_context_switch_unlock)
171 dev->driver->kernel_context_switch_unlock(dev, &lock); 169 dev->driver->kernel_context_switch_unlock(dev, &lock);
172 else { 170 else {
173 drm_lock_transfer( dev, &dev->lock.hw_lock->lock, 171 drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
174 DRM_KERNEL_CONTEXT ); 172 DRM_KERNEL_CONTEXT);
175 173
176 if ( drm_lock_free( dev, &dev->lock.hw_lock->lock, 174 if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
177 DRM_KERNEL_CONTEXT ) ) { 175 DRM_KERNEL_CONTEXT)) {
178 DRM_ERROR( "\n" ); 176 DRM_ERROR("\n");
179 } 177 }
180 } 178 }
181 179
@@ -198,8 +196,10 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
198 196
199 do { 197 do {
200 old = *lock; 198 old = *lock;
201 if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT; 199 if (old & _DRM_LOCK_HELD)
202 else new = context | _DRM_LOCK_HELD; 200 new = old | _DRM_LOCK_CONT;
201 else
202 new = context | _DRM_LOCK_HELD;
203 prev = cmpxchg(lock, old, new); 203 prev = cmpxchg(lock, old, new);
204 } while (prev != old); 204 } while (prev != old);
205 if (_DRM_LOCKING_CONTEXT(old) == context) { 205 if (_DRM_LOCKING_CONTEXT(old) == context) {
@@ -212,7 +212,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
212 } 212 }
213 } 213 }
214 if (new == (context | _DRM_LOCK_HELD)) { 214 if (new == (context | _DRM_LOCK_HELD)) {
215 /* Have lock */ 215 /* Have lock */
216 return 1; 216 return 1;
217 } 217 }
218 return 0; 218 return 0;
@@ -220,8 +220,8 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
220 220
221/** 221/**
222 * This takes a lock forcibly and hands it to context. Should ONLY be used 222 * This takes a lock forcibly and hands it to context. Should ONLY be used
223 * inside *_unlock to give lock to kernel before calling *_dma_schedule. 223 * inside *_unlock to give lock to kernel before calling *_dma_schedule.
224 * 224 *
225 * \param dev DRM device. 225 * \param dev DRM device.
226 * \param lock lock pointer. 226 * \param lock lock pointer.
227 * \param context locking context. 227 * \param context locking context.
@@ -230,7 +230,7 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
230 * Resets the lock file pointer. 230 * Resets the lock file pointer.
231 * Marks the lock as held by the given context, via the \p cmpxchg instruction. 231 * Marks the lock as held by the given context, via the \p cmpxchg instruction.
232 */ 232 */
233static int drm_lock_transfer(drm_device_t *dev, 233static int drm_lock_transfer(drm_device_t * dev,
234 __volatile__ unsigned int *lock, 234 __volatile__ unsigned int *lock,
235 unsigned int context) 235 unsigned int context)
236{ 236{
@@ -238,8 +238,8 @@ static int drm_lock_transfer(drm_device_t *dev,
238 238
239 dev->lock.filp = NULL; 239 dev->lock.filp = NULL;
240 do { 240 do {
241 old = *lock; 241 old = *lock;
242 new = context | _DRM_LOCK_HELD; 242 new = context | _DRM_LOCK_HELD;
243 prev = cmpxchg(lock, old, new); 243 prev = cmpxchg(lock, old, new);
244 } while (prev != old); 244 } while (prev != old);
245 return 1; 245 return 1;
@@ -247,30 +247,29 @@ static int drm_lock_transfer(drm_device_t *dev,
247 247
248/** 248/**
249 * Free lock. 249 * Free lock.
250 * 250 *
251 * \param dev DRM device. 251 * \param dev DRM device.
252 * \param lock lock. 252 * \param lock lock.
253 * \param context context. 253 * \param context context.
254 * 254 *
255 * Resets the lock file pointer. 255 * Resets the lock file pointer.
256 * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task 256 * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
257 * waiting on the lock queue. 257 * waiting on the lock queue.
258 */ 258 */
259int drm_lock_free(drm_device_t *dev, 259int drm_lock_free(drm_device_t * dev,
260 __volatile__ unsigned int *lock, unsigned int context) 260 __volatile__ unsigned int *lock, unsigned int context)
261{ 261{
262 unsigned int old, new, prev; 262 unsigned int old, new, prev;
263 263
264 dev->lock.filp = NULL; 264 dev->lock.filp = NULL;
265 do { 265 do {
266 old = *lock; 266 old = *lock;
267 new = 0; 267 new = 0;
268 prev = cmpxchg(lock, old, new); 268 prev = cmpxchg(lock, old, new);
269 } while (prev != old); 269 } while (prev != old);
270 if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) { 270 if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
271 DRM_ERROR("%d freed heavyweight lock held by %d\n", 271 DRM_ERROR("%d freed heavyweight lock held by %d\n",
272 context, 272 context, _DRM_LOCKING_CONTEXT(old));
273 _DRM_LOCKING_CONTEXT(old));
274 return 1; 273 return 1;
275 } 274 }
276 wake_up_interruptible(&dev->lock.lock_queue); 275 wake_up_interruptible(&dev->lock.lock_queue);
@@ -290,19 +289,19 @@ int drm_lock_free(drm_device_t *dev,
290 */ 289 */
291static int drm_notifier(void *priv) 290static int drm_notifier(void *priv)
292{ 291{
293 drm_sigdata_t *s = (drm_sigdata_t *)priv; 292 drm_sigdata_t *s = (drm_sigdata_t *) priv;
294 unsigned int old, new, prev; 293 unsigned int old, new, prev;
295
296 294
297 /* Allow signal delivery if lock isn't held */ 295 /* Allow signal delivery if lock isn't held */
298 if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock) 296 if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock)
299 || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1; 297 || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context)
298 return 1;
300 299
301 /* Otherwise, set flag to force call to 300 /* Otherwise, set flag to force call to
302 drmUnlock */ 301 drmUnlock */
303 do { 302 do {
304 old = s->lock->lock; 303 old = s->lock->lock;
305 new = old | _DRM_LOCK_CONT; 304 new = old | _DRM_LOCK_CONT;
306 prev = cmpxchg(&s->lock->lock, old, new); 305 prev = cmpxchg(&s->lock->lock, old, new);
307 } while (prev != old); 306 } while (prev != old);
308 return 0; 307 return 0;