12820Skz151634 /*
2*5804Scg149915 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
32820Skz151634 * Use is subject to license terms.
42820Skz151634 */
52820Skz151634
62820Skz151634 /*
72820Skz151634 * drm_context.h -- IOCTLs for generic contexts -*- linux-c -*-
82820Skz151634 * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com
92820Skz151634 */
102820Skz151634 /*
112820Skz151634 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
122820Skz151634 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
132820Skz151634 * All Rights Reserved.
142820Skz151634 *
152820Skz151634 * Permission is hereby granted, free of charge, to any person obtaining a
162820Skz151634 * copy of this software and associated documentation files (the "Software"),
172820Skz151634 * to deal in the Software without restriction, including without limitation
182820Skz151634 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
192820Skz151634 * and/or sell copies of the Software, and to permit persons to whom the
202820Skz151634 * Software is furnished to do so, subject to the following conditions:
212820Skz151634 *
222820Skz151634 * The above copyright notice and this permission notice (including the next
232820Skz151634 * paragraph) shall be included in all copies or substantial portions of the
242820Skz151634 * Software.
252820Skz151634 *
262820Skz151634 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
272820Skz151634 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
282820Skz151634 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
292820Skz151634 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
302820Skz151634 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
312820Skz151634 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
322820Skz151634 * OTHER DEALINGS IN THE SOFTWARE.
332820Skz151634 *
342820Skz151634 * Authors:
352820Skz151634 * Rickard E. (Rik) Faith <faith@valinux.com>
362820Skz151634 * Gareth Hughes <gareth@valinux.com>
372820Skz151634 *
382820Skz151634 */
392820Skz151634
402820Skz151634 #pragma ident "%Z%%M% %I% %E% SMI"
412820Skz151634
422820Skz151634 #include "drmP.h"
43*5804Scg149915 #include "drm_io32.h"
442820Skz151634
455376Scg149915 static inline int
find_first_zero_bit(volatile void * p,int max)465376Scg149915 find_first_zero_bit(volatile void *p, int max)
475376Scg149915 {
485376Scg149915 int b;
495376Scg149915 volatile int *ptr = (volatile int *)p;
505376Scg149915
515376Scg149915 for (b = 0; b < max; b += 32) {
525376Scg149915 if (ptr[b >> 5] != ~0) {
535376Scg149915 for (;;) {
545376Scg149915 if ((ptr[b >> 5] & (1 << (b & 0x1f))) == 0)
555376Scg149915 return (b);
565376Scg149915 b++;
575376Scg149915 }
585376Scg149915 }
595376Scg149915 }
605376Scg149915 return (max);
615376Scg149915 }
625376Scg149915
632820Skz151634 /*
642820Skz151634 * Context bitmap support
652820Skz151634 */
662820Skz151634 void
drm_ctxbitmap_free(drm_device_t * dev,int ctx_handle)672820Skz151634 drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle)
682820Skz151634 {
692820Skz151634 if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
702820Skz151634 dev->ctx_bitmap == NULL) {
712820Skz151634 DRM_ERROR("drm_ctxbitmap_free: Attempt to free\
722820Skz151634 invalid context handle: %d\n",
732820Skz151634 ctx_handle);
742820Skz151634 return;
752820Skz151634 }
762820Skz151634
772820Skz151634 DRM_LOCK();
782820Skz151634 clear_bit(ctx_handle, dev->ctx_bitmap);
792820Skz151634 dev->context_sareas[ctx_handle] = NULL;
802820Skz151634 DRM_UNLOCK();
812820Skz151634 }
822820Skz151634
832820Skz151634 /* Is supposed to return -1 if any error by calling functions */
842820Skz151634 int
drm_ctxbitmap_next(drm_device_t * dev)852820Skz151634 drm_ctxbitmap_next(drm_device_t *dev)
862820Skz151634 {
872820Skz151634 int bit;
882820Skz151634
892820Skz151634 if (dev->ctx_bitmap == NULL)
902820Skz151634 return (-1);
912820Skz151634
922820Skz151634 DRM_LOCK();
932820Skz151634 bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
942820Skz151634 if (bit >= DRM_MAX_CTXBITMAP) {
952820Skz151634 DRM_UNLOCK();
962820Skz151634 return (-1);
972820Skz151634 }
982820Skz151634
992820Skz151634 set_bit(bit, dev->ctx_bitmap);
1002820Skz151634 DRM_DEBUG("drm_ctxbitmap_next: bit : %d", bit);
1012820Skz151634 if ((bit+1) > dev->max_context) {
1022820Skz151634 dev->max_context = (bit+1);
1032820Skz151634 if (dev->context_sareas != NULL) {
1042820Skz151634 drm_local_map_t **ctx_sareas;
1052820Skz151634 ctx_sareas = drm_realloc(dev->context_sareas,
1065376Scg149915 (dev->max_context - 1) *
1075376Scg149915 sizeof (*dev->context_sareas),
1085376Scg149915 dev->max_context *
1095376Scg149915 sizeof (*dev->context_sareas),
1105376Scg149915 DRM_MEM_MAPS);
1112820Skz151634 if (ctx_sareas == NULL) {
1122820Skz151634 clear_bit(bit, dev->ctx_bitmap);
1132820Skz151634 DRM_UNLOCK();
1142820Skz151634 return (-1);
1152820Skz151634 }
1162820Skz151634 dev->context_sareas = ctx_sareas;
1172820Skz151634 dev->context_sareas[bit] = NULL;
1182820Skz151634 } else {
1192820Skz151634 /* max_context == 1 at this point */
1202820Skz151634 dev->context_sareas = drm_alloc(dev->max_context *
1215376Scg149915 sizeof (*dev->context_sareas), KM_NOSLEEP);
1222820Skz151634 if (dev->context_sareas == NULL) {
1232820Skz151634 clear_bit(bit, dev->ctx_bitmap);
1242820Skz151634 DRM_UNLOCK();
1252820Skz151634 return (-1);
1262820Skz151634 }
1272820Skz151634 dev->context_sareas[bit] = NULL;
1282820Skz151634 }
1292820Skz151634 }
1302820Skz151634 DRM_UNLOCK();
1312820Skz151634 DRM_DEBUG("drm_ctxbitmap_next: return %d", bit);
1322820Skz151634 return (bit);
1332820Skz151634 }
1342820Skz151634
1352820Skz151634 int
drm_ctxbitmap_init(drm_device_t * dev)1362820Skz151634 drm_ctxbitmap_init(drm_device_t *dev)
1372820Skz151634 {
1382820Skz151634 int i;
1392820Skz151634 int temp;
1402820Skz151634
1412820Skz151634 DRM_LOCK();
1422820Skz151634 dev->ctx_bitmap = drm_calloc(1, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
1432820Skz151634 if (dev->ctx_bitmap == NULL) {
1442820Skz151634 DRM_UNLOCK();
145*5804Scg149915 return (ENOMEM);
1462820Skz151634 }
1472820Skz151634 dev->context_sareas = NULL;
1482820Skz151634 dev->max_context = -1;
1492820Skz151634 DRM_UNLOCK();
1502820Skz151634
1512820Skz151634 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
1522820Skz151634 temp = drm_ctxbitmap_next(dev);
1532820Skz151634 DRM_DEBUG("drm_ctxbitmap_init : %d", temp);
1542820Skz151634 }
1552820Skz151634 return (0);
1562820Skz151634 }
1572820Skz151634
1582820Skz151634 void
drm_ctxbitmap_cleanup(drm_device_t * dev)1592820Skz151634 drm_ctxbitmap_cleanup(drm_device_t *dev)
1602820Skz151634 {
1612820Skz151634 DRM_LOCK();
1622820Skz151634 if (dev->context_sareas != NULL)
1632820Skz151634 drm_free(dev->context_sareas,
1645376Scg149915 sizeof (*dev->context_sareas) *
1655376Scg149915 dev->max_context,
1665376Scg149915 DRM_MEM_MAPS);
1672820Skz151634 drm_free(dev->ctx_bitmap, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP);
1682820Skz151634 DRM_UNLOCK();
1692820Skz151634 }
1702820Skz151634
1712820Skz151634 /*
1722820Skz151634 * Per Context SAREA Support
1732820Skz151634 */
1742820Skz151634 /*ARGSUSED*/
1752820Skz151634 int
drm_getsareactx(DRM_IOCTL_ARGS)1762820Skz151634 drm_getsareactx(DRM_IOCTL_ARGS)
1772820Skz151634 {
1782820Skz151634 DRM_DEVICE;
1792820Skz151634 drm_ctx_priv_map_t request;
1802820Skz151634 drm_local_map_t *map;
1812820Skz151634
182*5804Scg149915 #ifdef _MULTI_DATAMODEL
1832820Skz151634 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
184*5804Scg149915 drm_ctx_priv_map_32_t request32;
185*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
186*5804Scg149915 sizeof (drm_ctx_priv_map_32_t));
1872820Skz151634 request.ctx_id = request32.ctx_id;
1882820Skz151634 request.handle = (void *)(uintptr_t)request32.handle;
1892820Skz151634 } else
190*5804Scg149915 #endif
191*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&request, (void *)data,
1925376Scg149915 sizeof (request));
1932820Skz151634
1942820Skz151634 DRM_LOCK();
1952820Skz151634 if (dev->max_context < 0 || request.ctx_id >= (unsigned)
1962820Skz151634 dev->max_context) {
1972820Skz151634 DRM_UNLOCK();
198*5804Scg149915 return (EINVAL);
1992820Skz151634 }
2002820Skz151634
2012820Skz151634 map = dev->context_sareas[request.ctx_id];
2022820Skz151634 DRM_UNLOCK();
2032820Skz151634
204*5804Scg149915 if (!map)
205*5804Scg149915 return (EINVAL);
206*5804Scg149915
2072820Skz151634 request.handle = map->handle;
2082820Skz151634
209*5804Scg149915 #ifdef _MULTI_DATAMODEL
2102820Skz151634 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
211*5804Scg149915 drm_ctx_priv_map_32_t request32;
2122820Skz151634 request32.ctx_id = request.ctx_id;
2132820Skz151634 request32.handle = (caddr32_t)(uintptr_t)request.handle;
214*5804Scg149915 DRM_COPYTO_WITH_RETURN((void *)data, &request32,
215*5804Scg149915 sizeof (drm_ctx_priv_map_32_t));
2162820Skz151634 } else
217*5804Scg149915 #endif
218*5804Scg149915 DRM_COPYTO_WITH_RETURN((void *)data,
219*5804Scg149915 &request, sizeof (request));
2202820Skz151634
2212820Skz151634 return (0);
2222820Skz151634 }
2232820Skz151634
2242820Skz151634 /*ARGSUSED*/
2252820Skz151634 int
drm_setsareactx(DRM_IOCTL_ARGS)2262820Skz151634 drm_setsareactx(DRM_IOCTL_ARGS)
2272820Skz151634 {
2282820Skz151634 DRM_DEVICE;
2292820Skz151634 drm_ctx_priv_map_t request;
2302820Skz151634 drm_local_map_t *map = NULL;
2312820Skz151634
232*5804Scg149915 #ifdef _MULTI_DATAMODEL
2332820Skz151634 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
234*5804Scg149915 drm_ctx_priv_map_32_t request32;
2352820Skz151634
236*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&request32, (void *)data,
237*5804Scg149915 sizeof (drm_ctx_priv_map_32_t));
2382820Skz151634 request.ctx_id = request32.ctx_id;
2392820Skz151634 request.handle = (void *)(uintptr_t)request32.handle;
2402820Skz151634 } else
241*5804Scg149915 #endif
242*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&request,
243*5804Scg149915 (void *)data, sizeof (request));
2442820Skz151634
2452820Skz151634 DRM_LOCK();
2462820Skz151634 TAILQ_FOREACH(map, &dev->maplist, link) {
2472820Skz151634 if (map->handle == request.handle) {
2482820Skz151634 if (dev->max_context < 0)
2492820Skz151634 goto bad;
2502820Skz151634 if (request.ctx_id >= (unsigned)dev->max_context)
2512820Skz151634 goto bad;
2522820Skz151634 dev->context_sareas[request.ctx_id] = map;
2532820Skz151634 DRM_UNLOCK();
2542820Skz151634 return (0);
2552820Skz151634 }
2562820Skz151634 }
2572820Skz151634
2582820Skz151634 bad:
2592820Skz151634 DRM_UNLOCK();
260*5804Scg149915 return (EINVAL);
2612820Skz151634 }
2622820Skz151634
2632820Skz151634 /*
2642820Skz151634 * The actual DRM context handling routines
2652820Skz151634 */
2662820Skz151634 int
drm_context_switch(drm_device_t * dev,int old,int new)2672820Skz151634 drm_context_switch(drm_device_t *dev, int old, int new)
2682820Skz151634 {
2692820Skz151634 if (test_and_set_bit(0, &dev->context_flag)) {
2702820Skz151634 DRM_ERROR("drm_context_switch: Reentering -- FIXME");
271*5804Scg149915 return (EBUSY);
2722820Skz151634 }
2732820Skz151634
2742820Skz151634 DRM_DEBUG("drm_context_switch: Context switch from %d to %d",
2752820Skz151634 old, new);
2762820Skz151634
2772820Skz151634 if (new == dev->last_context) {
2782820Skz151634 clear_bit(0, &dev->context_flag);
2792820Skz151634 return (0);
2802820Skz151634 }
2812820Skz151634
2822820Skz151634 return (0);
2832820Skz151634 }
2842820Skz151634
2852820Skz151634 int
drm_context_switch_complete(drm_device_t * dev,int new)2862820Skz151634 drm_context_switch_complete(drm_device_t *dev, int new)
2872820Skz151634 {
2882820Skz151634 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
2892820Skz151634
2902820Skz151634 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
2912820Skz151634 DRM_ERROR(
2922820Skz151634 "drm_context_switch_complete: Lock not held");
2932820Skz151634 }
2942820Skz151634 /*
2952820Skz151634 * If a context switch is ever initiated
2962820Skz151634 * when the kernel holds the lock, release
2972820Skz151634 * that lock here.
2982820Skz151634 */
2992820Skz151634 clear_bit(0, &dev->context_flag);
3002820Skz151634
3012820Skz151634 return (0);
3022820Skz151634 }
3032820Skz151634
3042820Skz151634 /*ARGSUSED*/
3052820Skz151634 int
drm_resctx(DRM_IOCTL_ARGS)3062820Skz151634 drm_resctx(DRM_IOCTL_ARGS)
3072820Skz151634 {
3082820Skz151634 drm_ctx_res_t res;
3092820Skz151634 drm_ctx_t ctx;
3102820Skz151634 int i;
3112820Skz151634
312*5804Scg149915 #ifdef _MULTI_DATAMODEL
3132820Skz151634 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
314*5804Scg149915 drm_ctx_res_32_t res32;
315*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&res32, (void *)data, sizeof (res32));
3162820Skz151634 res.count = res32.count;
317*5804Scg149915 res.contexts = (drm_ctx_t *)(uintptr_t)res32.contexts;
3182820Skz151634 } else
319*5804Scg149915 #endif
320*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&res, (void *)data, sizeof (res));
3212820Skz151634
3222820Skz151634 if (res.count >= DRM_RESERVED_CONTEXTS) {
3232820Skz151634 bzero(&ctx, sizeof (ctx));
3242820Skz151634 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
3252820Skz151634 ctx.handle = i;
326*5804Scg149915 DRM_COPYTO_WITH_RETURN(&res.contexts[i],
327*5804Scg149915 &ctx, sizeof (ctx));
3282820Skz151634 }
3292820Skz151634 }
3302820Skz151634 res.count = DRM_RESERVED_CONTEXTS;
3312820Skz151634
332*5804Scg149915 #ifdef _MULTI_DATAMODEL
3332820Skz151634 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
334*5804Scg149915 drm_ctx_res_32_t res32;
3352820Skz151634 res32.count = res.count;
3362820Skz151634 res32.contexts = (caddr32_t)(uintptr_t)res.contexts;
3372820Skz151634
338*5804Scg149915 DRM_COPYTO_WITH_RETURN((void *)data, &res32,
339*5804Scg149915 sizeof (drm_ctx_res_32_t));
3402820Skz151634 } else
341*5804Scg149915 #endif
342*5804Scg149915 DRM_COPYTO_WITH_RETURN((void *)data, &res, sizeof (res));
3432820Skz151634
3442820Skz151634 return (0);
3452820Skz151634 }
3462820Skz151634
3472820Skz151634 /*ARGSUSED*/
3482820Skz151634 int
drm_addctx(DRM_IOCTL_ARGS)3492820Skz151634 drm_addctx(DRM_IOCTL_ARGS)
3502820Skz151634 {
3512820Skz151634 DRM_DEVICE;
3522820Skz151634 drm_ctx_t ctx;
3532820Skz151634
354*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
3552820Skz151634
3562820Skz151634 ctx.handle = drm_ctxbitmap_next(dev);
3572820Skz151634 if (ctx.handle == DRM_KERNEL_CONTEXT) {
3582820Skz151634 /* Skip kernel's context and get a new one. */
3592820Skz151634 ctx.handle = drm_ctxbitmap_next(dev);
3602820Skz151634 }
361*5804Scg149915 if (ctx.handle == (drm_context_t)-1) {
362*5804Scg149915 return (ENOMEM);
3632820Skz151634 }
3642820Skz151634
365*5804Scg149915 if (dev->driver->context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) {
366*5804Scg149915 dev->driver->context_ctor(dev, ctx.handle);
3672820Skz151634 }
3682820Skz151634
369*5804Scg149915 DRM_COPYTO_WITH_RETURN((void *)data, &ctx, sizeof (ctx));
3702820Skz151634
3712820Skz151634 return (0);
3722820Skz151634 }
3732820Skz151634
3742820Skz151634 /*ARGSUSED*/
3752820Skz151634 int
drm_modctx(DRM_IOCTL_ARGS)3762820Skz151634 drm_modctx(DRM_IOCTL_ARGS)
3772820Skz151634 {
3782820Skz151634 /* This does nothing */
3792820Skz151634 return (0);
3802820Skz151634 }
3812820Skz151634
3822820Skz151634 /*ARGSUSED*/
3832820Skz151634 int
drm_getctx(DRM_IOCTL_ARGS)3842820Skz151634 drm_getctx(DRM_IOCTL_ARGS)
3852820Skz151634 {
3862820Skz151634 drm_ctx_t ctx;
3872820Skz151634
388*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
3892820Skz151634
3902820Skz151634 /* This is 0, because we don't handle any context flags */
3912820Skz151634 ctx.flags = 0;
3922820Skz151634
393*5804Scg149915 DRM_COPYTO_WITH_RETURN((void *)data, &ctx, sizeof (ctx));
3942820Skz151634
3952820Skz151634 return (0);
3962820Skz151634 }
3972820Skz151634
3982820Skz151634 /*ARGSUSED*/
3992820Skz151634 int
drm_switchctx(DRM_IOCTL_ARGS)4002820Skz151634 drm_switchctx(DRM_IOCTL_ARGS)
4012820Skz151634 {
4022820Skz151634 DRM_DEVICE;
4032820Skz151634 drm_ctx_t ctx;
4042820Skz151634
405*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
4062820Skz151634
4072820Skz151634 DRM_DEBUG("drm_switchctx: %d", ctx.handle);
4082820Skz151634 return (drm_context_switch(dev, dev->last_context, ctx.handle));
4092820Skz151634 }
4102820Skz151634
4112820Skz151634 /*ARGSUSED*/
4122820Skz151634 int
drm_newctx(DRM_IOCTL_ARGS)4132820Skz151634 drm_newctx(DRM_IOCTL_ARGS)
4142820Skz151634 {
4152820Skz151634 DRM_DEVICE;
4162820Skz151634 drm_ctx_t ctx;
4172820Skz151634
418*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
4192820Skz151634
4202820Skz151634 DRM_DEBUG("drm_newctx: %d", ctx.handle);
4212820Skz151634 (void) drm_context_switch_complete(dev, ctx.handle);
4222820Skz151634
4232820Skz151634 return (0);
4242820Skz151634 }
4252820Skz151634
4262820Skz151634 /*ARGSUSED*/
4272820Skz151634 int
drm_rmctx(DRM_IOCTL_ARGS)4282820Skz151634 drm_rmctx(DRM_IOCTL_ARGS)
4292820Skz151634 {
4302820Skz151634 DRM_DEVICE;
4312820Skz151634 drm_ctx_t ctx;
4322820Skz151634
433*5804Scg149915 DRM_COPYFROM_WITH_RETURN(&ctx, (void *)data, sizeof (ctx));
4342820Skz151634
4352820Skz151634 DRM_DEBUG("drm_rmctx : %d", ctx.handle);
4362820Skz151634 if (ctx.handle != DRM_KERNEL_CONTEXT) {
437*5804Scg149915 if (dev->driver->context_dtor) {
4382820Skz151634 DRM_LOCK();
439*5804Scg149915 dev->driver->context_dtor(dev, ctx.handle);
4402820Skz151634 DRM_UNLOCK();
4412820Skz151634 }
4422820Skz151634
4432820Skz151634 drm_ctxbitmap_free(dev, ctx.handle);
4442820Skz151634 }
4452820Skz151634
4462820Skz151634 return (0);
4472820Skz151634 }
448