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