blob: 16c141f2557f616f60750db44565169f0862cb9f [file] [log] [blame]
kz15163460405de2006-09-28 01:41:18 -07001/*
cg149915d0538f62008-01-09 19:45:15 -08002 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
kz15163460405de2006-09-28 01:41:18 -07003 * 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"
cg149915d0538f62008-01-09 19:45:15 -080043#include "drm_io32.h"
kz15163460405de2006-09-28 01:41:18 -070044
cg14991566310b52007-10-29 22:02:09 -070045static inline int
46find_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
kz15163460405de2006-09-28 01:41:18 -070063/*
64 * Context bitmap support
65 */
66void
67drm_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 */
84int
85drm_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,
cg14991566310b52007-10-29 22:02:09 -0700106 (dev->max_context - 1) *
107 sizeof (*dev->context_sareas),
108 dev->max_context *
109 sizeof (*dev->context_sareas),
110 DRM_MEM_MAPS);
kz15163460405de2006-09-28 01:41:18 -0700111 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 *
cg14991566310b52007-10-29 22:02:09 -0700121 sizeof (*dev->context_sareas), KM_NOSLEEP);
kz15163460405de2006-09-28 01:41:18 -0700122 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
135int
136drm_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();
cg149915d0538f62008-01-09 19:45:15 -0800145 return (ENOMEM);
kz15163460405de2006-09-28 01:41:18 -0700146 }
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
158void
159drm_ctxbitmap_cleanup(drm_device_t *dev)
160{
161 DRM_LOCK();
162 if (dev->context_sareas != NULL)
163 drm_free(dev->context_sareas,
cg14991566310b52007-10-29 22:02:09 -0700164 sizeof (*dev->context_sareas) *
165 dev->max_context,
166 DRM_MEM_MAPS);
kz15163460405de2006-09-28 01:41:18 -0700167 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*/
175int
176drm_getsareactx(DRM_IOCTL_ARGS)
177{
178 DRM_DEVICE;
179 drm_ctx_priv_map_t request;
180 drm_local_map_t *map;
181
cg149915d0538f62008-01-09 19:45:15 -0800182#ifdef _MULTI_DATAMODEL
kz15163460405de2006-09-28 01:41:18 -0700183 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
cg149915d0538f62008-01-09 19:45:15 -0800184 drm_ctx_priv_map_32_t request32;
185 DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
186 sizeof (drm_ctx_priv_map_32_t));
kz15163460405de2006-09-28 01:41:18 -0700187 request.ctx_id = request32.ctx_id;
188 request.handle = (void *)(uintptr_t)request32.handle;
189 } else
cg149915d0538f62008-01-09 19:45:15 -0800190#endif
191 DRM_COPYFROM_WITH_RETURN(&request, (void *)data,
cg14991566310b52007-10-29 22:02:09 -0700192 sizeof (request));
kz15163460405de2006-09-28 01:41:18 -0700193
194 DRM_LOCK();
195 if (dev->max_context < 0 || request.ctx_id >= (unsigned)
196 dev->max_context) {
197 DRM_UNLOCK();
cg149915d0538f62008-01-09 19:45:15 -0800198 return (EINVAL);
kz15163460405de2006-09-28 01:41:18 -0700199 }
200
201 map = dev->context_sareas[request.ctx_id];
202 DRM_UNLOCK();
203
cg149915d0538f62008-01-09 19:45:15 -0800204 if (!map)
205 return (EINVAL);
206
kz15163460405de2006-09-28 01:41:18 -0700207 request.handle = map->handle;
208
cg149915d0538f62008-01-09 19:45:15 -0800209#ifdef _MULTI_DATAMODEL
kz15163460405de2006-09-28 01:41:18 -0700210 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
cg149915d0538f62008-01-09 19:45:15 -0800211 drm_ctx_priv_map_32_t request32;
kz15163460405de2006-09-28 01:41:18 -0700212 request32.ctx_id = request.ctx_id;
213 request32.handle = (caddr32_t)(uintptr_t)request.handle;
cg149915d0538f62008-01-09 19:45:15 -0800214 DRM_COPYTO_WITH_RETURN((void *)data, &request32,
215 sizeof (drm_ctx_priv_map_32_t));
kz15163460405de2006-09-28 01:41:18 -0700216 } else
cg149915d0538f62008-01-09 19:45:15 -0800217#endif
218 DRM_COPYTO_WITH_RETURN((void *)data,
219 &request, sizeof (request));
kz15163460405de2006-09-28 01:41:18 -0700220
221 return (0);
222}
223
224/*ARGSUSED*/
225int
226drm_setsareactx(DRM_IOCTL_ARGS)
227{
228 DRM_DEVICE;
229 drm_ctx_priv_map_t request;
230 drm_local_map_t *map = NULL;
231
cg149915d0538f62008-01-09 19:45:15 -0800232#ifdef _MULTI_DATAMODEL
kz15163460405de2006-09-28 01:41:18 -0700233 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
cg149915d0538f62008-01-09 19:45:15 -0800234 drm_ctx_priv_map_32_t request32;
kz15163460405de2006-09-28 01:41:18 -0700235
cg149915d0538f62008-01-09 19:45:15 -0800236 DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
237 sizeof (drm_ctx_priv_map_32_t));
kz15163460405de2006-09-28 01:41:18 -0700238 request.ctx_id = request32.ctx_id;
239 request.handle = (void *)(uintptr_t)request32.handle;
240 } else
cg149915d0538f62008-01-09 19:45:15 -0800241#endif
242 DRM_COPYFROM_WITH_RETURN(&request,
243 (void *)data, sizeof (request));
kz15163460405de2006-09-28 01:41:18 -0700244
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
258bad:
259 DRM_UNLOCK();
cg149915d0538f62008-01-09 19:45:15 -0800260 return (EINVAL);
kz15163460405de2006-09-28 01:41:18 -0700261}
262
263/*
264 * The actual DRM context handling routines
265 */
266int
267drm_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");
cg149915d0538f62008-01-09 19:45:15 -0800271 return (EBUSY);
kz15163460405de2006-09-28 01:41:18 -0700272 }
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
285int
286drm_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*/
305int
306drm_resctx(DRM_IOCTL_ARGS)
307{
308 drm_ctx_res_t res;
309 drm_ctx_t ctx;
310 int i;
311
cg149915d0538f62008-01-09 19:45:15 -0800312#ifdef _MULTI_DATAMODEL
kz15163460405de2006-09-28 01:41:18 -0700313 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
cg149915d0538f62008-01-09 19:45:15 -0800314 drm_ctx_res_32_t res32;
315 DRM_COPYFROM_WITH_RETURN(&res32, (void *)data, sizeof (res32));
kz15163460405de2006-09-28 01:41:18 -0700316 res.count = res32.count;
cg149915d0538f62008-01-09 19:45:15 -0800317 res.contexts = (drm_ctx_t *)(uintptr_t)res32.contexts;
kz15163460405de2006-09-28 01:41:18 -0700318 } else
cg149915d0538f62008-01-09 19:45:15 -0800319#endif
320 DRM_COPYFROM_WITH_RETURN(&res, (void *)data, sizeof (res));
kz15163460405de2006-09-28 01:41:18 -0700321
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;
cg149915d0538f62008-01-09 19:45:15 -0800326 DRM_COPYTO_WITH_RETURN(&res.contexts[i],
327 &ctx, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700328 }
329 }
330 res.count = DRM_RESERVED_CONTEXTS;
331
cg149915d0538f62008-01-09 19:45:15 -0800332#ifdef _MULTI_DATAMODEL
kz15163460405de2006-09-28 01:41:18 -0700333 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
cg149915d0538f62008-01-09 19:45:15 -0800334 drm_ctx_res_32_t res32;
kz15163460405de2006-09-28 01:41:18 -0700335 res32.count = res.count;
336 res32.contexts = (caddr32_t)(uintptr_t)res.contexts;
337
cg149915d0538f62008-01-09 19:45:15 -0800338 DRM_COPYTO_WITH_RETURN((void *)data, &res32,
339 sizeof (drm_ctx_res_32_t));
kz15163460405de2006-09-28 01:41:18 -0700340 } else
cg149915d0538f62008-01-09 19:45:15 -0800341#endif
342 DRM_COPYTO_WITH_RETURN((void *)data, &res, sizeof (res));
kz15163460405de2006-09-28 01:41:18 -0700343
344 return (0);
345}
346
347/*ARGSUSED*/
348int
349drm_addctx(DRM_IOCTL_ARGS)
350{
351 DRM_DEVICE;
352 drm_ctx_t ctx;
353
cg149915d0538f62008-01-09 19:45:15 -0800354 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700355
356 ctx.handle = drm_ctxbitmap_next(dev);
kz15163460405de2006-09-28 01:41:18 -0700357 if (ctx.handle == DRM_KERNEL_CONTEXT) {
358 /* Skip kernel's context and get a new one. */
kz15163460405de2006-09-28 01:41:18 -0700359 ctx.handle = drm_ctxbitmap_next(dev);
360 }
cg149915d0538f62008-01-09 19:45:15 -0800361 if (ctx.handle == (drm_context_t)-1) {
362 return (ENOMEM);
kz15163460405de2006-09-28 01:41:18 -0700363 }
364
cg149915d0538f62008-01-09 19:45:15 -0800365 if (dev->driver->context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) {
366 dev->driver->context_ctor(dev, ctx.handle);
kz15163460405de2006-09-28 01:41:18 -0700367 }
368
cg149915d0538f62008-01-09 19:45:15 -0800369 DRM_COPYTO_WITH_RETURN((void *)data, &ctx, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700370
371 return (0);
372}
373
374/*ARGSUSED*/
375int
376drm_modctx(DRM_IOCTL_ARGS)
377{
378 /* This does nothing */
379 return (0);
380}
381
382/*ARGSUSED*/
383int
384drm_getctx(DRM_IOCTL_ARGS)
385{
386 drm_ctx_t ctx;
387
cg149915d0538f62008-01-09 19:45:15 -0800388 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700389
390 /* This is 0, because we don't handle any context flags */
391 ctx.flags = 0;
392
cg149915d0538f62008-01-09 19:45:15 -0800393 DRM_COPYTO_WITH_RETURN((void *)data, &ctx, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700394
395 return (0);
396}
397
398/*ARGSUSED*/
399int
400drm_switchctx(DRM_IOCTL_ARGS)
401{
402 DRM_DEVICE;
403 drm_ctx_t ctx;
404
cg149915d0538f62008-01-09 19:45:15 -0800405 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700406
407 DRM_DEBUG("drm_switchctx: %d", ctx.handle);
408 return (drm_context_switch(dev, dev->last_context, ctx.handle));
409}
410
411/*ARGSUSED*/
412int
413drm_newctx(DRM_IOCTL_ARGS)
414{
415 DRM_DEVICE;
416 drm_ctx_t ctx;
417
cg149915d0538f62008-01-09 19:45:15 -0800418 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700419
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*/
427int
428drm_rmctx(DRM_IOCTL_ARGS)
429{
430 DRM_DEVICE;
431 drm_ctx_t ctx;
432
cg149915d0538f62008-01-09 19:45:15 -0800433 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
kz15163460405de2006-09-28 01:41:18 -0700434
435 DRM_DEBUG("drm_rmctx : %d", ctx.handle);
436 if (ctx.handle != DRM_KERNEL_CONTEXT) {
cg149915d0538f62008-01-09 19:45:15 -0800437 if (dev->driver->context_dtor) {
kz15163460405de2006-09-28 01:41:18 -0700438 DRM_LOCK();
cg149915d0538f62008-01-09 19:45:15 -0800439 dev->driver->context_dtor(dev, ctx.handle);
kz15163460405de2006-09-28 01:41:18 -0700440 DRM_UNLOCK();
441 }
442
443 drm_ctxbitmap_free(dev, ctx.handle);
444 }
445
446 return (0);
447}