Merge with Linux 2.6.0-test1.
[linux-2.6/linux-mips.git] / drivers / char / drm / drm_context.h
blob64d32d6c9e41059e3e0aedc4dec264409ce36c8c
1 /**
2 * \file drm_context.h
3 * IOCTLs for generic contexts
4 *
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Gareth Hughes <gareth@valinux.com>
7 */
9 /*
10 * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
12 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
13 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
14 * All Rights Reserved.
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:
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.
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.
37 * ChangeLog:
38 * 2001-11-16 Torsten Duwe <duwe@caldera.de>
39 * added context constructor/destructor hooks,
40 * needed by SiS driver's memory management.
43 #include "drmP.h"
45 #if !__HAVE_CTX_BITMAP
46 #error "__HAVE_CTX_BITMAP must be defined"
47 #endif
50 /******************************************************************/
51 /** \name Context bitmap support */
52 /*@{*/
54 /**
55 * Free a handle from the context bitmap.
57 * \param dev DRM device.
58 * \param ctx_handle context handle.
60 * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
61 * in drm_device::context_sareas, while holding the drm_device::struct_sem
62 * lock.
64 void DRM(ctxbitmap_free)( drm_device_t *dev, int ctx_handle )
66 if ( ctx_handle < 0 ) goto failed;
67 if ( !dev->ctx_bitmap ) goto failed;
69 if ( ctx_handle < DRM_MAX_CTXBITMAP ) {
70 down(&dev->struct_sem);
71 clear_bit( ctx_handle, dev->ctx_bitmap );
72 dev->context_sareas[ctx_handle] = NULL;
73 up(&dev->struct_sem);
74 return;
76 failed:
77 DRM_ERROR( "Attempt to free invalid context handle: %d\n",
78 ctx_handle );
79 return;
82 /**
83 * Context bitmap allocation.
85 * \param dev DRM device.
86 * \return (non-negative) context handle on success or a negative number on failure.
88 * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
89 * drm_device::context_sareas to accommodate the new entry while holding the
90 * drm_device::struct_sem lock.
92 int DRM(ctxbitmap_next)( drm_device_t *dev )
94 int bit;
96 if(!dev->ctx_bitmap) return -1;
98 down(&dev->struct_sem);
99 bit = find_first_zero_bit( dev->ctx_bitmap, DRM_MAX_CTXBITMAP );
100 if ( bit < DRM_MAX_CTXBITMAP ) {
101 set_bit( bit, dev->ctx_bitmap );
102 DRM_DEBUG( "drm_ctxbitmap_next bit : %d\n", bit );
103 if((bit+1) > dev->max_context) {
104 dev->max_context = (bit+1);
105 if(dev->context_sareas) {
106 drm_map_t **ctx_sareas;
108 ctx_sareas = DRM(realloc)(dev->context_sareas,
109 (dev->max_context - 1) *
110 sizeof(*dev->context_sareas),
111 dev->max_context *
112 sizeof(*dev->context_sareas),
113 DRM_MEM_MAPS);
114 if(!ctx_sareas) {
115 clear_bit(bit, dev->ctx_bitmap);
116 up(&dev->struct_sem);
117 return -1;
119 dev->context_sareas = ctx_sareas;
120 dev->context_sareas[bit] = NULL;
121 } else {
122 /* max_context == 1 at this point */
123 dev->context_sareas = DRM(alloc)(
124 dev->max_context *
125 sizeof(*dev->context_sareas),
126 DRM_MEM_MAPS);
127 if(!dev->context_sareas) {
128 clear_bit(bit, dev->ctx_bitmap);
129 up(&dev->struct_sem);
130 return -1;
132 dev->context_sareas[bit] = NULL;
135 up(&dev->struct_sem);
136 return bit;
138 up(&dev->struct_sem);
139 return -1;
143 * Context bitmap initialization.
145 * \param dev DRM device.
147 * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
148 * the drm_device::struct_sem lock.
150 int DRM(ctxbitmap_init)( drm_device_t *dev )
152 int i;
153 int temp;
155 down(&dev->struct_sem);
156 dev->ctx_bitmap = (unsigned long *) DRM(alloc)( PAGE_SIZE,
157 DRM_MEM_CTXBITMAP );
158 if ( dev->ctx_bitmap == NULL ) {
159 up(&dev->struct_sem);
160 return -ENOMEM;
162 memset( (void *)dev->ctx_bitmap, 0, PAGE_SIZE );
163 dev->context_sareas = NULL;
164 dev->max_context = -1;
165 up(&dev->struct_sem);
167 for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
168 temp = DRM(ctxbitmap_next)( dev );
169 DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp );
172 return 0;
176 * Context bitmap cleanup.
178 * \param dev DRM device.
180 * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
181 * the drm_device::struct_sem lock.
183 void DRM(ctxbitmap_cleanup)( drm_device_t *dev )
185 down(&dev->struct_sem);
186 if( dev->context_sareas ) DRM(free)( dev->context_sareas,
187 sizeof(*dev->context_sareas) *
188 dev->max_context,
189 DRM_MEM_MAPS );
190 DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP );
191 up(&dev->struct_sem);
194 /*@}*/
196 /******************************************************************/
197 /** \name Per Context SAREA Support */
198 /*@{*/
201 * Get per-context SAREA.
203 * \param inode device inode.
204 * \param filp file pointer.
205 * \param cmd command.
206 * \param arg user argument pointing to a drm_ctx_priv_map structure.
207 * \return zero on success or a negative number on failure.
209 * Gets the map from drm_device::context_sareas with the handle specified and
210 * returns its handle.
212 int DRM(getsareactx)(struct inode *inode, struct file *filp,
213 unsigned int cmd, unsigned long arg)
215 drm_file_t *priv = filp->private_data;
216 drm_device_t *dev = priv->dev;
217 drm_ctx_priv_map_t request;
218 drm_map_t *map;
220 if (copy_from_user(&request,
221 (drm_ctx_priv_map_t *)arg,
222 sizeof(request)))
223 return -EFAULT;
225 down(&dev->struct_sem);
226 if (dev->max_context < 0 || request.ctx_id >= (unsigned) dev->max_context) {
227 up(&dev->struct_sem);
228 return -EINVAL;
231 map = dev->context_sareas[request.ctx_id];
232 up(&dev->struct_sem);
234 request.handle = map->handle;
235 if (copy_to_user((drm_ctx_priv_map_t *)arg, &request, sizeof(request)))
236 return -EFAULT;
237 return 0;
241 * Set per-context SAREA.
243 * \param inode device inode.
244 * \param filp file pointer.
245 * \param cmd command.
246 * \param arg user argument pointing to a drm_ctx_priv_map structure.
247 * \return zero on success or a negative number on failure.
249 * Searches the mapping specified in \p arg and update the entry in
250 * drm_device::context_sareas with it.
252 int DRM(setsareactx)(struct inode *inode, struct file *filp,
253 unsigned int cmd, unsigned long arg)
255 drm_file_t *priv = filp->private_data;
256 drm_device_t *dev = priv->dev;
257 drm_ctx_priv_map_t request;
258 drm_map_t *map = NULL;
259 drm_map_list_t *r_list = NULL;
260 struct list_head *list;
262 if (copy_from_user(&request,
263 (drm_ctx_priv_map_t *)arg,
264 sizeof(request)))
265 return -EFAULT;
267 down(&dev->struct_sem);
268 list_for_each(list, &dev->maplist->head) {
269 r_list = list_entry(list, drm_map_list_t, head);
270 if(r_list->map &&
271 r_list->map->handle == request.handle)
272 goto found;
274 bad:
275 up(&dev->struct_sem);
276 return -EINVAL;
278 found:
279 map = r_list->map;
280 if (!map) goto bad;
281 if (dev->max_context < 0)
282 goto bad;
283 if (request.ctx_id >= (unsigned) dev->max_context)
284 goto bad;
285 dev->context_sareas[request.ctx_id] = map;
286 up(&dev->struct_sem);
287 return 0;
290 /*@}*/
292 /******************************************************************/
293 /** \name The actual DRM context handling routines */
294 /*@{*/
297 * Switch context.
299 * \param dev DRM device.
300 * \param old old context handle.
301 * \param new new context handle.
302 * \return zero on success or a negative number on failure.
304 * Attempt to set drm_device::context_flag.
306 int DRM(context_switch)( drm_device_t *dev, int old, int new )
308 if ( test_and_set_bit( 0, &dev->context_flag ) ) {
309 DRM_ERROR( "Reentering -- FIXME\n" );
310 return -EBUSY;
314 DRM_DEBUG( "Context switch from %d to %d\n", old, new );
316 if ( new == dev->last_context ) {
317 clear_bit( 0, &dev->context_flag );
318 return 0;
321 return 0;
325 * Complete context switch.
327 * \param dev DRM device.
328 * \param new new context handle.
329 * \return zero on success or a negative number on failure.
331 * Updates drm_device::last_context and drm_device::last_switch. Verifies the
332 * hardware lock is held, clears the drm_device::context_flag and wakes up
333 * drm_device::context_wait.
335 int DRM(context_switch_complete)( drm_device_t *dev, int new )
337 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
338 dev->last_switch = jiffies;
340 if ( !_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ) {
341 DRM_ERROR( "Lock isn't held after context switch\n" );
344 /* If a context switch is ever initiated
345 when the kernel holds the lock, release
346 that lock here. */
347 clear_bit( 0, &dev->context_flag );
348 wake_up( &dev->context_wait );
350 return 0;
354 * Reserve contexts.
356 * \param inode device inode.
357 * \param filp file pointer.
358 * \param cmd command.
359 * \param arg user argument pointing to a drm_ctx_res structure.
360 * \return zero on success or a negative number on failure.
362 int DRM(resctx)( struct inode *inode, struct file *filp,
363 unsigned int cmd, unsigned long arg )
365 drm_ctx_res_t res;
366 drm_ctx_t ctx;
367 int i;
369 if ( copy_from_user( &res, (drm_ctx_res_t *)arg, sizeof(res) ) )
370 return -EFAULT;
372 if ( res.count >= DRM_RESERVED_CONTEXTS ) {
373 memset( &ctx, 0, sizeof(ctx) );
374 for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
375 ctx.handle = i;
376 if ( copy_to_user( &res.contexts[i],
377 &i, sizeof(i) ) )
378 return -EFAULT;
381 res.count = DRM_RESERVED_CONTEXTS;
383 if ( copy_to_user( (drm_ctx_res_t *)arg, &res, sizeof(res) ) )
384 return -EFAULT;
385 return 0;
389 * Add context.
391 * \param inode device inode.
392 * \param filp file pointer.
393 * \param cmd command.
394 * \param arg user argument pointing to a drm_ctx structure.
395 * \return zero on success or a negative number on failure.
397 * Get a new handle for the context and copy to userspace.
399 int DRM(addctx)( struct inode *inode, struct file *filp,
400 unsigned int cmd, unsigned long arg )
402 drm_file_t *priv = filp->private_data;
403 drm_device_t *dev = priv->dev;
404 drm_ctx_t ctx;
406 if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
407 return -EFAULT;
409 ctx.handle = DRM(ctxbitmap_next)( dev );
410 if ( ctx.handle == DRM_KERNEL_CONTEXT ) {
411 /* Skip kernel's context and get a new one. */
412 ctx.handle = DRM(ctxbitmap_next)( dev );
414 DRM_DEBUG( "%d\n", ctx.handle );
415 if ( ctx.handle == -1 ) {
416 DRM_DEBUG( "Not enough free contexts.\n" );
417 /* Should this return -EBUSY instead? */
418 return -ENOMEM;
420 #ifdef DRIVER_CTX_CTOR
421 if ( ctx.handle != DRM_KERNEL_CONTEXT )
422 DRIVER_CTX_CTOR(ctx.handle); /* XXX: also pass dev ? */
423 #endif
425 if ( copy_to_user( (drm_ctx_t *)arg, &ctx, sizeof(ctx) ) )
426 return -EFAULT;
427 return 0;
430 int DRM(modctx)( struct inode *inode, struct file *filp,
431 unsigned int cmd, unsigned long arg )
433 /* This does nothing */
434 return 0;
438 * Get context.
440 * \param inode device inode.
441 * \param filp file pointer.
442 * \param cmd command.
443 * \param arg user argument pointing to a drm_ctx structure.
444 * \return zero on success or a negative number on failure.
446 int DRM(getctx)( struct inode *inode, struct file *filp,
447 unsigned int cmd, unsigned long arg )
449 drm_ctx_t ctx;
451 if ( copy_from_user( &ctx, (drm_ctx_t*)arg, sizeof(ctx) ) )
452 return -EFAULT;
454 /* This is 0, because we don't handle any context flags */
455 ctx.flags = 0;
457 if ( copy_to_user( (drm_ctx_t*)arg, &ctx, sizeof(ctx) ) )
458 return -EFAULT;
459 return 0;
463 * Switch context.
465 * \param inode device inode.
466 * \param filp file pointer.
467 * \param cmd command.
468 * \param arg user argument pointing to a drm_ctx structure.
469 * \return zero on success or a negative number on failure.
471 * Calls context_switch().
473 int DRM(switchctx)( struct inode *inode, struct file *filp,
474 unsigned int cmd, unsigned long arg )
476 drm_file_t *priv = filp->private_data;
477 drm_device_t *dev = priv->dev;
478 drm_ctx_t ctx;
480 if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
481 return -EFAULT;
483 DRM_DEBUG( "%d\n", ctx.handle );
484 return DRM(context_switch)( dev, dev->last_context, ctx.handle );
488 * New context.
490 * \param inode device inode.
491 * \param filp file pointer.
492 * \param cmd command.
493 * \param arg user argument pointing to a drm_ctx structure.
494 * \return zero on success or a negative number on failure.
496 * Calls context_switch_complete().
498 int DRM(newctx)( struct inode *inode, struct file *filp,
499 unsigned int cmd, unsigned long arg )
501 drm_file_t *priv = filp->private_data;
502 drm_device_t *dev = priv->dev;
503 drm_ctx_t ctx;
505 if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
506 return -EFAULT;
508 DRM_DEBUG( "%d\n", ctx.handle );
509 DRM(context_switch_complete)( dev, ctx.handle );
511 return 0;
515 * Remove context.
517 * \param inode device inode.
518 * \param filp file pointer.
519 * \param cmd command.
520 * \param arg user argument pointing to a drm_ctx structure.
521 * \return zero on success or a negative number on failure.
523 * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
525 int DRM(rmctx)( struct inode *inode, struct file *filp,
526 unsigned int cmd, unsigned long arg )
528 drm_file_t *priv = filp->private_data;
529 drm_device_t *dev = priv->dev;
530 drm_ctx_t ctx;
532 if ( copy_from_user( &ctx, (drm_ctx_t *)arg, sizeof(ctx) ) )
533 return -EFAULT;
535 DRM_DEBUG( "%d\n", ctx.handle );
536 if ( ctx.handle == DRM_KERNEL_CONTEXT + 1 ) {
537 priv->remove_auth_on_close = 1;
539 if ( ctx.handle != DRM_KERNEL_CONTEXT ) {
540 #ifdef DRIVER_CTX_DTOR
541 DRIVER_CTX_DTOR(ctx.handle); /* XXX: also pass dev ? */
542 #endif
543 DRM(ctxbitmap_free)( dev, ctx.handle );
546 return 0;
549 /*@}*/