3 * IOCTLs for generic contexts
5 * \author Rickard E. (Rik) Faith <faith@valinux.com>
6 * \author Gareth Hughes <gareth@valinux.com>
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
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.
38 * 2001-11-16 Torsten Duwe <duwe@caldera.de>
39 * added context constructor/destructor hooks,
40 * needed by SiS driver's memory management.
45 /******************************************************************/
46 /** \name Context bitmap support */
50 * Free a handle from the context bitmap.
52 * \param dev DRM device.
53 * \param ctx_handle context handle.
55 * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
56 * in drm_device::context_sareas, while holding the drm_device::struct_sem
59 void drm_ctxbitmap_free( drm_device_t
*dev
, int ctx_handle
)
61 if ( ctx_handle
< 0 ) goto failed
;
62 if ( !dev
->ctx_bitmap
) goto failed
;
64 if ( ctx_handle
< DRM_MAX_CTXBITMAP
) {
65 down(&dev
->struct_sem
);
66 clear_bit( ctx_handle
, dev
->ctx_bitmap
);
67 dev
->context_sareas
[ctx_handle
] = NULL
;
72 DRM_ERROR( "Attempt to free invalid context handle: %d\n",
78 * Context bitmap allocation.
80 * \param dev DRM device.
81 * \return (non-negative) context handle on success or a negative number on failure.
83 * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
84 * drm_device::context_sareas to accommodate the new entry while holding the
85 * drm_device::struct_sem lock.
87 static int drm_ctxbitmap_next( drm_device_t
*dev
)
91 if(!dev
->ctx_bitmap
) return -1;
93 down(&dev
->struct_sem
);
94 bit
= find_first_zero_bit( dev
->ctx_bitmap
, DRM_MAX_CTXBITMAP
);
95 if ( bit
< DRM_MAX_CTXBITMAP
) {
96 set_bit( bit
, dev
->ctx_bitmap
);
97 DRM_DEBUG( "drm_ctxbitmap_next bit : %d\n", bit
);
98 if((bit
+1) > dev
->max_context
) {
99 dev
->max_context
= (bit
+1);
100 if(dev
->context_sareas
) {
101 drm_map_t
**ctx_sareas
;
103 ctx_sareas
= drm_realloc(dev
->context_sareas
,
104 (dev
->max_context
- 1) *
105 sizeof(*dev
->context_sareas
),
107 sizeof(*dev
->context_sareas
),
110 clear_bit(bit
, dev
->ctx_bitmap
);
111 up(&dev
->struct_sem
);
114 dev
->context_sareas
= ctx_sareas
;
115 dev
->context_sareas
[bit
] = NULL
;
117 /* max_context == 1 at this point */
118 dev
->context_sareas
= drm_alloc(
120 sizeof(*dev
->context_sareas
),
122 if(!dev
->context_sareas
) {
123 clear_bit(bit
, dev
->ctx_bitmap
);
124 up(&dev
->struct_sem
);
127 dev
->context_sareas
[bit
] = NULL
;
130 up(&dev
->struct_sem
);
133 up(&dev
->struct_sem
);
138 * Context bitmap initialization.
140 * \param dev DRM device.
142 * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
143 * the drm_device::struct_sem lock.
145 int drm_ctxbitmap_init( drm_device_t
*dev
)
150 down(&dev
->struct_sem
);
151 dev
->ctx_bitmap
= (unsigned long *) drm_alloc( PAGE_SIZE
,
153 if ( dev
->ctx_bitmap
== NULL
) {
154 up(&dev
->struct_sem
);
157 memset( (void *)dev
->ctx_bitmap
, 0, PAGE_SIZE
);
158 dev
->context_sareas
= NULL
;
159 dev
->max_context
= -1;
160 up(&dev
->struct_sem
);
162 for ( i
= 0 ; i
< DRM_RESERVED_CONTEXTS
; i
++ ) {
163 temp
= drm_ctxbitmap_next( dev
);
164 DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp
);
171 * Context bitmap cleanup.
173 * \param dev DRM device.
175 * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
176 * the drm_device::struct_sem lock.
178 void drm_ctxbitmap_cleanup( drm_device_t
*dev
)
180 down(&dev
->struct_sem
);
181 if( dev
->context_sareas
) drm_free( dev
->context_sareas
,
182 sizeof(*dev
->context_sareas
) *
185 drm_free( (void *)dev
->ctx_bitmap
, PAGE_SIZE
, DRM_MEM_CTXBITMAP
);
186 up(&dev
->struct_sem
);
191 /******************************************************************/
192 /** \name Per Context SAREA Support */
196 * Get per-context SAREA.
198 * \param inode device inode.
199 * \param filp file pointer.
200 * \param cmd command.
201 * \param arg user argument pointing to a drm_ctx_priv_map structure.
202 * \return zero on success or a negative number on failure.
204 * Gets the map from drm_device::context_sareas with the handle specified and
205 * returns its handle.
207 int drm_getsareactx(struct inode
*inode
, struct file
*filp
,
208 unsigned int cmd
, unsigned long arg
)
210 drm_file_t
*priv
= filp
->private_data
;
211 drm_device_t
*dev
= priv
->head
->dev
;
212 drm_ctx_priv_map_t __user
*argp
= (void __user
*)arg
;
213 drm_ctx_priv_map_t request
;
215 drm_map_list_t
*_entry
;
217 if (copy_from_user(&request
, argp
, sizeof(request
)))
220 down(&dev
->struct_sem
);
221 if (dev
->max_context
< 0 || request
.ctx_id
>= (unsigned) dev
->max_context
) {
222 up(&dev
->struct_sem
);
226 map
= dev
->context_sareas
[request
.ctx_id
];
227 up(&dev
->struct_sem
);
230 list_for_each_entry(_entry
, &dev
->maplist
->head
,head
) {
231 if (_entry
->map
== map
) {
232 request
.handle
= (void *)(unsigned long)_entry
->user_token
;
236 if (request
.handle
== 0)
240 if (copy_to_user(argp
, &request
, sizeof(request
)))
246 * Set per-context SAREA.
248 * \param inode device inode.
249 * \param filp file pointer.
250 * \param cmd command.
251 * \param arg user argument pointing to a drm_ctx_priv_map structure.
252 * \return zero on success or a negative number on failure.
254 * Searches the mapping specified in \p arg and update the entry in
255 * drm_device::context_sareas with it.
257 int drm_setsareactx(struct inode
*inode
, struct file
*filp
,
258 unsigned int cmd
, unsigned long arg
)
260 drm_file_t
*priv
= filp
->private_data
;
261 drm_device_t
*dev
= priv
->head
->dev
;
262 drm_ctx_priv_map_t request
;
263 drm_map_t
*map
= NULL
;
264 drm_map_list_t
*r_list
= NULL
;
265 struct list_head
*list
;
267 if (copy_from_user(&request
,
268 (drm_ctx_priv_map_t __user
*)arg
,
272 down(&dev
->struct_sem
);
273 list_for_each(list
, &dev
->maplist
->head
) {
274 r_list
= list_entry(list
, drm_map_list_t
, head
);
276 && r_list
->user_token
== (unsigned long) request
.handle
)
280 up(&dev
->struct_sem
);
286 if (dev
->max_context
< 0)
288 if (request
.ctx_id
>= (unsigned) dev
->max_context
)
290 dev
->context_sareas
[request
.ctx_id
] = map
;
291 up(&dev
->struct_sem
);
297 /******************************************************************/
298 /** \name The actual DRM context handling routines */
304 * \param dev DRM device.
305 * \param old old context handle.
306 * \param new new context handle.
307 * \return zero on success or a negative number on failure.
309 * Attempt to set drm_device::context_flag.
311 static int drm_context_switch( drm_device_t
*dev
, int old
, int new )
313 if ( test_and_set_bit( 0, &dev
->context_flag
) ) {
314 DRM_ERROR( "Reentering -- FIXME\n" );
319 DRM_DEBUG( "Context switch from %d to %d\n", old
, new );
321 if ( new == dev
->last_context
) {
322 clear_bit( 0, &dev
->context_flag
);
330 * Complete context switch.
332 * \param dev DRM device.
333 * \param new new context handle.
334 * \return zero on success or a negative number on failure.
336 * Updates drm_device::last_context and drm_device::last_switch. Verifies the
337 * hardware lock is held, clears the drm_device::context_flag and wakes up
338 * drm_device::context_wait.
340 static int drm_context_switch_complete( drm_device_t
*dev
, int new )
342 dev
->last_context
= new; /* PRE/POST: This is the _only_ writer. */
343 dev
->last_switch
= jiffies
;
345 if ( !_DRM_LOCK_IS_HELD(dev
->lock
.hw_lock
->lock
) ) {
346 DRM_ERROR( "Lock isn't held after context switch\n" );
349 /* If a context switch is ever initiated
350 when the kernel holds the lock, release
352 clear_bit( 0, &dev
->context_flag
);
353 wake_up( &dev
->context_wait
);
361 * \param inode device inode.
362 * \param filp file pointer.
363 * \param cmd command.
364 * \param arg user argument pointing to a drm_ctx_res structure.
365 * \return zero on success or a negative number on failure.
367 int drm_resctx( struct inode
*inode
, struct file
*filp
,
368 unsigned int cmd
, unsigned long arg
)
371 drm_ctx_t __user
*argp
= (void __user
*)arg
;
375 if ( copy_from_user( &res
, argp
, sizeof(res
) ) )
378 if ( res
.count
>= DRM_RESERVED_CONTEXTS
) {
379 memset( &ctx
, 0, sizeof(ctx
) );
380 for ( i
= 0 ; i
< DRM_RESERVED_CONTEXTS
; i
++ ) {
382 if ( copy_to_user( &res
.contexts
[i
],
383 &ctx
, sizeof(ctx
) ) )
387 res
.count
= DRM_RESERVED_CONTEXTS
;
389 if ( copy_to_user( argp
, &res
, sizeof(res
) ) )
397 * \param inode device inode.
398 * \param filp file pointer.
399 * \param cmd command.
400 * \param arg user argument pointing to a drm_ctx structure.
401 * \return zero on success or a negative number on failure.
403 * Get a new handle for the context and copy to userspace.
405 int drm_addctx( struct inode
*inode
, struct file
*filp
,
406 unsigned int cmd
, unsigned long arg
)
408 drm_file_t
*priv
= filp
->private_data
;
409 drm_device_t
*dev
= priv
->head
->dev
;
410 drm_ctx_list_t
* ctx_entry
;
411 drm_ctx_t __user
*argp
= (void __user
*)arg
;
414 if ( copy_from_user( &ctx
, argp
, sizeof(ctx
) ) )
417 ctx
.handle
= drm_ctxbitmap_next( dev
);
418 if ( ctx
.handle
== DRM_KERNEL_CONTEXT
) {
419 /* Skip kernel's context and get a new one. */
420 ctx
.handle
= drm_ctxbitmap_next( dev
);
422 DRM_DEBUG( "%d\n", ctx
.handle
);
423 if ( ctx
.handle
== -1 ) {
424 DRM_DEBUG( "Not enough free contexts.\n" );
425 /* Should this return -EBUSY instead? */
429 if ( ctx
.handle
!= DRM_KERNEL_CONTEXT
)
431 if (dev
->driver
->context_ctor
)
432 dev
->driver
->context_ctor(dev
, ctx
.handle
);
435 ctx_entry
= drm_alloc( sizeof(*ctx_entry
), DRM_MEM_CTXLIST
);
437 DRM_DEBUG("out of memory\n");
441 INIT_LIST_HEAD( &ctx_entry
->head
);
442 ctx_entry
->handle
= ctx
.handle
;
443 ctx_entry
->tag
= priv
;
445 down( &dev
->ctxlist_sem
);
446 list_add( &ctx_entry
->head
, &dev
->ctxlist
->head
);
448 up( &dev
->ctxlist_sem
);
450 if ( copy_to_user( argp
, &ctx
, sizeof(ctx
) ) )
455 int drm_modctx( struct inode
*inode
, struct file
*filp
,
456 unsigned int cmd
, unsigned long arg
)
458 /* This does nothing */
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 int drm_getctx( struct inode
*inode
, struct file
*filp
,
472 unsigned int cmd
, unsigned long arg
)
474 drm_ctx_t __user
*argp
= (void __user
*)arg
;
477 if ( copy_from_user( &ctx
, argp
, sizeof(ctx
) ) )
480 /* This is 0, because we don't handle any context flags */
483 if ( copy_to_user( argp
, &ctx
, sizeof(ctx
) ) )
491 * \param inode device inode.
492 * \param filp file pointer.
493 * \param cmd command.
494 * \param arg user argument pointing to a drm_ctx structure.
495 * \return zero on success or a negative number on failure.
497 * Calls context_switch().
499 int drm_switchctx( struct inode
*inode
, struct file
*filp
,
500 unsigned int cmd
, unsigned long arg
)
502 drm_file_t
*priv
= filp
->private_data
;
503 drm_device_t
*dev
= priv
->head
->dev
;
506 if ( copy_from_user( &ctx
, (drm_ctx_t __user
*)arg
, sizeof(ctx
) ) )
509 DRM_DEBUG( "%d\n", ctx
.handle
);
510 return drm_context_switch( dev
, dev
->last_context
, ctx
.handle
);
516 * \param inode device inode.
517 * \param filp file pointer.
518 * \param cmd command.
519 * \param arg user argument pointing to a drm_ctx structure.
520 * \return zero on success or a negative number on failure.
522 * Calls context_switch_complete().
524 int drm_newctx( struct inode
*inode
, struct file
*filp
,
525 unsigned int cmd
, unsigned long arg
)
527 drm_file_t
*priv
= filp
->private_data
;
528 drm_device_t
*dev
= priv
->head
->dev
;
531 if ( copy_from_user( &ctx
, (drm_ctx_t __user
*)arg
, sizeof(ctx
) ) )
534 DRM_DEBUG( "%d\n", ctx
.handle
);
535 drm_context_switch_complete( dev
, ctx
.handle
);
543 * \param inode device inode.
544 * \param filp file pointer.
545 * \param cmd command.
546 * \param arg user argument pointing to a drm_ctx structure.
547 * \return zero on success or a negative number on failure.
549 * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
551 int drm_rmctx( struct inode
*inode
, struct file
*filp
,
552 unsigned int cmd
, unsigned long arg
)
554 drm_file_t
*priv
= filp
->private_data
;
555 drm_device_t
*dev
= priv
->head
->dev
;
558 if ( copy_from_user( &ctx
, (drm_ctx_t __user
*)arg
, sizeof(ctx
) ) )
561 DRM_DEBUG( "%d\n", ctx
.handle
);
562 if ( ctx
.handle
== DRM_KERNEL_CONTEXT
+ 1 ) {
563 priv
->remove_auth_on_close
= 1;
565 if ( ctx
.handle
!= DRM_KERNEL_CONTEXT
) {
566 if (dev
->driver
->context_dtor
)
567 dev
->driver
->context_dtor(dev
, ctx
.handle
);
568 drm_ctxbitmap_free( dev
, ctx
.handle
);
571 down( &dev
->ctxlist_sem
);
572 if ( !list_empty( &dev
->ctxlist
->head
) ) {
573 drm_ctx_list_t
*pos
, *n
;
575 list_for_each_entry_safe( pos
, n
, &dev
->ctxlist
->head
, head
) {
576 if ( pos
->handle
== ctx
.handle
) {
577 list_del( &pos
->head
);
578 drm_free( pos
, sizeof(*pos
), DRM_MEM_CTXLIST
);
583 up( &dev
->ctxlist_sem
);