1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
8 * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
9 */
10 /*
11 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
12 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13 * All Rights Reserved.
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice (including the next
23 * paragraph) shall be included in all copies or substantial portions of the
24 * Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32 * OTHER DEALINGS IN THE SOFTWARE.
33 *
34 * Authors:
35 * Rickard E. (Rik) Faith <faith@valinux.com>
36 * Gareth Hughes <gareth@valinux.com>
37 *
38 */
39
40 #pragma ident "%Z%%M% %I% %E% SMI"
41
42 #include "drmP.h"
43 #include "drm_io32.h"
44
45 static inline int
find_first_zero_bit(volatile void * p,int max)46 find_first_zero_bit(volatile void *p, int max)
47 {
48 int b;
49 volatile int *ptr = (volatile int *)p;
50
51 for (b = 0; b < max; b += 32) {
52 if (ptr[b >> 5] != ~0) {
53 for (;;) {
54 if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
55 return (b);
56 b++;
57 }
58 }
59 }
60 return (max);
61 }
62
63 /*
64 * Context bitmap support
65 */
66 void
drm_ctxbitmap_free(drm_device_t * dev,int ctx_handle)67 drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
68 {
69 if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
70 dev->ctx_bitmap == NULL) {
71 DRM_ERROR("drm_ctxbitmap_free: Attempt to free\
72 invalid context handle: %d\n",
73 ctx_handle);
74 return;
75 }
76
77 DRM_LOCK();
78 clear_bit(ctx_handle, dev->ctx_bitmap);
79 dev->context_sareas[ctx_handle] = NULL;
80 DRM_UNLOCK();
81 }
82
83 /* Is supposed to return -1 if any error by calling functions */
84 int
drm_ctxbitmap_next(drm_device_t * dev)85 drm_ctxbitmap_next(drm_device_t *dev)
86 {
87 int bit;
88
89 if (dev->ctx_bitmap == NULL)
90 return (-1);
91
92 DRM_LOCK();
93 bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
94 if (bit >= DRM_MAX_CTXBITMAP) {
95 DRM_UNLOCK();
96 return (-1);
97 }
98
99 set_bit(bit, dev->ctx_bitmap);
100 DRM_DEBUG("drm_ctxbitmap_next: bit : %d", bit);
101 if ((bit+1) > dev->max_context) {
102 dev->max_context = (bit+1);
103 if (dev->context_sareas != NULL) {
104 drm_local_map_t **ctx_sareas;
105 ctx_sareas = drm_realloc(dev->context_sareas,
106 (dev->max_context - 1) *
107 sizeof (*dev->context_sareas),
108 dev->max_context *
109 sizeof (*dev->context_sareas),
110 DRM_MEM_MAPS);
111 if (ctx_sareas == NULL) {
112 clear_bit(bit, dev->ctx_bitmap);
113 DRM_UNLOCK();
114 return (-1);
115 }
116 dev->context_sareas = ctx_sareas;
117 dev->context_sareas[bit] = NULL;
118 } else {
119 /* max_context == 1 at this point */
120 dev->context_sareas = drm_alloc(dev->max_context *
121 sizeof (*dev->context_sareas), KM_NOSLEEP);
122 if (dev->context_sareas == NULL) {
123 clear_bit(bit, dev->ctx_bitmap);
124 DRM_UNLOCK();
125 return (-1);
126 }
127 dev->context_sareas[bit] = NULL;
128 }
129 }
130 DRM_UNLOCK();
131 DRM_DEBUG("drm_ctxbitmap_next: return %d", bit);
132 return (bit);
133 }
134
135 int
drm_ctxbitmap_init(drm_device_t * dev)136 drm_ctxbitmap_init(drm_device_t *dev)
137 {
138 int i;
139 int temp;
140
141 DRM_LOCK();
142 dev->ctx_bitmap = drm_calloc(1, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
143 if (dev->ctx_bitmap == NULL) {
144 DRM_UNLOCK();
145 return (ENOMEM);
146 }
147 dev->context_sareas = NULL;
148 dev->max_context = -1;
149 DRM_UNLOCK();
150
151 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
152 temp = drm_ctxbitmap_next(dev);
153 DRM_DEBUG("drm_ctxbitmap_init : %d", temp);
154 }
155 return (0);
156 }
157
158 void
drm_ctxbitmap_cleanup(drm_device_t * dev)159 drm_ctxbitmap_cleanup(drm_device_t *dev)
160 {
161 DRM_LOCK();
162 if (dev->context_sareas != NULL)
163 drm_free(dev->context_sareas,
164 sizeof (*dev->context_sareas) *
165 dev->max_context,
166 DRM_MEM_MAPS);
167 drm_free(dev->ctx_bitmap, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
168 DRM_UNLOCK();
169 }
170
171 /*
172 * Per Context SAREA Support
173 */
174 /*ARGSUSED*/
175 int
drm_getsareactx(DRM_IOCTL_ARGS)176 drm_getsareactx(DRM_IOCTL_ARGS)
177 {
178 DRM_DEVICE;
179 drm_ctx_priv_map_t request;
180 drm_local_map_t *map;
181
182 #ifdef _MULTI_DATAMODEL
183 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
184 drm_ctx_priv_map_32_t request32;
185 DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
186 sizeof (drm_ctx_priv_map_32_t));
187 request.ctx_id = request32.ctx_id;
188 request.handle = (void *)(uintptr_t)request32.handle;
189 } else
190 #endif
191 DRM_COPYFROM_WITH_RETURN(&request, (void *)data,
192 sizeof (request));
193
194 DRM_LOCK();
195 if (dev->max_context < 0 || request.ctx_id >= (unsigned)
196 dev->max_context) {
197 DRM_UNLOCK();
198 return (EINVAL);
199 }
200
201 map = dev->context_sareas[request.ctx_id];
202 DRM_UNLOCK();
203
204 if (!map)
205 return (EINVAL);
206
207 request.handle = map->handle;
208
209 #ifdef _MULTI_DATAMODEL
210 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
211 drm_ctx_priv_map_32_t request32;
212 request32.ctx_id = request.ctx_id;
213 request32.handle = (caddr32_t)(uintptr_t)request.handle;
214 DRM_COPYTO_WITH_RETURN((void *)data, &request32,
215 sizeof (drm_ctx_priv_map_32_t));
216 } else
217 #endif
218 DRM_COPYTO_WITH_RETURN((void *)data,
219 &request, sizeof (request));
220
221 return (0);
222 }
223
224 /*ARGSUSED*/
225 int
drm_setsareactx(DRM_IOCTL_ARGS)226 drm_setsareactx(DRM_IOCTL_ARGS)
227 {
228 DRM_DEVICE;
229 drm_ctx_priv_map_t request;
230 drm_local_map_t *map = NULL;
231
232 #ifdef _MULTI_DATAMODEL
233 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
234 drm_ctx_priv_map_32_t request32;
235
236 DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
237 sizeof (drm_ctx_priv_map_32_t));
238 request.ctx_id = request32.ctx_id;
239 request.handle = (void *)(uintptr_t)request32.handle;
240 } else
241 #endif
242 DRM_COPYFROM_WITH_RETURN(&request,
243 (void *)data, sizeof (request));
244
245 DRM_LOCK();
246 TAILQ_FOREACH(map, &dev->maplist, link) {
247 if (map->handle == request.handle) {
248 if (dev->max_context < 0)
249 goto bad;
250 if (request.ctx_id >= (unsigned)dev->max_context)
251 goto bad;
252 dev->context_sareas[request.ctx_id] = map;
253 DRM_UNLOCK();
254 return (0);
255 }
256 }
257
258 bad:
259 DRM_UNLOCK();
260 return (EINVAL);
261 }
262
263 /*
264 * The actual DRM context handling routines
265 */
266 int
drm_context_switch(drm_device_t * dev,int old,int new)267 drm_context_switch(drm_device_t *dev, int old, int new)
268 {
269 if (test_and_set_bit(0, &dev->context_flag)) {
270 DRM_ERROR("drm_context_switch: Reentering -- FIXME");
271 return (EBUSY);
272 }
273
274 DRM_DEBUG("drm_context_switch: Context switch from %d to %d",
275 old, new);
276
277 if (new == dev->last_context) {
278 clear_bit(0, &dev->context_flag);
279 return (0);
280 }
281
282 return (0);
283 }
284
285 int
drm_context_switch_complete(drm_device_t * dev,int new)286 drm_context_switch_complete(drm_device_t *dev, int new)
287 {
288 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
289
290 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
291 DRM_ERROR(
292 "drm_context_switch_complete: Lock not held");
293 }
294 /*
295 * If a context switch is ever initiated
296 * when the kernel holds the lock, release
297 * that lock here.
298 */
299 clear_bit(0, &dev->context_flag);
300
301 return (0);
302 }
303
304 /*ARGSUSED*/
305 int
drm_resctx(DRM_IOCTL_ARGS)306 drm_resctx(DRM_IOCTL_ARGS)
307 {
308 drm_ctx_res_t res;
309 drm_ctx_t ctx;
310 int i;
311
312 #ifdef _MULTI_DATAMODEL
313 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
314 drm_ctx_res_32_t res32;
315 DRM_COPYFROM_WITH_RETURN(&res32, (void *)data, sizeof (res32));
316 res.count = res32.count;
317 res.contexts = (drm_ctx_t *)(uintptr_t)res32.contexts;
318 } else
319 #endif
320 DRM_COPYFROM_WITH_RETURN(&res, (void *)data, sizeof (res));
321
322 if (res.count >= DRM_RESERVED_CONTEXTS) {
323 bzero(&ctx, sizeof (ctx));
324 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
325 ctx.handle = i;
326 DRM_COPYTO_WITH_RETURN(&res.contexts[i],
327 &ctx, sizeof (ctx));
328 }
329 }
330 res.count = DRM_RESERVED_CONTEXTS;
331
332 #ifdef _MULTI_DATAMODEL
333 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
334 drm_ctx_res_32_t res32;
335 res32.count = res.count;
336 res32.contexts = (caddr32_t)(uintptr_t)res.contexts;
337
338 DRM_COPYTO_WITH_RETURN((void *)data, &res32,
339 sizeof (drm_ctx_res_32_t));
340 } else
341 #endif
342 DRM_COPYTO_WITH_RETURN((void *)data, &res, sizeof (res));
343
344 return (0);
345 }
346
347 /*ARGSUSED*/
348 int
drm_addctx(DRM_IOCTL_ARGS)349 drm_addctx(DRM_IOCTL_ARGS)
350 {
351 DRM_DEVICE;
352 drm_ctx_t ctx;
353
354 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
355
356 ctx.handle = drm_ctxbitmap_next(dev);
357 if (ctx.handle == DRM_KERNEL_CONTEXT) {
358 /* Skip kernel's context and get a new one. */
359 ctx.handle = drm_ctxbitmap_next(dev);
360 }
361 if (ctx.handle == (drm_context_t)-1) {
362 return (ENOMEM);
363 }
364
365 if (dev->driver->context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) {
366 dev->driver->context_ctor(dev, ctx.handle);
367 }
368
369 DRM_COPYTO_WITH_RETURN((void *)data, &ctx, sizeof (ctx));
370
371 return (0);
372 }
373
374 /*ARGSUSED*/
375 int
drm_modctx(DRM_IOCTL_ARGS)376 drm_modctx(DRM_IOCTL_ARGS)
377 {
378 /* This does nothing */
379 return (0);
380 }
381
382 /*ARGSUSED*/
383 int
drm_getctx(DRM_IOCTL_ARGS)384 drm_getctx(DRM_IOCTL_ARGS)
385 {
386 drm_ctx_t ctx;
387
388 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
389
390 /* This is 0, because we don't handle any context flags */
391 ctx.flags = 0;
392
393 DRM_COPYTO_WITH_RETURN((void *)data, &ctx, sizeof (ctx));
394
395 return (0);
396 }
397
398 /*ARGSUSED*/
399 int
drm_switchctx(DRM_IOCTL_ARGS)400 drm_switchctx(DRM_IOCTL_ARGS)
401 {
402 DRM_DEVICE;
403 drm_ctx_t ctx;
404
405 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
406
407 DRM_DEBUG("drm_switchctx: %d", ctx.handle);
408 return (drm_context_switch(dev, dev->last_context, ctx.handle));
409 }
410
411 /*ARGSUSED*/
412 int
drm_newctx(DRM_IOCTL_ARGS)413 drm_newctx(DRM_IOCTL_ARGS)
414 {
415 DRM_DEVICE;
416 drm_ctx_t ctx;
417
418 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
419
420 DRM_DEBUG("drm_newctx: %d", ctx.handle);
421 (void) drm_context_switch_complete(dev, ctx.handle);
422
423 return (0);
424 }
425
426 /*ARGSUSED*/
427 int
drm_rmctx(DRM_IOCTL_ARGS)428 drm_rmctx(DRM_IOCTL_ARGS)
429 {
430 DRM_DEVICE;
431 drm_ctx_t ctx;
432
433 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
434
435 DRM_DEBUG("drm_rmctx : %d", ctx.handle);
436 if (ctx.handle != DRM_KERNEL_CONTEXT) {
437 if (dev->driver->context_dtor) {
438 DRM_LOCK();
439 dev->driver->context_dtor(dev, ctx.handle);
440 DRM_UNLOCK();
441 }
442
443 drm_ctxbitmap_free(dev, ctx.handle);
444 }
445
446 return (0);
447 }
448