1/** 2 * \file drm_context.c 3 * IOCTLs for generic contexts 4 * 5 * \author Rickard E. (Rik) Faith <faith@valinux.com> 6 * \author Gareth Hughes <gareth@valinux.com> 7 */ 8 9/* 10 * Created: Fri Nov 24 18:31:37 2000 by gareth@valinux.com 11 * 12 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. 13 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. 14 * All Rights Reserved. 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a 17 * copy of this software and associated documentation files (the "Software"), 18 * to deal in the Software without restriction, including without limitation 19 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 20 * and/or sell copies of the Software, and to permit persons to whom the 21 * Software is furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice (including the next 24 * paragraph) shall be included in all copies or substantial portions of the 25 * Software. 26 * 27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 31 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 32 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 * OTHER DEALINGS IN THE SOFTWARE. 34 */ 35 36/* 37 * ChangeLog: 38 * 2001-11-16 Torsten Duwe <duwe@caldera.de> 39 * added context constructor/destructor hooks, 40 * needed by SiS driver's memory management. 41 */ 42 43#include "drmP.h" 44 45/******************************************************************/ 46/** \name Context bitmap support */ 47/*@{*/ 48 49/** 50 * Free a handle from the context bitmap. 51 * 52 * \param dev DRM device. 53 * \param ctx_handle context handle. 54 * 55 * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry 56 * in drm_device::context_sareas, while holding the drm_device::struct_mutex 57 * lock. 58 */ 59void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle) 60{ 61 if (ctx_handle < 0) 62 goto failed; 63 if (!dev->ctx_bitmap) 64 goto failed; 65 66 if (ctx_handle < DRM_MAX_CTXBITMAP) { 67 mutex_lock(&dev->struct_mutex); 68 clear_bit(ctx_handle, dev->ctx_bitmap); 69 dev->context_sareas[ctx_handle] = NULL; 70 mutex_unlock(&dev->struct_mutex); 71 return; 72 } 73 failed: 74 DRM_ERROR("Attempt to free invalid context handle: %d\n", ctx_handle); 75 return; 76} 77 78/** 79 * Context bitmap allocation. 80 * 81 * \param dev DRM device. 82 * \return (non-negative) context handle on success or a negative number on failure. 83 * 84 * Find the first zero bit in drm_device::ctx_bitmap and (re)allocates 85 * drm_device::context_sareas to accommodate the new entry while holding the 86 * drm_device::struct_mutex lock. 87 */ 88static int drm_ctxbitmap_next(drm_device_t * dev) 89{ 90 int bit; 91 92 if (!dev->ctx_bitmap) 93 return -1; 94 95 mutex_lock(&dev->struct_mutex); 96 bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP); 97 if (bit < DRM_MAX_CTXBITMAP) { 98 set_bit(bit, dev->ctx_bitmap); 99 DRM_DEBUG("drm_ctxbitmap_next bit : %d\n", bit); 100 if ((bit + 1) > dev->max_context) { 101 dev->max_context = (bit + 1); 102 if (dev->context_sareas) { 103 drm_map_t **ctx_sareas; 104 105 ctx_sareas = drm_realloc(dev->context_sareas, 106 (dev->max_context - 107 1) * 108 sizeof(*dev-> 109 context_sareas), 110 dev->max_context * 111 sizeof(*dev-> 112 context_sareas), 113 DRM_MEM_MAPS); 114 if (!ctx_sareas) { 115 clear_bit(bit, dev->ctx_bitmap); 116 mutex_unlock(&dev->struct_mutex); 117 return -1; 118 } 119 dev->context_sareas = ctx_sareas; 120 dev->context_sareas[bit] = NULL; 121 } else { 122 /* max_context == 1 at this point */ 123 dev->context_sareas = 124 drm_alloc(dev->max_context * 125 sizeof(*dev->context_sareas), 126 DRM_MEM_MAPS); 127 if (!dev->context_sareas) { 128 clear_bit(bit, dev->ctx_bitmap); 129 mutex_unlock(&dev->struct_mutex); 130 return -1; 131 } 132 dev->context_sareas[bit] = NULL; 133 } 134 } 135 mutex_unlock(&dev->struct_mutex); 136 return bit; 137 } 138 mutex_unlock(&dev->struct_mutex); 139 return -1; 140} 141 142/** 143 * Context bitmap initialization. 144 * 145 * \param dev DRM device. 146 * 147 * Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding 148 * the drm_device::struct_mutex lock. 149 */ 150int drm_ctxbitmap_init(drm_device_t * dev) 151{ 152 int i; 153 int temp; 154 155 mutex_lock(&dev->struct_mutex); 156 dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE, 157 DRM_MEM_CTXBITMAP); 158 if (dev->ctx_bitmap == NULL) { 159 mutex_unlock(&dev->struct_mutex); 160 return -ENOMEM; 161 } 162 memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE); 163 dev->context_sareas = NULL; 164 dev->max_context = -1; 165 mutex_unlock(&dev->struct_mutex); 166 167 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 168 temp = drm_ctxbitmap_next(dev); 169 DRM_DEBUG("drm_ctxbitmap_init : %d\n", temp); 170 } 171 172 return 0; 173} 174 175/** 176 * Context bitmap cleanup. 177 * 178 * \param dev DRM device. 179 * 180 * Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding 181 * the drm_device::struct_mutex lock. 182 */ 183void drm_ctxbitmap_cleanup(drm_device_t * dev) 184{ 185 mutex_lock(&dev->struct_mutex); 186 if (dev->context_sareas) 187 drm_free(dev->context_sareas, 188 sizeof(*dev->context_sareas) * 189 dev->max_context, DRM_MEM_MAPS); 190 drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP); 191 mutex_unlock(&dev->struct_mutex); 192} 193 194/*@}*/ 195 196/******************************************************************/ 197/** \name Per Context SAREA Support */ 198/*@{*/ 199 200/** 201 * Get per-context SAREA. 202 * 203 * \param inode device inode. 204 * \param filp file pointer. 205 * \param cmd command. 206 * \param arg user argument pointing to a drm_ctx_priv_map structure. 207 * \return zero on success or a negative number on failure. 208 * 209 * Gets the map from drm_device::context_sareas with the handle specified and 210 * returns its handle. 211 */ 212int drm_getsareactx(struct inode *inode, struct file *filp, 213 unsigned int cmd, unsigned long arg) 214{ 215 drm_file_t *priv = filp->private_data; 216 drm_device_t *dev = priv->head->dev; 217 drm_ctx_priv_map_t __user *argp = (void __user *)arg; 218 drm_ctx_priv_map_t request; 219 drm_map_t *map; 220 drm_map_list_t *_entry; 221 222 if (copy_from_user(&request, argp, sizeof(request))) 223 return -EFAULT; 224 225 mutex_lock(&dev->struct_mutex); 226 if (dev->max_context < 0 227 || request.ctx_id >= (unsigned)dev->max_context) { 228 mutex_unlock(&dev->struct_mutex); 229 return -EINVAL; 230 } 231 232 map = dev->context_sareas[request.ctx_id]; 233 mutex_unlock(&dev->struct_mutex); 234 235 request.handle = NULL; 236 list_for_each_entry(_entry, &dev->maplist->head, head) { 237 if (_entry->map == map) { 238 request.handle = 239 (void *)(unsigned long)_entry->user_token; 240 break; 241 } 242 } 243 if (request.handle == NULL) 244 return -EINVAL; 245 246 if (copy_to_user(argp, &request, sizeof(request))) 247 return -EFAULT; 248 return 0; 249} 250 251/** 252 * Set per-context SAREA. 253 * 254 * \param inode device inode. 255 * \param filp file pointer. 256 * \param cmd command. 257 * \param arg user argument pointing to a drm_ctx_priv_map structure. 258 * \return zero on success or a negative number on failure. 259 * 260 * Searches the mapping specified in \p arg and update the entry in 261 * drm_device::context_sareas with it. 262 */ 263int drm_setsareactx(struct inode *inode, struct file *filp, 264 unsigned int cmd, unsigned long arg) 265{ 266 drm_file_t *priv = filp->private_data; 267 drm_device_t *dev = priv->head->dev; 268 drm_ctx_priv_map_t request; 269 drm_map_t *map = NULL; 270 drm_map_list_t *r_list = NULL; 271 struct list_head *list; 272 273 if (copy_from_user(&request, 274 (drm_ctx_priv_map_t __user *) arg, sizeof(request))) 275 return -EFAULT; 276 277 mutex_lock(&dev->struct_mutex); 278 list_for_each(list, &dev->maplist->head) { 279 r_list = list_entry(list, drm_map_list_t, head); 280 if (r_list->map 281 && r_list->user_token == (unsigned long)request.handle) 282 goto found; 283 } 284 bad: 285 mutex_unlock(&dev->struct_mutex); 286 return -EINVAL; 287 288 found: 289 map = r_list->map; 290 if (!map) 291 goto bad; 292 if (dev->max_context < 0) 293 goto bad; 294 if (request.ctx_id >= (unsigned)dev->max_context) 295 goto bad; 296 dev->context_sareas[request.ctx_id] = map; 297 mutex_unlock(&dev->struct_mutex); 298 return 0; 299} 300 301/*@}*/ 302 303/******************************************************************/ 304/** \name The actual DRM context handling routines */ 305/*@{*/ 306 307/** 308 * Switch context. 309 * 310 * \param dev DRM device. 311 * \param old old context handle. 312 * \param new new context handle. 313 * \return zero on success or a negative number on failure. 314 * 315 * Attempt to set drm_device::context_flag. 316 */ 317static int drm_context_switch(drm_device_t * dev, int old, int new) 318{ 319 if (test_and_set_bit(0, &dev->context_flag)) { 320 DRM_ERROR("Reentering -- FIXME\n"); 321 return -EBUSY; 322 } 323 324 DRM_DEBUG("Context switch from %d to %d\n", old, new); 325 326 if (new == dev->last_context) { 327 clear_bit(0, &dev->context_flag); 328 return 0; 329 } 330 331 return 0; 332} 333 334/** 335 * Complete context switch. 336 * 337 * \param dev DRM device. 338 * \param new new context handle. 339 * \return zero on success or a negative number on failure. 340 * 341 * Updates drm_device::last_context and drm_device::last_switch. Verifies the 342 * hardware lock is held, clears the drm_device::context_flag and wakes up 343 * drm_device::context_wait. 344 */ 345static int drm_context_switch_complete(drm_device_t * dev, int new) 346{ 347 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ 348 dev->last_switch = jiffies; 349 350 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { 351 DRM_ERROR("Lock isn't held after context switch\n"); 352 } 353 354 /* If a context switch is ever initiated 355 when the kernel holds the lock, release 356 that lock here. */ 357 clear_bit(0, &dev->context_flag); 358 wake_up(&dev->context_wait); 359 360 return 0; 361} 362 363/** 364 * Reserve contexts. 365 * 366 * \param inode device inode. 367 * \param filp file pointer. 368 * \param cmd command. 369 * \param arg user argument pointing to a drm_ctx_res structure. 370 * \return zero on success or a negative number on failure. 371 */ 372int drm_resctx(struct inode *inode, struct file *filp, 373 unsigned int cmd, unsigned long arg) 374{ 375 drm_ctx_res_t res; 376 drm_ctx_t __user *argp = (void __user *)arg; 377 drm_ctx_t ctx; 378 int i; 379 380 if (copy_from_user(&res, argp, sizeof(res))) 381 return -EFAULT; 382 383 if (res.count >= DRM_RESERVED_CONTEXTS) { 384 memset(&ctx, 0, sizeof(ctx)); 385 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 386 ctx.handle = i; 387 if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx))) 388 return -EFAULT; 389 } 390 } 391 res.count = DRM_RESERVED_CONTEXTS; 392 393 if (copy_to_user(argp, &res, sizeof(res))) 394 return -EFAULT; 395 return 0; 396} 397 398/** 399 * Add context. 400 * 401 * \param inode device inode. 402 * \param filp file pointer. 403 * \param cmd command. 404 * \param arg user argument pointing to a drm_ctx structure. 405 * \return zero on success or a negative number on failure. 406 * 407 * Get a new handle for the context and copy to userspace. 408 */ 409int drm_addctx(struct inode *inode, struct file *filp, 410 unsigned int cmd, unsigned long arg) 411{ 412 drm_file_t *priv = filp->private_data; 413 drm_device_t *dev = priv->head->dev; 414 drm_ctx_list_t *ctx_entry; 415 drm_ctx_t __user *argp = (void __user *)arg; 416 drm_ctx_t ctx; 417 418 if (copy_from_user(&ctx, argp, sizeof(ctx))) 419 return -EFAULT; 420 421 ctx.handle = drm_ctxbitmap_next(dev); 422 if (ctx.handle == DRM_KERNEL_CONTEXT) { 423 /* Skip kernel's context and get a new one. */ 424 ctx.handle = drm_ctxbitmap_next(dev); 425 } 426 DRM_DEBUG("%d\n", ctx.handle); 427 if (ctx.handle == -1) { 428 DRM_DEBUG("Not enough free contexts.\n"); 429 /* Should this return -EBUSY instead? */ 430 return -ENOMEM; 431 } 432 433 if (ctx.handle != DRM_KERNEL_CONTEXT) { 434 if (dev->driver->context_ctor) 435 if (!dev->driver->context_ctor(dev, ctx.handle)) { 436 DRM_DEBUG("Running out of ctxs or memory.\n"); 437 return -ENOMEM; 438 } 439 } 440 441 ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST); 442 if (!ctx_entry) { 443 DRM_DEBUG("out of memory\n"); 444 return -ENOMEM; 445 } 446 447 INIT_LIST_HEAD(&ctx_entry->head); 448 ctx_entry->handle = ctx.handle; 449 ctx_entry->tag = priv; 450 451 mutex_lock(&dev->ctxlist_mutex); 452 list_add(&ctx_entry->head, &dev->ctxlist->head); 453 ++dev->ctx_count; 454 mutex_unlock(&dev->ctxlist_mutex); 455 456 if (copy_to_user(argp, &ctx, sizeof(ctx))) 457 return -EFAULT; 458 return 0; 459} 460 461int drm_modctx(struct inode *inode, struct file *filp, 462 unsigned int cmd, unsigned long arg) 463{ 464 /* This does nothing */ 465 return 0; 466} 467 468/** 469 * Get context. 470 * 471 * \param inode device inode. 472 * \param filp file pointer. 473 * \param cmd command. 474 * \param arg user argument pointing to a drm_ctx structure. 475 * \return zero on success or a negative number on failure. 476 */ 477int drm_getctx(struct inode *inode, struct file *filp, 478 unsigned int cmd, unsigned long arg) 479{ 480 drm_ctx_t __user *argp = (void __user *)arg; 481 drm_ctx_t ctx; 482 483 if (copy_from_user(&ctx, argp, sizeof(ctx))) 484 return -EFAULT; 485 486 /* This is 0, because we don't handle any context flags */ 487 ctx.flags = 0; 488 489 if (copy_to_user(argp, &ctx, sizeof(ctx))) 490 return -EFAULT; 491 return 0; 492} 493 494/** 495 * Switch context. 496 * 497 * \param inode device inode. 498 * \param filp file pointer. 499 * \param cmd command. 500 * \param arg user argument pointing to a drm_ctx structure. 501 * \return zero on success or a negative number on failure. 502 * 503 * Calls context_switch(). 504 */ 505int drm_switchctx(struct inode *inode, struct file *filp, 506 unsigned int cmd, unsigned long arg) 507{ 508 drm_file_t *priv = filp->private_data; 509 drm_device_t *dev = priv->head->dev; 510 drm_ctx_t ctx; 511 512 if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx))) 513 return -EFAULT; 514 515 DRM_DEBUG("%d\n", ctx.handle); 516 return drm_context_switch(dev, dev->last_context, ctx.handle); 517} 518 519/** 520 * New context. 521 * 522 * \param inode device inode. 523 * \param filp file pointer. 524 * \param cmd command. 525 * \param arg user argument pointing to a drm_ctx structure. 526 * \return zero on success or a negative number on failure. 527 * 528 * Calls context_switch_complete(). 529 */ 530int drm_newctx(struct inode *inode, struct file *filp, 531 unsigned int cmd, unsigned long arg) 532{ 533 drm_file_t *priv = filp->private_data; 534 drm_device_t *dev = priv->head->dev; 535 drm_ctx_t ctx; 536 537 if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx))) 538 return -EFAULT; 539 540 DRM_DEBUG("%d\n", ctx.handle); 541 drm_context_switch_complete(dev, ctx.handle); 542 543 return 0; 544} 545 546/** 547 * Remove context. 548 * 549 * \param inode device inode. 550 * \param filp file pointer. 551 * \param cmd command. 552 * \param arg user argument pointing to a drm_ctx structure. 553 * \return zero on success or a negative number on failure. 554 * 555 * If not the special kernel context, calls ctxbitmap_free() to free the specified context. 556 */ 557int drm_rmctx(struct inode *inode, struct file *filp, 558 unsigned int cmd, unsigned long arg) 559{ 560 drm_file_t *priv = filp->private_data; 561 drm_device_t *dev = priv->head->dev; 562 drm_ctx_t ctx; 563 564 if (copy_from_user(&ctx, (drm_ctx_t __user *) arg, sizeof(ctx))) 565 return -EFAULT; 566 567 DRM_DEBUG("%d\n", ctx.handle); 568 if (ctx.handle == DRM_KERNEL_CONTEXT + 1) { 569 priv->remove_auth_on_close = 1; 570 } 571 if (ctx.handle != DRM_KERNEL_CONTEXT) { 572 if (dev->driver->context_dtor) 573 dev->driver->context_dtor(dev, ctx.handle); 574 drm_ctxbitmap_free(dev, ctx.handle); 575 } 576 577 mutex_lock(&dev->ctxlist_mutex); 578 if (!list_empty(&dev->ctxlist->head)) { 579 drm_ctx_list_t *pos, *n; 580 581 list_for_each_entry_safe(pos, n, &dev->ctxlist->head, head) { 582 if (pos->handle == ctx.handle) { 583 list_del(&pos->head); 584 drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); 585 --dev->ctx_count; 586 } 587 } 588 } 589 mutex_unlock(&dev->ctxlist_mutex); 590 591 return 0; 592} 593 594/*@}*/ 595