blob: 12dcdd1832f080b57574d02ecd4acfc6076ecd88 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/**
Dave Airlieb5e89ed2005-09-25 14:28:13 +10002 * \file drm_lock.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * IOCTLs for locking
Dave Airlieb5e89ed2005-09-25 14:28:13 +10004 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Gareth Hughes <gareth@valinux.com>
7 */
8
9/*
10 * Created: Tue Feb 2 08:37:54 1999 by faith@valinux.com
11 *
12 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
13 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14 * All Rights Reserved.
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
22 *
23 * The above copyright notice and this permission notice (including the next
24 * paragraph) shall be included in all copies or substantial portions of the
25 * Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
31 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
32 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
33 * OTHER DEALINGS IN THE SOFTWARE.
34 */
35
36#include "drmP.h"
37
Dave Airliec94f7022005-07-07 21:03:38 +100038static int drm_notifier(void *priv);
39
Dave Airlieb5e89ed2005-09-25 14:28:13 +100040/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 * Lock ioctl.
42 *
43 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +100044 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 * \param cmd command.
46 * \param arg user argument, pointing to a drm_lock structure.
47 * \return zero on success or negative number on failure.
48 *
49 * Add the current task to the lock wait queue, and attempt to take to lock.
50 */
Eric Anholtc153f452007-09-03 12:06:45 +100051int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -070052{
Dave Airlieb5e89ed2005-09-25 14:28:13 +100053 DECLARE_WAITQUEUE(entry, current);
Eric Anholtc153f452007-09-03 12:06:45 +100054 struct drm_lock *lock = data;
Dave Airlieb5e89ed2005-09-25 14:28:13 +100055 int ret = 0;
Mike Isely9df58082008-03-13 15:30:35 -050056 unsigned long irqflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Eric Anholt6c340ea2007-08-25 20:23:09 +100058 ++file_priv->lock_count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Eric Anholtc153f452007-09-03 12:06:45 +100060 if (lock->context == DRM_KERNEL_CONTEXT) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +100061 DRM_ERROR("Process %d using kernel context %d\n",
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -070062 task_pid_nr(current), lock->context);
Dave Airlieb5e89ed2005-09-25 14:28:13 +100063 return -EINVAL;
64 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
Dave Airlieb5e89ed2005-09-25 14:28:13 +100066 DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -070067 lock->context, task_pid_nr(current),
Eric Anholtc153f452007-09-03 12:06:45 +100068 dev->lock.hw_lock->lock, lock->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070069
70 if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE))
Eric Anholtc153f452007-09-03 12:06:45 +100071 if (lock->context < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 return -EINVAL;
73
Dave Airlieb5e89ed2005-09-25 14:28:13 +100074 add_wait_queue(&dev->lock.lock_queue, &entry);
Mike Isely9df58082008-03-13 15:30:35 -050075 spin_lock_irqsave(&dev->lock.spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +110076 dev->lock.user_waiters++;
Mike Isely9df58082008-03-13 15:30:35 -050077 spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 for (;;) {
79 __set_current_state(TASK_INTERRUPTIBLE);
Dave Airlieb5e89ed2005-09-25 14:28:13 +100080 if (!dev->lock.hw_lock) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 /* Device has been unregistered */
82 ret = -EINTR;
83 break;
84 }
Eric Anholtc153f452007-09-03 12:06:45 +100085 if (drm_lock_take(&dev->lock, lock->context)) {
Eric Anholt6c340ea2007-08-25 20:23:09 +100086 dev->lock.file_priv = file_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 dev->lock.lock_time = jiffies;
Dave Airlieb5e89ed2005-09-25 14:28:13 +100088 atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
89 break; /* Got lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 }
Dave Airlieb5e89ed2005-09-25 14:28:13 +100091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 /* Contention */
93 schedule();
Dave Airlieb5e89ed2005-09-25 14:28:13 +100094 if (signal_pending(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 ret = -ERESTARTSYS;
96 break;
97 }
98 }
Mike Isely9df58082008-03-13 15:30:35 -050099 spin_lock_irqsave(&dev->lock.spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100100 dev->lock.user_waiters--;
Mike Isely9df58082008-03-13 15:30:35 -0500101 spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 __set_current_state(TASK_RUNNING);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000103 remove_wait_queue(&dev->lock.lock_queue, &entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Eric Anholtc153f452007-09-03 12:06:45 +1000105 DRM_DEBUG("%d %s\n", lock->context,
106 ret ? "interrupted" : "has lock");
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100107 if (ret) return ret;
Dave Airlied985c102006-01-02 21:32:48 +1100108
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000109 sigemptyset(&dev->sigmask);
110 sigaddset(&dev->sigmask, SIGSTOP);
111 sigaddset(&dev->sigmask, SIGTSTP);
112 sigaddset(&dev->sigmask, SIGTTIN);
113 sigaddset(&dev->sigmask, SIGTTOU);
Eric Anholtc153f452007-09-03 12:06:45 +1000114 dev->sigdata.context = lock->context;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000115 dev->sigdata.lock = dev->lock.hw_lock;
116 block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
117
Eric Anholtc153f452007-09-03 12:06:45 +1000118 if (dev->driver->dma_ready && (lock->flags & _DRM_LOCK_READY))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 dev->driver->dma_ready(dev);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000120
Eric Anholtc153f452007-09-03 12:06:45 +1000121 if (dev->driver->dma_quiescent && (lock->flags & _DRM_LOCK_QUIESCENT))
122 {
Dave Airlied985c102006-01-02 21:32:48 +1100123 if (dev->driver->dma_quiescent(dev)) {
Eric Anholtc153f452007-09-03 12:06:45 +1000124 DRM_DEBUG("%d waiting for DMA quiescent\n",
125 lock->context);
Eric Anholt20caafa2007-08-25 19:22:43 +1000126 return -EBUSY;
Dave Airlied985c102006-01-02 21:32:48 +1100127 }
128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000130 if (dev->driver->kernel_context_switch &&
Eric Anholtc153f452007-09-03 12:06:45 +1000131 dev->last_context != lock->context) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000132 dev->driver->kernel_context_switch(dev, dev->last_context,
Eric Anholtc153f452007-09-03 12:06:45 +1000133 lock->context);
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000134 }
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100135
Dave Airlied985c102006-01-02 21:32:48 +1100136 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137}
138
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000139/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 * Unlock ioctl.
141 *
142 * \param inode device inode.
Eric Anholt6c340ea2007-08-25 20:23:09 +1000143 * \param file_priv DRM file private.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 * \param cmd command.
145 * \param arg user argument, pointing to a drm_lock structure.
146 * \return zero on success or negative number on failure.
147 *
148 * Transfer and free the lock.
149 */
Eric Anholtc153f452007-09-03 12:06:45 +1000150int drm_unlock(struct drm_device *dev, void *data, struct drm_file *file_priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151{
Eric Anholtc153f452007-09-03 12:06:45 +1000152 struct drm_lock *lock = data;
Dave Airlie5c2df2b2006-10-24 11:36:59 -0700153 unsigned long irqflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Eric Anholtc153f452007-09-03 12:06:45 +1000155 if (lock->context == DRM_KERNEL_CONTEXT) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000156 DRM_ERROR("Process %d using kernel context %d\n",
Pavel Emelyanovba25f9d2007-10-18 23:40:40 -0700157 task_pid_nr(current), lock->context);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 return -EINVAL;
159 }
160
=?utf-8?q?Michel_D=C3=A4nzer?=2e54a002006-10-24 23:08:16 +1000161 spin_lock_irqsave(&dev->tasklet_lock, irqflags);
162
163 if (dev->locked_tasklet_func) {
164 dev->locked_tasklet_func(dev);
165
166 dev->locked_tasklet_func = NULL;
167 }
168
169 spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
170
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000171 atomic_inc(&dev->counts[_DRM_STAT_UNLOCKS]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
173 /* kernel_context_switch isn't used by any of the x86 drm
174 * modules but is required by the Sparc driver.
175 */
176 if (dev->driver->kernel_context_switch_unlock)
Dave Airlie0c4dd902006-12-19 17:49:44 +1100177 dev->driver->kernel_context_switch_unlock(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 else {
Eric Anholtc153f452007-09-03 12:06:45 +1000179 if (drm_lock_free(&dev->lock,lock->context)) {
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100180 /* FIXME: Should really bail out here. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 }
182 }
183
184 unblock_all_signals();
185 return 0;
186}
187
188/**
189 * Take the heavyweight lock.
190 *
191 * \param lock lock pointer.
192 * \param context locking context.
193 * \return one if the lock is held, or zero otherwise.
194 *
195 * Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
196 */
Dave Airlie55910512007-07-11 16:53:40 +1000197int drm_lock_take(struct drm_lock_data *lock_data,
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100198 unsigned int context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199{
200 unsigned int old, new, prev;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100201 volatile unsigned int *lock = &lock_data->hw_lock->lock;
Mike Isely9df58082008-03-13 15:30:35 -0500202 unsigned long irqflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Mike Isely9df58082008-03-13 15:30:35 -0500204 spin_lock_irqsave(&lock_data->spinlock, irqflags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 do {
206 old = *lock;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000207 if (old & _DRM_LOCK_HELD)
208 new = old | _DRM_LOCK_CONT;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100209 else {
210 new = context | _DRM_LOCK_HELD |
211 ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
212 _DRM_LOCK_CONT : 0);
213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 prev = cmpxchg(lock, old, new);
215 } while (prev != old);
Mike Isely9df58082008-03-13 15:30:35 -0500216 spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100217
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 if (_DRM_LOCKING_CONTEXT(old) == context) {
219 if (old & _DRM_LOCK_HELD) {
220 if (context != DRM_KERNEL_CONTEXT) {
221 DRM_ERROR("%d holds heavyweight lock\n",
222 context);
223 }
224 return 0;
225 }
226 }
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100227
228 if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000229 /* Have lock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 return 1;
231 }
232 return 0;
233}
234
235/**
236 * This takes a lock forcibly and hands it to context. Should ONLY be used
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000237 * inside *_unlock to give lock to kernel before calling *_dma_schedule.
238 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 * \param dev DRM device.
240 * \param lock lock pointer.
241 * \param context locking context.
242 * \return always one.
243 *
244 * Resets the lock file pointer.
245 * Marks the lock as held by the given context, via the \p cmpxchg instruction.
246 */
Dave Airlie55910512007-07-11 16:53:40 +1000247static int drm_lock_transfer(struct drm_lock_data *lock_data,
Dave Airliec94f7022005-07-07 21:03:38 +1000248 unsigned int context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249{
250 unsigned int old, new, prev;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100251 volatile unsigned int *lock = &lock_data->hw_lock->lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
Eric Anholt6c340ea2007-08-25 20:23:09 +1000253 lock_data->file_priv = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000255 old = *lock;
256 new = context | _DRM_LOCK_HELD;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257 prev = cmpxchg(lock, old, new);
258 } while (prev != old);
259 return 1;
260}
261
262/**
263 * Free lock.
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000264 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 * \param dev DRM device.
266 * \param lock lock.
267 * \param context context.
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000268 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 * Resets the lock file pointer.
270 * Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
271 * waiting on the lock queue.
272 */
Dave Airlie55910512007-07-11 16:53:40 +1000273int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
275 unsigned int old, new, prev;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100276 volatile unsigned int *lock = &lock_data->hw_lock->lock;
Mike Isely9df58082008-03-13 15:30:35 -0500277 unsigned long irqflags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278
Mike Isely9df58082008-03-13 15:30:35 -0500279 spin_lock_irqsave(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100280 if (lock_data->kernel_waiters != 0) {
281 drm_lock_transfer(lock_data, 0);
282 lock_data->idle_has_lock = 1;
Mike Isely9df58082008-03-13 15:30:35 -0500283 spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100284 return 1;
285 }
Mike Isely9df58082008-03-13 15:30:35 -0500286 spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000289 old = *lock;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100290 new = _DRM_LOCKING_CONTEXT(old);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 prev = cmpxchg(lock, old, new);
292 } while (prev != old);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100293
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
295 DRM_ERROR("%d freed heavyweight lock held by %d\n",
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000296 context, _DRM_LOCKING_CONTEXT(old));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 return 1;
298 }
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100299 wake_up_interruptible(&lock_data->lock_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300 return 0;
301}
302
303/**
304 * If we get here, it means that the process has called DRM_IOCTL_LOCK
305 * without calling DRM_IOCTL_UNLOCK.
306 *
307 * If the lock is not held, then let the signal proceed as usual. If the lock
308 * is held, then set the contended flag and keep the signal blocked.
309 *
310 * \param priv pointer to a drm_sigdata structure.
311 * \return one if the signal should be delivered normally, or zero if the
312 * signal should be blocked.
313 */
Dave Airliec94f7022005-07-07 21:03:38 +1000314static int drm_notifier(void *priv)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
Dave Airlie55910512007-07-11 16:53:40 +1000316 struct drm_sigdata *s = (struct drm_sigdata *) priv;
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000317 unsigned int old, new, prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000319 /* Allow signal delivery if lock isn't held */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320 if (!s->lock || !_DRM_LOCK_IS_HELD(s->lock->lock)
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000321 || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context)
322 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000324 /* Otherwise, set flag to force call to
325 drmUnlock */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 do {
Dave Airlieb5e89ed2005-09-25 14:28:13 +1000327 old = s->lock->lock;
328 new = old | _DRM_LOCK_CONT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 prev = cmpxchg(&s->lock->lock, old, new);
330 } while (prev != old);
331 return 0;
332}
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100333
334/**
335 * This function returns immediately and takes the hw lock
336 * with the kernel context if it is free, otherwise it gets the highest priority when and if
337 * it is eventually released.
338 *
339 * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held
340 * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause
341 * a deadlock, which is why the "idlelock" was invented).
342 *
343 * This should be sufficient to wait for GPU idle without
344 * having to worry about starvation.
345 */
346
Dave Airlie55910512007-07-11 16:53:40 +1000347void drm_idlelock_take(struct drm_lock_data *lock_data)
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100348{
349 int ret = 0;
Mike Isely9df58082008-03-13 15:30:35 -0500350 unsigned long irqflags;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100351
Mike Isely9df58082008-03-13 15:30:35 -0500352 spin_lock_irqsave(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100353 lock_data->kernel_waiters++;
354 if (!lock_data->idle_has_lock) {
355
Mike Isely9df58082008-03-13 15:30:35 -0500356 spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100357 ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
Mike Isely9df58082008-03-13 15:30:35 -0500358 spin_lock_irqsave(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100359
360 if (ret == 1)
361 lock_data->idle_has_lock = 1;
362 }
Mike Isely9df58082008-03-13 15:30:35 -0500363 spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100364}
365EXPORT_SYMBOL(drm_idlelock_take);
366
Dave Airlie55910512007-07-11 16:53:40 +1000367void drm_idlelock_release(struct drm_lock_data *lock_data)
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100368{
369 unsigned int old, prev;
370 volatile unsigned int *lock = &lock_data->hw_lock->lock;
Mike Isely9df58082008-03-13 15:30:35 -0500371 unsigned long irqflags;
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100372
Mike Isely9df58082008-03-13 15:30:35 -0500373 spin_lock_irqsave(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100374 if (--lock_data->kernel_waiters == 0) {
375 if (lock_data->idle_has_lock) {
376 do {
377 old = *lock;
378 prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT);
379 } while (prev != old);
380 wake_up_interruptible(&lock_data->lock_queue);
381 lock_data->idle_has_lock = 0;
382 }
383 }
Mike Isely9df58082008-03-13 15:30:35 -0500384 spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100385}
386EXPORT_SYMBOL(drm_idlelock_release);
387
388
Eric Anholtc153f452007-09-03 12:06:45 +1000389int drm_i_have_hw_lock(struct drm_device *dev, struct drm_file *file_priv)
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100390{
Eric Anholt6c340ea2007-08-25 20:23:09 +1000391 return (file_priv->lock_count && dev->lock.hw_lock &&
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100392 _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
Eric Anholt6c340ea2007-08-25 20:23:09 +1000393 dev->lock.file_priv == file_priv);
Thomas Hellstrom040ac322007-03-23 13:28:33 +1100394}
395
396EXPORT_SYMBOL(drm_i_have_hw_lock);