diff options
Diffstat (limited to 'drivers/char/drm/drm_lock.c')
-rw-r--r-- | drivers/char/drm/drm_lock.c | 177 |
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 | ||
38 | static int drm_lock_transfer(drm_device_t *dev, | 38 | static 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); |
41 | static int drm_notifier(void *priv); | 41 | static 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 | */ |
54 | int drm_lock( struct inode *inode, struct file *filp, | 54 | int 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 | */ |
149 | int drm_unlock( struct inode *inode, struct file *filp, | 147 | int 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 | */ |
233 | static int drm_lock_transfer(drm_device_t *dev, | 233 | static 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 | */ |
259 | int drm_lock_free(drm_device_t *dev, | 259 | int 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 | */ |
291 | static int drm_notifier(void *priv) | 290 | static 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; |