1 /* 2 * Copyright 2006 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 44 /* 45 * Context bitmap support 46 */ 47 void 48 drm_ctxbitmap_free(drm_device_t *dev, int ctx_handle) 49 { 50 if (ctx_handle < 0 || ctx_handle >= DRM_MAX_CTXBITMAP || 51 dev->ctx_bitmap == NULL) { 52 DRM_ERROR("drm_ctxbitmap_free: Attempt to free\ 53 invalid context handle: %d\n", 54 ctx_handle); 55 return; 56 } 57 58 DRM_LOCK(); 59 clear_bit(ctx_handle, dev->ctx_bitmap); 60 dev->context_sareas[ctx_handle] = NULL; 61 DRM_UNLOCK(); 62 } 63 64 /* Is supposed to return -1 if any error by calling functions */ 65 int 66 drm_ctxbitmap_next(drm_device_t *dev) 67 { 68 int bit; 69 70 if (dev->ctx_bitmap == NULL) 71 return (-1); 72 73 DRM_LOCK(); 74 bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); 75 if (bit >= DRM_MAX_CTXBITMAP) { 76 DRM_UNLOCK(); 77 return (-1); 78 } 79 80 set_bit(bit, dev->ctx_bitmap); 81 DRM_DEBUG("drm_ctxbitmap_next: bit : %d", bit); 82 if ((bit+1) > dev->max_context) { 83 dev->max_context = (bit+1); 84 if (dev->context_sareas != NULL) { 85 drm_local_map_t **ctx_sareas; 86 ctx_sareas = drm_realloc(dev->context_sareas, 87 (dev->max_context - 1) * 88 sizeof (*dev->context_sareas), 89 dev->max_context * 90 sizeof (*dev->context_sareas), 91 DRM_MEM_MAPS); 92 if (ctx_sareas == NULL) { 93 clear_bit(bit, dev->ctx_bitmap); 94 DRM_UNLOCK(); 95 return (-1); 96 } 97 dev->context_sareas = ctx_sareas; 98 dev->context_sareas[bit] = NULL; 99 } else { 100 /* max_context == 1 at this point */ 101 dev->context_sareas = drm_alloc(dev->max_context * 102 sizeof (*dev->context_sareas), KM_NOSLEEP); 103 if (dev->context_sareas == NULL) { 104 clear_bit(bit, dev->ctx_bitmap); 105 DRM_UNLOCK(); 106 return (-1); 107 } 108 dev->context_sareas[bit] = NULL; 109 } 110 } 111 DRM_UNLOCK(); 112 DRM_DEBUG("drm_ctxbitmap_next: return %d", bit); 113 return (bit); 114 } 115 116 int 117 drm_ctxbitmap_init(drm_device_t *dev) 118 { 119 int i; 120 int temp; 121 122 DRM_LOCK(); 123 dev->ctx_bitmap = drm_calloc(1, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP); 124 if (dev->ctx_bitmap == NULL) { 125 DRM_UNLOCK(); 126 return (DRM_ERR(ENOMEM)); 127 } 128 dev->context_sareas = NULL; 129 dev->max_context = -1; 130 DRM_UNLOCK(); 131 132 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 133 temp = drm_ctxbitmap_next(dev); 134 DRM_DEBUG("drm_ctxbitmap_init : %d", temp); 135 } 136 return (0); 137 } 138 139 void 140 drm_ctxbitmap_cleanup(drm_device_t *dev) 141 { 142 DRM_LOCK(); 143 if (dev->context_sareas != NULL) 144 drm_free(dev->context_sareas, 145 sizeof (*dev->context_sareas) * 146 dev->max_context, 147 DRM_MEM_MAPS); 148 drm_free(dev->ctx_bitmap, DRM_PAGE_SIZE, DRM_MEM_CTXBITMAP); 149 DRM_UNLOCK(); 150 } 151 152 /* 153 * Per Context SAREA Support 154 */ 155 /*ARGSUSED*/ 156 int 157 drm_getsareactx(DRM_IOCTL_ARGS) 158 { 159 DRM_DEVICE; 160 drm_ctx_priv_map_t request; 161 drm_local_map_t *map; 162 163 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 164 drm_ctx_priv_map32_t request32; 165 DRM_COPY_FROM_USER_IOCTL(request32, 166 (drm_ctx_priv_map32_t *)data, 167 sizeof (drm_ctx_priv_map32_t)); 168 request.ctx_id = request32.ctx_id; 169 request.handle = (void *)(uintptr_t)request32.handle; 170 } else 171 DRM_COPY_FROM_USER_IOCTL(request, (drm_ctx_priv_map_t *)data, 172 sizeof (request)); 173 174 DRM_LOCK(); 175 if (dev->max_context < 0 || request.ctx_id >= (unsigned) 176 dev->max_context) { 177 DRM_UNLOCK(); 178 return (DRM_ERR(EINVAL)); 179 } 180 181 map = dev->context_sareas[request.ctx_id]; 182 DRM_UNLOCK(); 183 184 request.handle = map->handle; 185 186 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 187 drm_ctx_priv_map32_t request32; 188 request32.ctx_id = request.ctx_id; 189 request32.handle = (caddr32_t)(uintptr_t)request.handle; 190 DRM_COPY_TO_USER_IOCTL((drm_ctx_priv_map32_t *)data, 191 request32, 192 sizeof (drm_ctx_priv_map32_t)); 193 } else 194 DRM_COPY_TO_USER_IOCTL((drm_ctx_priv_map_t *)data, request, 195 sizeof (request)); 196 197 return (0); 198 } 199 200 /*ARGSUSED*/ 201 int 202 drm_setsareactx(DRM_IOCTL_ARGS) 203 { 204 DRM_DEVICE; 205 drm_ctx_priv_map_t request; 206 drm_local_map_t *map = NULL; 207 208 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 209 drm_ctx_priv_map32_t request32; 210 211 DRM_COPY_FROM_USER_IOCTL(request32, 212 (drm_ctx_priv_map32_t *)data, 213 sizeof (drm_ctx_priv_map32_t)); 214 request.ctx_id = request32.ctx_id; 215 request.handle = (void *)(uintptr_t)request32.handle; 216 } else 217 DRM_COPY_FROM_USER_IOCTL(request, (drm_ctx_priv_map_t *)data, 218 sizeof (request)); 219 220 DRM_LOCK(); 221 TAILQ_FOREACH(map, &dev->maplist, link) { 222 if (map->handle == request.handle) { 223 if (dev->max_context < 0) 224 goto bad; 225 if (request.ctx_id >= (unsigned)dev->max_context) 226 goto bad; 227 dev->context_sareas[request.ctx_id] = map; 228 DRM_UNLOCK(); 229 return (0); 230 } 231 } 232 233 bad: 234 DRM_UNLOCK(); 235 return (DRM_ERR(EINVAL)); 236 } 237 238 /* 239 * The actual DRM context handling routines 240 */ 241 int 242 drm_context_switch(drm_device_t *dev, int old, int new) 243 { 244 if (test_and_set_bit(0, &dev->context_flag)) { 245 DRM_ERROR("drm_context_switch: Reentering -- FIXME"); 246 return (DRM_ERR(EBUSY)); 247 } 248 249 DRM_DEBUG("drm_context_switch: Context switch from %d to %d", 250 old, new); 251 252 if (new == dev->last_context) { 253 clear_bit(0, &dev->context_flag); 254 return (0); 255 } 256 257 return (0); 258 } 259 260 int 261 drm_context_switch_complete(drm_device_t *dev, int new) 262 { 263 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ 264 265 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { 266 DRM_ERROR( 267 "drm_context_switch_complete: Lock not held"); 268 } 269 /* 270 * If a context switch is ever initiated 271 * when the kernel holds the lock, release 272 * that lock here. 273 */ 274 clear_bit(0, &dev->context_flag); 275 276 return (0); 277 } 278 279 /*ARGSUSED*/ 280 int 281 drm_resctx(DRM_IOCTL_ARGS) 282 { 283 drm_ctx_res_t res; 284 drm_ctx_t ctx; 285 int i; 286 287 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 288 drm_ctx_res32_t res32; 289 DRM_COPY_FROM_USER_IOCTL(res32, 290 (drm_ctx_res32_t *)data, 291 sizeof (drm_ctx_res32_t)); 292 res.count = res32.count; 293 res.contexts = (drm_ctx_t __user *)(uintptr_t)res32.contexts; 294 } else 295 DRM_COPY_FROM_USER_IOCTL(res, 296 (drm_ctx_res_t *)data, 297 sizeof (res)); 298 299 if (res.count >= DRM_RESERVED_CONTEXTS) { 300 bzero(&ctx, sizeof (ctx)); 301 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 302 ctx.handle = i; 303 if (DRM_COPY_TO_USER(&res.contexts[i], 304 &ctx, sizeof (ctx))) 305 return (DRM_ERR(EFAULT)); 306 } 307 } 308 res.count = DRM_RESERVED_CONTEXTS; 309 310 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 311 drm_ctx_res32_t res32; 312 res32.count = res.count; 313 res32.contexts = (caddr32_t)(uintptr_t)res.contexts; 314 315 DRM_COPY_TO_USER_IOCTL((drm_ctx_res32_t *)data, 316 res32, sizeof (drm_ctx_res32_t)); 317 } else 318 DRM_COPY_TO_USER_IOCTL((drm_ctx_res_t *)data, 319 res, sizeof (res)); 320 321 return (0); 322 } 323 324 /*ARGSUSED*/ 325 int 326 drm_addctx(DRM_IOCTL_ARGS) 327 { 328 DRM_DEVICE; 329 drm_ctx_t ctx; 330 331 DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx)); 332 333 ctx.handle = drm_ctxbitmap_next(dev); 334 DRM_DEBUG("drm_addctx: ctx.handle 1:%d\n", (int)ctx.handle); 335 if (ctx.handle == DRM_KERNEL_CONTEXT) { 336 /* Skip kernel's context and get a new one. */ 337 DRM_DEBUG("drm_addctx: ctx.handle 2:%d\n", (int)ctx.handle); 338 ctx.handle = drm_ctxbitmap_next(dev); 339 } 340 DRM_DEBUG("drm_addctx :%d\n", ctx.handle); 341 if (ctx.handle == -1) { 342 DRM_DEBUG("drm_addctx: Not enough free contexts."); 343 return (DRM_ERR(ENOMEM)); 344 } 345 346 if (dev->context_ctor && ctx.handle != DRM_KERNEL_CONTEXT) { 347 DRM_LOCK(); 348 dev->context_ctor(dev, ctx.handle); 349 DRM_UNLOCK(); 350 } 351 352 DRM_COPY_TO_USER_IOCTL((drm_ctx_t *)data, ctx, sizeof (ctx)); 353 354 return (0); 355 } 356 357 /*ARGSUSED*/ 358 int 359 drm_modctx(DRM_IOCTL_ARGS) 360 { 361 /* This does nothing */ 362 return (0); 363 } 364 365 /*ARGSUSED*/ 366 int 367 drm_getctx(DRM_IOCTL_ARGS) 368 { 369 drm_ctx_t ctx; 370 371 DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx)); 372 373 /* This is 0, because we don't handle any context flags */ 374 ctx.flags = 0; 375 376 DRM_COPY_TO_USER_IOCTL((drm_ctx_t *)data, ctx, sizeof (ctx)); 377 378 return (0); 379 } 380 381 /*ARGSUSED*/ 382 int 383 drm_switchctx(DRM_IOCTL_ARGS) 384 { 385 DRM_DEVICE; 386 drm_ctx_t ctx; 387 388 DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx)); 389 390 DRM_DEBUG("drm_switchctx: %d", ctx.handle); 391 return (drm_context_switch(dev, dev->last_context, ctx.handle)); 392 } 393 394 /*ARGSUSED*/ 395 int 396 drm_newctx(DRM_IOCTL_ARGS) 397 { 398 DRM_DEVICE; 399 drm_ctx_t ctx; 400 401 DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx)); 402 403 DRM_DEBUG("drm_newctx: %d", ctx.handle); 404 (void) drm_context_switch_complete(dev, ctx.handle); 405 406 return (0); 407 } 408 409 /*ARGSUSED*/ 410 int 411 drm_rmctx(DRM_IOCTL_ARGS) 412 { 413 DRM_DEVICE; 414 drm_ctx_t ctx; 415 416 DRM_COPY_FROM_USER_IOCTL(ctx, (drm_ctx_t *)data, sizeof (ctx)); 417 418 DRM_DEBUG("drm_rmctx : %d", ctx.handle); 419 if (ctx.handle != DRM_KERNEL_CONTEXT) { 420 if (dev->context_dtor) { 421 DRM_LOCK(); 422 dev->context_dtor(dev, ctx.handle); 423 DRM_UNLOCK(); 424 } 425 426 drm_ctxbitmap_free(dev, ctx.handle); 427 } 428 429 return (0); 430 } 431