Home | History | Annotate | Line # | Download | only in bsd-core
      1 /*-
      2  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
      3  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the "Software"),
      8  * to deal in the Software without restriction, including without limitation
      9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     10  * and/or sell copies of the Software, and to permit persons to whom the
     11  * Software is furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     21  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     22  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     23  * OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  * Authors:
     26  *    Rickard E. (Rik) Faith <faith (at) valinux.com>
     27  *    Gareth Hughes <gareth (at) valinux.com>
     28  *
     29  */
     30 
     31 /** @file drm_context.c
     32  * Implementation of the context management ioctls.
     33  */
     34 
     35 #include "drmP.h"
     36 
     37 /* ================================================================
     38  * Context bitmap support
     39  */
     40 
     41 void drm_ctxbitmap_free(struct drm_device *dev, int ctx_handle)
     42 {
     43 	if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP ||
     44 	    dev->ctx_bitmap == NULL) {
     45 		DRM_ERROR("Attempt to free invalid context handle: %d\n",
     46 		   ctx_handle);
     47 		return;
     48 	}
     49 
     50 	DRM_LOCK();
     51 	clear_bit(ctx_handle, dev->ctx_bitmap);
     52 	dev->context_sareas[ctx_handle] = NULL;
     53 	DRM_UNLOCK();
     54 	return;
     55 }
     56 
     57 int drm_ctxbitmap_next(struct drm_device *dev)
     58 {
     59 	int bit;
     60 
     61 	if (dev->ctx_bitmap == NULL)
     62 		return -1;
     63 
     64 	DRM_LOCK();
     65 	bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
     66 	if (bit >= DRM_MAX_CTXBITMAP) {
     67 		DRM_UNLOCK();
     68 		return -1;
     69 	}
     70 
     71 	set_bit(bit, dev->ctx_bitmap);
     72 	DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit);
     73 	if ((bit+1) > dev->max_context) {
     74 		dev->max_context = (bit+1);
     75 		if (dev->context_sareas != NULL) {
     76 			drm_local_map_t **ctx_sareas;
     77 
     78 			ctx_sareas = realloc(dev->context_sareas,
     79 			    dev->max_context * sizeof(*dev->context_sareas),
     80 			    DRM_MEM_SAREA, M_NOWAIT);
     81 			if (ctx_sareas == NULL) {
     82 				clear_bit(bit, dev->ctx_bitmap);
     83 				DRM_UNLOCK();
     84 				return -1;
     85 			}
     86 			dev->context_sareas = ctx_sareas;
     87 			dev->context_sareas[bit] = NULL;
     88 		} else {
     89 			/* max_context == 1 at this point */
     90 			dev->context_sareas = malloc(dev->max_context *
     91 			    sizeof(*dev->context_sareas), DRM_MEM_SAREA,
     92 			    M_NOWAIT);
     93 			if (dev->context_sareas == NULL) {
     94 				clear_bit(bit, dev->ctx_bitmap);
     95 				DRM_UNLOCK();
     96 				return -1;
     97 			}
     98 			dev->context_sareas[bit] = NULL;
     99 		}
    100 	}
    101 	DRM_UNLOCK();
    102 	return bit;
    103 }
    104 
    105 int drm_ctxbitmap_init(struct drm_device *dev)
    106 {
    107 	int i;
    108    	int temp;
    109 
    110 	DRM_LOCK();
    111 	dev->ctx_bitmap = malloc(PAGE_SIZE, DRM_MEM_CTXBITMAP,
    112 	    M_NOWAIT | M_ZERO);
    113 	if (dev->ctx_bitmap == NULL) {
    114 		DRM_UNLOCK();
    115 		return ENOMEM;
    116 	}
    117 	dev->context_sareas = NULL;
    118 	dev->max_context = -1;
    119 	DRM_UNLOCK();
    120 
    121 	for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
    122 		temp = drm_ctxbitmap_next(dev);
    123 		DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp);
    124 	}
    125 
    126 	return 0;
    127 }
    128 
    129 void drm_ctxbitmap_cleanup(struct drm_device *dev)
    130 {
    131 	DRM_LOCK();
    132 	if (dev->context_sareas != NULL)
    133 		free(dev->context_sareas, DRM_MEM_SAREA);
    134 	free(dev->ctx_bitmap, DRM_MEM_CTXBITMAP);
    135 	DRM_UNLOCK();
    136 }
    137 
    138 /* ================================================================
    139  * Per Context SAREA Support
    140  */
    141 
    142 int drm_getsareactx(struct drm_device *dev, void *data,
    143 		    struct drm_file *file_priv)
    144 {
    145 	struct drm_ctx_priv_map *request = data;
    146 	drm_local_map_t *map;
    147 
    148 	DRM_LOCK();
    149 	if (dev->max_context < 0 ||
    150 	    request->ctx_id >= (unsigned) dev->max_context) {
    151 		DRM_UNLOCK();
    152 		return EINVAL;
    153 	}
    154 
    155 	map = dev->context_sareas[request->ctx_id];
    156 	DRM_UNLOCK();
    157 
    158 	request->handle = map->handle;
    159 
    160 	return 0;
    161 }
    162 
    163 int drm_setsareactx(struct drm_device *dev, void *data,
    164 		    struct drm_file *file_priv)
    165 {
    166 	struct drm_ctx_priv_map *request = data;
    167 	drm_local_map_t *map = NULL;
    168 
    169 	DRM_LOCK();
    170 	TAILQ_FOREACH(map, &dev->maplist, link) {
    171 		if (map->handle == request->handle) {
    172 			if (dev->max_context < 0)
    173 				goto bad;
    174 			if (request->ctx_id >= (unsigned) dev->max_context)
    175 				goto bad;
    176 			dev->context_sareas[request->ctx_id] = map;
    177 			DRM_UNLOCK();
    178 			return 0;
    179 		}
    180 	}
    181 
    182 bad:
    183 	DRM_UNLOCK();
    184 	return EINVAL;
    185 }
    186 
    187 /* ================================================================
    188  * The actual DRM context handling routines
    189  */
    190 
    191 int drm_context_switch(struct drm_device *dev, int old, int new)
    192 {
    193 	if (test_and_set_bit(0, &dev->context_flag)) {
    194 		DRM_ERROR("Reentering -- FIXME\n");
    195 		return EBUSY;
    196 	}
    197 
    198 	DRM_DEBUG("Context switch from %d to %d\n", old, new);
    199 
    200 	if (new == dev->last_context) {
    201 		clear_bit(0, &dev->context_flag);
    202 		return 0;
    203 	}
    204 
    205 	return 0;
    206 }
    207 
    208 int drm_context_switch_complete(struct drm_device *dev, int new)
    209 {
    210 	dev->last_context = new;  /* PRE/POST: This is the _only_ writer. */
    211 
    212 	if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
    213 		DRM_ERROR("Lock isn't held after context switch\n");
    214 	}
    215 
    216 	/* If a context switch is ever initiated
    217 	   when the kernel holds the lock, release
    218 	   that lock here. */
    219 	clear_bit(0, &dev->context_flag);
    220 
    221 	return 0;
    222 }
    223 
    224 int drm_resctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
    225 {
    226 	struct drm_ctx_res *res = data;
    227 	struct drm_ctx ctx;
    228 	int i;
    229 
    230 	if (res->count >= DRM_RESERVED_CONTEXTS) {
    231 		bzero(&ctx, sizeof(ctx));
    232 		for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
    233 			ctx.handle = i;
    234 			if (DRM_COPY_TO_USER(&res->contexts[i],
    235 			    &ctx, sizeof(ctx)))
    236 				return EFAULT;
    237 		}
    238 	}
    239 	res->count = DRM_RESERVED_CONTEXTS;
    240 
    241 	return 0;
    242 }
    243 
    244 int drm_addctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
    245 {
    246 	struct drm_ctx *ctx = data;
    247 
    248 	ctx->handle = drm_ctxbitmap_next(dev);
    249 	if (ctx->handle == DRM_KERNEL_CONTEXT) {
    250 		/* Skip kernel's context and get a new one. */
    251 		ctx->handle = drm_ctxbitmap_next(dev);
    252 	}
    253 	DRM_DEBUG("%d\n", ctx->handle);
    254 	if (ctx->handle == -1) {
    255 		DRM_DEBUG("Not enough free contexts.\n");
    256 		/* Should this return -EBUSY instead? */
    257 		return ENOMEM;
    258 	}
    259 
    260 	if (dev->driver->context_ctor && ctx->handle != DRM_KERNEL_CONTEXT) {
    261 		DRM_LOCK();
    262 		dev->driver->context_ctor(dev, ctx->handle);
    263 		DRM_UNLOCK();
    264 	}
    265 
    266 	return 0;
    267 }
    268 
    269 int drm_modctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
    270 {
    271 	/* This does nothing */
    272 	return 0;
    273 }
    274 
    275 int drm_getctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
    276 {
    277 	struct drm_ctx *ctx = data;
    278 
    279 	/* This is 0, because we don't handle any context flags */
    280 	ctx->flags = 0;
    281 
    282 	return 0;
    283 }
    284 
    285 int drm_switchctx(struct drm_device *dev, void *data,
    286 		  struct drm_file *file_priv)
    287 {
    288 	struct drm_ctx *ctx = data;
    289 
    290 	DRM_DEBUG("%d\n", ctx->handle);
    291 	return drm_context_switch(dev, dev->last_context, ctx->handle);
    292 }
    293 
    294 int drm_newctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
    295 {
    296 	struct drm_ctx *ctx = data;
    297 
    298 	DRM_DEBUG("%d\n", ctx->handle);
    299 	drm_context_switch_complete(dev, ctx->handle);
    300 
    301 	return 0;
    302 }
    303 
    304 int drm_rmctx(struct drm_device *dev, void *data, struct drm_file *file_priv)
    305 {
    306 	struct drm_ctx *ctx = data;
    307 
    308 	DRM_DEBUG("%d\n", ctx->handle);
    309 	if (ctx->handle != DRM_KERNEL_CONTEXT) {
    310 		if (dev->driver->context_dtor) {
    311 			DRM_LOCK();
    312 			dev->driver->context_dtor(dev, ctx->handle);
    313 			DRM_UNLOCK();
    314 		}
    315 
    316 		drm_ctxbitmap_free(dev, ctx->handle);
    317 	}
    318 
    319 	return 0;
    320 }
    321