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 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 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 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 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 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 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 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 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 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 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 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 376 drm_modctx(DRM_IOCTL_ARGS) 377 { 378 /* This does nothing */ 379 return (0); 380 } 381 382 /*ARGSUSED*/ 383 int 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 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 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 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 }