1 /* lock.c -- IOCTLs for locking -*- linux-c -*-
2 * Created: Tue Feb 2 08:37:54 1999 by faith@precisioninsight.com
3 * Revised: Fri Aug 20 09:27:01 1999 by faith@precisioninsight.com
5 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
27 * $PI: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/generic/lock.c,v 1.5 1999/08/30 13:05:00 faith Exp $
32 #define __NO_VERSION__
35 int drm_block(struct inode
*inode
, struct file
*filp
, unsigned int cmd
,
42 int drm_unblock(struct inode
*inode
, struct file
*filp
, unsigned int cmd
,
49 int drm_lock_take(__volatile__
unsigned int *lock
, unsigned int context
)
55 DRM_DEBUG("%d attempts\n", context
);
58 if (old
& _DRM_LOCK_HELD
) new = old
| _DRM_LOCK_CONT
;
59 else new = context
| _DRM_LOCK_HELD
;
60 _DRM_CAS(lock
, old
, new, failed
);
62 if (_DRM_LOCKING_CONTEXT(old
) == context
) {
63 if (old
& _DRM_LOCK_HELD
) {
64 if (context
!= DRM_KERNEL_CONTEXT
) {
65 DRM_ERROR("%d holds heavyweight lock\n",
71 if (new == (context
| _DRM_LOCK_HELD
)) {
73 DRM_DEBUG("%d\n", context
);
76 DRM_DEBUG("%d unable to get lock held by %d\n",
77 context
, _DRM_LOCKING_CONTEXT(old
));
81 /* This takes a lock forcibly and hands it to context. Should ONLY be used
82 inside *_unlock to give lock to kernel before calling *_dma_schedule. */
83 int drm_lock_transfer(__volatile__
unsigned int *lock
, unsigned int context
)
91 new = context
| _DRM_LOCK_HELD
;
92 _DRM_CAS(lock
, old
, new, failed
);
94 DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old
), context
);
98 int drm_lock_free(drm_device_t
*dev
,
99 __volatile__
unsigned int *lock
, unsigned int context
)
105 DRM_DEBUG("%d\n", context
);
109 _DRM_CAS(lock
, old
, new, failed
);
111 if (_DRM_LOCK_IS_HELD(old
) && _DRM_LOCKING_CONTEXT(old
) != context
) {
112 DRM_ERROR("%d freed heavyweight lock held by %d\n",
114 _DRM_LOCKING_CONTEXT(old
));
118 wake_up_interruptible(&dev
->lock
.lock_queue
);
122 static int drm_flush_queue(drm_device_t
*dev
, int context
)
124 DECLARE_WAITQUEUE(entry
, current
);
126 drm_queue_t
*q
= dev
->queuelist
[context
];
130 atomic_inc(&q
->use_count
);
131 if (atomic_read(&q
->use_count
) > 1) {
132 atomic_inc(&q
->block_write
);
133 current
->state
= TASK_INTERRUPTIBLE
;
134 add_wait_queue(&q
->flush_queue
, &entry
);
135 atomic_inc(&q
->block_count
);
137 if (!DRM_BUFCOUNT(&q
->waitlist
)) break;
139 if (signal_pending(current
)) {
140 ret
= -EINTR
; /* Can't restart */
144 atomic_dec(&q
->block_count
);
145 current
->state
= TASK_RUNNING
;
146 remove_wait_queue(&q
->flush_queue
, &entry
);
148 atomic_dec(&q
->use_count
);
149 atomic_inc(&q
->total_flushed
);
151 /* NOTE: block_write is still incremented!
152 Use drm_flush_unlock_queue to decrement. */
156 static int drm_flush_unblock_queue(drm_device_t
*dev
, int context
)
158 drm_queue_t
*q
= dev
->queuelist
[context
];
162 atomic_inc(&q
->use_count
);
163 if (atomic_read(&q
->use_count
) > 1) {
164 if (atomic_read(&q
->block_write
)) {
165 atomic_dec(&q
->block_write
);
166 wake_up_interruptible(&q
->write_queue
);
169 atomic_dec(&q
->use_count
);
173 int drm_flush_block_and_flush(drm_device_t
*dev
, int context
,
174 drm_lock_flags_t flags
)
181 if (flags
& _DRM_LOCK_FLUSH
) {
182 ret
= drm_flush_queue(dev
, DRM_KERNEL_CONTEXT
);
183 if (!ret
) ret
= drm_flush_queue(dev
, context
);
185 if (flags
& _DRM_LOCK_FLUSH_ALL
) {
186 for (i
= 0; !ret
&& i
< dev
->queue_count
; i
++) {
187 ret
= drm_flush_queue(dev
, i
);
193 int drm_flush_unblock(drm_device_t
*dev
, int context
, drm_lock_flags_t flags
)
200 if (flags
& _DRM_LOCK_FLUSH
) {
201 ret
= drm_flush_unblock_queue(dev
, DRM_KERNEL_CONTEXT
);
202 if (!ret
) ret
= drm_flush_unblock_queue(dev
, context
);
204 if (flags
& _DRM_LOCK_FLUSH_ALL
) {
205 for (i
= 0; !ret
&& i
< dev
->queue_count
; i
++) {
206 ret
= drm_flush_unblock_queue(dev
, i
);
213 int drm_finish(struct inode
*inode
, struct file
*filp
, unsigned int cmd
,
216 drm_file_t
*priv
= filp
->private_data
;
217 drm_device_t
*dev
= priv
->dev
;
223 copy_from_user_ret(&lock
, (drm_lock_t
*)arg
, sizeof(lock
), -EFAULT
);
224 ret
= drm_flush_block_and_flush(dev
, lock
.context
, lock
.flags
);
225 drm_flush_unblock(dev
, lock
.context
, lock
.flags
);