Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / drm / drm_context.h
1 /* drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
2  * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
3  *
4  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6  * All Rights Reserved.
7  *
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:
14  *
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
17  * Software.
18  *
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  * VA LINUX SYSTEMS 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
25  * OTHER DEALINGS IN THE SOFTWARE.
26  *
27  * Authors:
28  *    Rickard E. (Rik) Faith <faith@valinux.com>
29  *    Gareth Hughes <gareth@valinux.com>
30  * $FreeBSD: src/sys/dev/drm/drm_context.h,v 1.4.2.1 2003/04/26 07:05:28 anholt Exp $
31  */
32
33 #include "dev/drm/drmP.h"
34
35 #if !__HAVE_CTX_BITMAP
36 #error "__HAVE_CTX_BITMAP must be defined"
37 #endif
38
39 /* ================================================================
40  * Context bitmap support
41  */
42
43 void DRM(ctxbitmap_free)( drm_device_t *dev, int ctx_handle )
44 {
45         if ( ctx_handle < 0 ) goto failed;
46         if ( !dev->ctx_bitmap ) goto failed;
47
48         if ( ctx_handle < DRM_MAX_CTXBITMAP ) {
49                 DRM_LOCK;
50                 clear_bit( ctx_handle, dev->ctx_bitmap );
51                 dev->context_sareas[ctx_handle] = NULL;
52                 DRM_UNLOCK;
53                 return;
54         }
55 failed:
56         DRM_ERROR( "Attempt to free invalid context handle: %d\n",
57                    ctx_handle );
58         return;
59 }
60
61 int DRM(ctxbitmap_next)( drm_device_t *dev )
62 {
63         int bit;
64
65         if(!dev->ctx_bitmap) return -1;
66
67         DRM_LOCK;
68         bit = find_first_zero_bit( dev->ctx_bitmap, DRM_MAX_CTXBITMAP );
69         if ( bit < DRM_MAX_CTXBITMAP ) {
70                 set_bit( bit, dev->ctx_bitmap );
71                 DRM_DEBUG( "drm_ctxbitmap_next bit : %d\n", bit );
72                 if((bit+1) > dev->max_context) {
73                         dev->max_context = (bit+1);
74                         if(dev->context_sareas) {
75                                 drm_local_map_t **ctx_sareas;
76
77                                 ctx_sareas = DRM(realloc)(dev->context_sareas,
78                                                 (dev->max_context - 1) * 
79                                                 sizeof(*dev->context_sareas),
80                                                 dev->max_context * 
81                                                 sizeof(*dev->context_sareas),
82                                                 DRM_MEM_MAPS);
83                                 if(!ctx_sareas) {
84                                         clear_bit(bit, dev->ctx_bitmap);
85                                         DRM_UNLOCK;
86                                         return -1;
87                                 }
88                                 dev->context_sareas = ctx_sareas;
89                                 dev->context_sareas[bit] = NULL;
90                         } else {
91                                 /* max_context == 1 at this point */
92                                 dev->context_sareas = DRM(alloc)(
93                                                 dev->max_context * 
94                                                 sizeof(*dev->context_sareas),
95                                                 DRM_MEM_MAPS);
96                                 if(!dev->context_sareas) {
97                                         clear_bit(bit, dev->ctx_bitmap);
98                                         DRM_UNLOCK;
99                                         return -1;
100                                 }
101                                 dev->context_sareas[bit] = NULL;
102                         }
103                 }
104                 DRM_UNLOCK;
105                 return bit;
106         }
107         DRM_UNLOCK;
108         return -1;
109 }
110
111 int DRM(ctxbitmap_init)( drm_device_t *dev )
112 {
113         int i;
114         int temp;
115
116         DRM_LOCK;
117         dev->ctx_bitmap = (atomic_t *) DRM(alloc)( PAGE_SIZE,
118                                                         DRM_MEM_CTXBITMAP );
119         if ( dev->ctx_bitmap == NULL ) {
120                 DRM_UNLOCK;
121                 return DRM_ERR(ENOMEM);
122         }
123         memset( (void *)dev->ctx_bitmap, 0, PAGE_SIZE );
124         dev->context_sareas = NULL;
125         dev->max_context = -1;
126         DRM_UNLOCK;
127
128         for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
129                 temp = DRM(ctxbitmap_next)( dev );
130                 DRM_DEBUG( "drm_ctxbitmap_init : %d\n", temp );
131         }
132
133         return 0;
134 }
135
136 void DRM(ctxbitmap_cleanup)( drm_device_t *dev )
137 {
138         DRM_LOCK;
139         if( dev->context_sareas ) DRM(free)( dev->context_sareas,
140                                              sizeof(*dev->context_sareas) * 
141                                              dev->max_context,
142                                              DRM_MEM_MAPS );
143         DRM(free)( (void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP );
144         DRM_UNLOCK;
145 }
146
147 /* ================================================================
148  * Per Context SAREA Support
149  */
150
151 int DRM(getsareactx)( DRM_IOCTL_ARGS )
152 {
153         DRM_DEVICE;
154         drm_ctx_priv_map_t request;
155         drm_local_map_t *map;
156
157         DRM_COPY_FROM_USER_IOCTL( request, (drm_ctx_priv_map_t *)data, 
158                            sizeof(request) );
159
160         DRM_LOCK;
161         if (dev->max_context < 0 || request.ctx_id >= (unsigned) dev->max_context) {
162                 DRM_UNLOCK;
163                 return DRM_ERR(EINVAL);
164         }
165
166         map = dev->context_sareas[request.ctx_id];
167         DRM_UNLOCK;
168
169         request.handle = map->handle;
170
171         DRM_COPY_TO_USER_IOCTL( (drm_ctx_priv_map_t *)data, request, sizeof(request) );
172
173         return 0;
174 }
175
176 int DRM(setsareactx)( DRM_IOCTL_ARGS )
177 {
178         DRM_DEVICE;
179         drm_ctx_priv_map_t request;
180         drm_local_map_t *map = NULL;
181         drm_map_list_entry_t *list;
182
183         DRM_COPY_FROM_USER_IOCTL( request, (drm_ctx_priv_map_t *)data,
184                            sizeof(request) );
185
186         DRM_LOCK;
187         TAILQ_FOREACH(list, dev->maplist, link) {
188                 map=list->map;
189                 if(map->handle == request.handle) {
190                         if (dev->max_context < 0)
191                                 goto bad;
192                         if (request.ctx_id >= (unsigned) dev->max_context)
193                                 goto bad;
194                         dev->context_sareas[request.ctx_id] = map;
195                         DRM_UNLOCK;
196                         return 0;
197                 }
198         }
199
200 bad:
201         DRM_UNLOCK;
202         return DRM_ERR(EINVAL);
203 }
204
205 /* ================================================================
206  * The actual DRM context handling routines
207  */
208
209 int DRM(context_switch)( drm_device_t *dev, int old, int new )
210 {
211         if ( test_and_set_bit( 0, &dev->context_flag ) ) {
212                 DRM_ERROR( "Reentering -- FIXME\n" );
213                 return DRM_ERR(EBUSY);
214         }
215
216         DRM_DEBUG( "Context switch from %d to %d\n", old, new );
217
218         if ( new == dev->last_context ) {
219                 clear_bit( 0, &dev->context_flag );
220                 return 0;
221         }
222
223         return 0;
224 }
225
226 int DRM(context_switch_complete)( drm_device_t *dev, int new )
227 {
228         dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
229
230         if ( !_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) ) {
231                 DRM_ERROR( "Lock isn't held after context switch\n" );
232         }
233
234                                 /* If a context switch is ever initiated
235                                    when the kernel holds the lock, release
236                                    that lock here. */
237         clear_bit( 0, &dev->context_flag );
238
239         return 0;
240 }
241
242 int DRM(resctx)( DRM_IOCTL_ARGS )
243 {
244         drm_ctx_res_t res;
245         drm_ctx_t ctx;
246         int i;
247
248         DRM_COPY_FROM_USER_IOCTL( res, (drm_ctx_res_t *)data, sizeof(res) );
249
250         if ( res.count >= DRM_RESERVED_CONTEXTS ) {
251                 memset( &ctx, 0, sizeof(ctx) );
252                 for ( i = 0 ; i < DRM_RESERVED_CONTEXTS ; i++ ) {
253                         ctx.handle = i;
254                         if ( DRM_COPY_TO_USER( &res.contexts[i],
255                                            &i, sizeof(i) ) )
256                                 return DRM_ERR(EFAULT);
257                 }
258         }
259         res.count = DRM_RESERVED_CONTEXTS;
260
261         DRM_COPY_TO_USER_IOCTL( (drm_ctx_res_t *)data, res, sizeof(res) );
262
263         return 0;
264 }
265
266 int DRM(addctx)( DRM_IOCTL_ARGS )
267 {
268         DRM_DEVICE;
269         drm_ctx_t ctx;
270
271         DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
272
273         ctx.handle = DRM(ctxbitmap_next)( dev );
274         if ( ctx.handle == DRM_KERNEL_CONTEXT ) {
275                                 /* Skip kernel's context and get a new one. */
276                 ctx.handle = DRM(ctxbitmap_next)( dev );
277         }
278         DRM_DEBUG( "%d\n", ctx.handle );
279         if ( ctx.handle == -1 ) {
280                 DRM_DEBUG( "Not enough free contexts.\n" );
281                                 /* Should this return -EBUSY instead? */
282                 return DRM_ERR(ENOMEM);
283         }
284
285         DRM_COPY_TO_USER_IOCTL( (drm_ctx_t *)data, ctx, sizeof(ctx) );
286
287         return 0;
288 }
289
290 int DRM(modctx)( DRM_IOCTL_ARGS )
291 {
292         /* This does nothing */
293         return 0;
294 }
295
296 int DRM(getctx)( DRM_IOCTL_ARGS )
297 {
298         drm_ctx_t ctx;
299
300         DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
301
302         /* This is 0, because we don't handle any context flags */
303         ctx.flags = 0;
304
305         DRM_COPY_TO_USER_IOCTL( (drm_ctx_t *)data, ctx, sizeof(ctx) );
306
307         return 0;
308 }
309
310 int DRM(switchctx)( DRM_IOCTL_ARGS )
311 {
312         DRM_DEVICE;
313         drm_ctx_t ctx;
314
315         DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
316
317         DRM_DEBUG( "%d\n", ctx.handle );
318         return DRM(context_switch)( dev, dev->last_context, ctx.handle );
319 }
320
321 int DRM(newctx)( DRM_IOCTL_ARGS )
322 {
323         DRM_DEVICE;
324         drm_ctx_t ctx;
325
326         DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
327
328         DRM_DEBUG( "%d\n", ctx.handle );
329         DRM(context_switch_complete)( dev, ctx.handle );
330
331         return 0;
332 }
333
334 int DRM(rmctx)( DRM_IOCTL_ARGS )
335 {
336         DRM_DEVICE;
337         drm_ctx_t ctx;
338
339         DRM_COPY_FROM_USER_IOCTL( ctx, (drm_ctx_t *)data, sizeof(ctx) );
340
341         DRM_DEBUG( "%d\n", ctx.handle );
342         if ( ctx.handle != DRM_KERNEL_CONTEXT ) {
343                 DRM(ctxbitmap_free)( dev, ctx.handle );
344         }
345
346         return 0;
347 }