1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#define __NO_VERSION__
33#include "drmP.h"
34
35int DRM(block)(struct inode *inode, struct file *filp, unsigned int cmd,
36 unsigned long arg)
37{
38 DRM_DEBUG("\n");
39 return 0;
40}
41
42int DRM(unblock)(struct inode *inode, struct file *filp, unsigned int cmd,
43 unsigned long arg)
44{
45 DRM_DEBUG("\n");
46 return 0;
47}
48
49int DRM(lock_take)(__volatile__ unsigned int *lock, unsigned int context)
50{
51 unsigned int old, new, prev;
52
53 do {
54 old = *lock;
55 if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
56 else new = context | _DRM_LOCK_HELD;
57 prev = cmpxchg(lock, old, new);
58 } while (prev != old);
59 if (_DRM_LOCKING_CONTEXT(old) == context) {
60 if (old & _DRM_LOCK_HELD) {
61 if (context != DRM_KERNEL_CONTEXT) {
62 DRM_ERROR("%d holds heavyweight lock\n",
63 context);
64 }
65 return 0;
66 }
67 }
68 if (new == (context | _DRM_LOCK_HELD)) {
69
70 return 1;
71 }
72 return 0;
73}
74
75
76
77int DRM(lock_transfer)(drm_device_t *dev,
78 __volatile__ unsigned int *lock, unsigned int context)
79{
80 unsigned int old, new, prev;
81
82 dev->lock.pid = 0;
83 do {
84 old = *lock;
85 new = context | _DRM_LOCK_HELD;
86 prev = cmpxchg(lock, old, new);
87 } while (prev != old);
88 return 1;
89}
90
91int DRM(lock_free)(drm_device_t *dev,
92 __volatile__ unsigned int *lock, unsigned int context)
93{
94 unsigned int old, new, prev;
95 pid_t pid = dev->lock.pid;
96
97 dev->lock.pid = 0;
98 do {
99 old = *lock;
100 new = 0;
101 prev = cmpxchg(lock, old, new);
102 } while (prev != old);
103 if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
104 DRM_ERROR("%d freed heavyweight lock held by %d (pid %d)\n",
105 context,
106 _DRM_LOCKING_CONTEXT(old),
107 pid);
108 return 1;
109 }
110 wake_up_interruptible(&dev->lock.lock_queue);
111 return 0;
112}
113
114static int DRM(flush_queue)(drm_device_t *dev, int context)
115{
116 DECLARE_WAITQUEUE(entry, current);
117 int ret = 0;
118 drm_queue_t *q = dev->queuelist[context];
119
120 DRM_DEBUG("\n");
121
122 atomic_inc(&q->use_count);
123 if (atomic_read(&q->use_count) > 1) {
124 atomic_inc(&q->block_write);
125 add_wait_queue(&q->flush_queue, &entry);
126 atomic_inc(&q->block_count);
127 for (;;) {
128 current->state = TASK_INTERRUPTIBLE;
129 if (!DRM_BUFCOUNT(&q->waitlist)) break;
130 schedule();
131 if (signal_pending(current)) {
132 ret = -EINTR;
133 break;
134 }
135 }
136 atomic_dec(&q->block_count);
137 current->state = TASK_RUNNING;
138 remove_wait_queue(&q->flush_queue, &entry);
139 }
140 atomic_dec(&q->use_count);
141
142
143
144 return ret;
145}
146
147static int DRM(flush_unblock_queue)(drm_device_t *dev, int context)
148{
149 drm_queue_t *q = dev->queuelist[context];
150
151 DRM_DEBUG("\n");
152
153 atomic_inc(&q->use_count);
154 if (atomic_read(&q->use_count) > 1) {
155 if (atomic_read(&q->block_write)) {
156 atomic_dec(&q->block_write);
157 wake_up_interruptible(&q->write_queue);
158 }
159 }
160 atomic_dec(&q->use_count);
161 return 0;
162}
163
164int DRM(flush_block_and_flush)(drm_device_t *dev, int context,
165 drm_lock_flags_t flags)
166{
167 int ret = 0;
168 int i;
169
170 DRM_DEBUG("\n");
171
172 if (flags & _DRM_LOCK_FLUSH) {
173 ret = DRM(flush_queue)(dev, DRM_KERNEL_CONTEXT);
174 if (!ret) ret = DRM(flush_queue)(dev, context);
175 }
176 if (flags & _DRM_LOCK_FLUSH_ALL) {
177 for (i = 0; !ret && i < dev->queue_count; i++) {
178 ret = DRM(flush_queue)(dev, i);
179 }
180 }
181 return ret;
182}
183
184int DRM(flush_unblock)(drm_device_t *dev, int context, drm_lock_flags_t flags)
185{
186 int ret = 0;
187 int i;
188
189 DRM_DEBUG("\n");
190
191 if (flags & _DRM_LOCK_FLUSH) {
192 ret = DRM(flush_unblock_queue)(dev, DRM_KERNEL_CONTEXT);
193 if (!ret) ret = DRM(flush_unblock_queue)(dev, context);
194 }
195 if (flags & _DRM_LOCK_FLUSH_ALL) {
196 for (i = 0; !ret && i < dev->queue_count; i++) {
197 ret = DRM(flush_unblock_queue)(dev, i);
198 }
199 }
200
201 return ret;
202}
203
204int DRM(finish)(struct inode *inode, struct file *filp, unsigned int cmd,
205 unsigned long arg)
206{
207 drm_file_t *priv = filp->private_data;
208 drm_device_t *dev = priv->dev;
209 int ret = 0;
210 drm_lock_t lock;
211
212 DRM_DEBUG("\n");
213
214 if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
215 return -EFAULT;
216 ret = DRM(flush_block_and_flush)(dev, lock.context, lock.flags);
217 DRM(flush_unblock)(dev, lock.context, lock.flags);
218 return ret;
219}
220
221
222
223
224
225
226
227
228
229
230
231
232
233int DRM(notifier)(void *priv)
234{
235 drm_sigdata_t *s = (drm_sigdata_t *)priv;
236 unsigned int old, new, prev;
237
238
239
240 if (!_DRM_LOCK_IS_HELD(s->lock->lock)
241 || _DRM_LOCKING_CONTEXT(s->lock->lock) != s->context) return 1;
242
243
244
245 do {
246 old = s->lock->lock;
247 new = old | _DRM_LOCK_CONT;
248 prev = cmpxchg(&s->lock->lock, old, new);
249 } while (prev != old);
250 return 0;
251}
252