at v2.6.23 522 lines 14 kB view raw
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::ctx_idr, while holding the drm_device::struct_mutex 57 * lock. 58 */ 59void drm_ctxbitmap_free(struct drm_device * dev, int ctx_handle) 60{ 61 mutex_lock(&dev->struct_mutex); 62 idr_remove(&dev->ctx_idr, ctx_handle); 63 mutex_unlock(&dev->struct_mutex); 64} 65 66/** 67 * Context bitmap allocation. 68 * 69 * \param dev DRM device. 70 * \return (non-negative) context handle on success or a negative number on failure. 71 * 72 * Allocate a new idr from drm_device::ctx_idr while holding the 73 * drm_device::struct_mutex lock. 74 */ 75static int drm_ctxbitmap_next(struct drm_device * dev) 76{ 77 int new_id; 78 int ret; 79 80again: 81 if (idr_pre_get(&dev->ctx_idr, GFP_KERNEL) == 0) { 82 DRM_ERROR("Out of memory expanding drawable idr\n"); 83 return -ENOMEM; 84 } 85 mutex_lock(&dev->struct_mutex); 86 ret = idr_get_new_above(&dev->ctx_idr, NULL, 87 DRM_RESERVED_CONTEXTS, &new_id); 88 if (ret == -EAGAIN) { 89 mutex_unlock(&dev->struct_mutex); 90 goto again; 91 } 92 mutex_unlock(&dev->struct_mutex); 93 return new_id; 94} 95 96/** 97 * Context bitmap initialization. 98 * 99 * \param dev DRM device. 100 * 101 * Initialise the drm_device::ctx_idr 102 */ 103int drm_ctxbitmap_init(struct drm_device * dev) 104{ 105 idr_init(&dev->ctx_idr); 106 return 0; 107} 108 109/** 110 * Context bitmap cleanup. 111 * 112 * \param dev DRM device. 113 * 114 * Free all idr members using drm_ctx_sarea_free helper function 115 * while holding the drm_device::struct_mutex lock. 116 */ 117void drm_ctxbitmap_cleanup(struct drm_device * dev) 118{ 119 mutex_lock(&dev->struct_mutex); 120 idr_remove_all(&dev->ctx_idr); 121 mutex_unlock(&dev->struct_mutex); 122} 123 124/*@}*/ 125 126/******************************************************************/ 127/** \name Per Context SAREA Support */ 128/*@{*/ 129 130/** 131 * Get per-context SAREA. 132 * 133 * \param inode device inode. 134 * \param filp file pointer. 135 * \param cmd command. 136 * \param arg user argument pointing to a drm_ctx_priv_map structure. 137 * \return zero on success or a negative number on failure. 138 * 139 * Gets the map from drm_device::ctx_idr with the handle specified and 140 * returns its handle. 141 */ 142int drm_getsareactx(struct inode *inode, struct file *filp, 143 unsigned int cmd, unsigned long arg) 144{ 145 struct drm_file *priv = filp->private_data; 146 struct drm_device *dev = priv->head->dev; 147 struct drm_ctx_priv_map __user *argp = (void __user *)arg; 148 struct drm_ctx_priv_map request; 149 struct drm_map *map; 150 struct drm_map_list *_entry; 151 152 if (copy_from_user(&request, argp, sizeof(request))) 153 return -EFAULT; 154 155 mutex_lock(&dev->struct_mutex); 156 157 map = idr_find(&dev->ctx_idr, request.ctx_id); 158 if (!map) { 159 mutex_unlock(&dev->struct_mutex); 160 return -EINVAL; 161 } 162 163 mutex_unlock(&dev->struct_mutex); 164 165 request.handle = NULL; 166 list_for_each_entry(_entry, &dev->maplist, head) { 167 if (_entry->map == map) { 168 request.handle = 169 (void *)(unsigned long)_entry->user_token; 170 break; 171 } 172 } 173 if (request.handle == NULL) 174 return -EINVAL; 175 176 if (copy_to_user(argp, &request, sizeof(request))) 177 return -EFAULT; 178 return 0; 179} 180 181/** 182 * Set per-context SAREA. 183 * 184 * \param inode device inode. 185 * \param filp file pointer. 186 * \param cmd command. 187 * \param arg user argument pointing to a drm_ctx_priv_map structure. 188 * \return zero on success or a negative number on failure. 189 * 190 * Searches the mapping specified in \p arg and update the entry in 191 * drm_device::ctx_idr with it. 192 */ 193int drm_setsareactx(struct inode *inode, struct file *filp, 194 unsigned int cmd, unsigned long arg) 195{ 196 struct drm_file *priv = filp->private_data; 197 struct drm_device *dev = priv->head->dev; 198 struct drm_ctx_priv_map request; 199 struct drm_map *map = NULL; 200 struct drm_map_list *r_list = NULL; 201 202 if (copy_from_user(&request, 203 (struct drm_ctx_priv_map __user *) arg, 204 sizeof(request))) 205 return -EFAULT; 206 207 mutex_lock(&dev->struct_mutex); 208 list_for_each_entry(r_list, &dev->maplist, head) { 209 if (r_list->map 210 && r_list->user_token == (unsigned long)request.handle) 211 goto found; 212 } 213 bad: 214 mutex_unlock(&dev->struct_mutex); 215 return -EINVAL; 216 217 found: 218 map = r_list->map; 219 if (!map) 220 goto bad; 221 222 if (IS_ERR(idr_replace(&dev->ctx_idr, map, request.ctx_id))) 223 goto bad; 224 225 mutex_unlock(&dev->struct_mutex); 226 return 0; 227} 228 229/*@}*/ 230 231/******************************************************************/ 232/** \name The actual DRM context handling routines */ 233/*@{*/ 234 235/** 236 * Switch context. 237 * 238 * \param dev DRM device. 239 * \param old old context handle. 240 * \param new new context handle. 241 * \return zero on success or a negative number on failure. 242 * 243 * Attempt to set drm_device::context_flag. 244 */ 245static int drm_context_switch(struct drm_device * dev, int old, int new) 246{ 247 if (test_and_set_bit(0, &dev->context_flag)) { 248 DRM_ERROR("Reentering -- FIXME\n"); 249 return -EBUSY; 250 } 251 252 DRM_DEBUG("Context switch from %d to %d\n", old, new); 253 254 if (new == dev->last_context) { 255 clear_bit(0, &dev->context_flag); 256 return 0; 257 } 258 259 return 0; 260} 261 262/** 263 * Complete context switch. 264 * 265 * \param dev DRM device. 266 * \param new new context handle. 267 * \return zero on success or a negative number on failure. 268 * 269 * Updates drm_device::last_context and drm_device::last_switch. Verifies the 270 * hardware lock is held, clears the drm_device::context_flag and wakes up 271 * drm_device::context_wait. 272 */ 273static int drm_context_switch_complete(struct drm_device * dev, int new) 274{ 275 dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ 276 dev->last_switch = jiffies; 277 278 if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { 279 DRM_ERROR("Lock isn't held after context switch\n"); 280 } 281 282 /* If a context switch is ever initiated 283 when the kernel holds the lock, release 284 that lock here. */ 285 clear_bit(0, &dev->context_flag); 286 wake_up(&dev->context_wait); 287 288 return 0; 289} 290 291/** 292 * Reserve contexts. 293 * 294 * \param inode device inode. 295 * \param filp file pointer. 296 * \param cmd command. 297 * \param arg user argument pointing to a drm_ctx_res structure. 298 * \return zero on success or a negative number on failure. 299 */ 300int drm_resctx(struct inode *inode, struct file *filp, 301 unsigned int cmd, unsigned long arg) 302{ 303 struct drm_ctx_res res; 304 struct drm_ctx_res __user *argp = (void __user *)arg; 305 struct drm_ctx ctx; 306 int i; 307 308 if (copy_from_user(&res, argp, sizeof(res))) 309 return -EFAULT; 310 311 if (res.count >= DRM_RESERVED_CONTEXTS) { 312 memset(&ctx, 0, sizeof(ctx)); 313 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { 314 ctx.handle = i; 315 if (copy_to_user(&res.contexts[i], &ctx, sizeof(ctx))) 316 return -EFAULT; 317 } 318 } 319 res.count = DRM_RESERVED_CONTEXTS; 320 321 if (copy_to_user(argp, &res, sizeof(res))) 322 return -EFAULT; 323 return 0; 324} 325 326/** 327 * Add context. 328 * 329 * \param inode device inode. 330 * \param filp file pointer. 331 * \param cmd command. 332 * \param arg user argument pointing to a drm_ctx structure. 333 * \return zero on success or a negative number on failure. 334 * 335 * Get a new handle for the context and copy to userspace. 336 */ 337int drm_addctx(struct inode *inode, struct file *filp, 338 unsigned int cmd, unsigned long arg) 339{ 340 struct drm_file *priv = filp->private_data; 341 struct drm_device *dev = priv->head->dev; 342 struct drm_ctx_list *ctx_entry; 343 struct drm_ctx __user *argp = (void __user *)arg; 344 struct drm_ctx ctx; 345 346 if (copy_from_user(&ctx, argp, sizeof(ctx))) 347 return -EFAULT; 348 349 ctx.handle = drm_ctxbitmap_next(dev); 350 if (ctx.handle == DRM_KERNEL_CONTEXT) { 351 /* Skip kernel's context and get a new one. */ 352 ctx.handle = drm_ctxbitmap_next(dev); 353 } 354 DRM_DEBUG("%d\n", ctx.handle); 355 if (ctx.handle == -1) { 356 DRM_DEBUG("Not enough free contexts.\n"); 357 /* Should this return -EBUSY instead? */ 358 return -ENOMEM; 359 } 360 361 if (ctx.handle != DRM_KERNEL_CONTEXT) { 362 if (dev->driver->context_ctor) 363 if (!dev->driver->context_ctor(dev, ctx.handle)) { 364 DRM_DEBUG("Running out of ctxs or memory.\n"); 365 return -ENOMEM; 366 } 367 } 368 369 ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST); 370 if (!ctx_entry) { 371 DRM_DEBUG("out of memory\n"); 372 return -ENOMEM; 373 } 374 375 INIT_LIST_HEAD(&ctx_entry->head); 376 ctx_entry->handle = ctx.handle; 377 ctx_entry->tag = priv; 378 379 mutex_lock(&dev->ctxlist_mutex); 380 list_add(&ctx_entry->head, &dev->ctxlist); 381 ++dev->ctx_count; 382 mutex_unlock(&dev->ctxlist_mutex); 383 384 if (copy_to_user(argp, &ctx, sizeof(ctx))) 385 return -EFAULT; 386 return 0; 387} 388 389int drm_modctx(struct inode *inode, struct file *filp, 390 unsigned int cmd, unsigned long arg) 391{ 392 /* This does nothing */ 393 return 0; 394} 395 396/** 397 * Get context. 398 * 399 * \param inode device inode. 400 * \param filp file pointer. 401 * \param cmd command. 402 * \param arg user argument pointing to a drm_ctx structure. 403 * \return zero on success or a negative number on failure. 404 */ 405int drm_getctx(struct inode *inode, struct file *filp, 406 unsigned int cmd, unsigned long arg) 407{ 408 struct drm_ctx __user *argp = (void __user *)arg; 409 struct drm_ctx ctx; 410 411 if (copy_from_user(&ctx, argp, sizeof(ctx))) 412 return -EFAULT; 413 414 /* This is 0, because we don't handle any context flags */ 415 ctx.flags = 0; 416 417 if (copy_to_user(argp, &ctx, sizeof(ctx))) 418 return -EFAULT; 419 return 0; 420} 421 422/** 423 * Switch context. 424 * 425 * \param inode device inode. 426 * \param filp file pointer. 427 * \param cmd command. 428 * \param arg user argument pointing to a drm_ctx structure. 429 * \return zero on success or a negative number on failure. 430 * 431 * Calls context_switch(). 432 */ 433int drm_switchctx(struct inode *inode, struct file *filp, 434 unsigned int cmd, unsigned long arg) 435{ 436 struct drm_file *priv = filp->private_data; 437 struct drm_device *dev = priv->head->dev; 438 struct drm_ctx ctx; 439 440 if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx))) 441 return -EFAULT; 442 443 DRM_DEBUG("%d\n", ctx.handle); 444 return drm_context_switch(dev, dev->last_context, ctx.handle); 445} 446 447/** 448 * New context. 449 * 450 * \param inode device inode. 451 * \param filp file pointer. 452 * \param cmd command. 453 * \param arg user argument pointing to a drm_ctx structure. 454 * \return zero on success or a negative number on failure. 455 * 456 * Calls context_switch_complete(). 457 */ 458int drm_newctx(struct inode *inode, struct file *filp, 459 unsigned int cmd, unsigned long arg) 460{ 461 struct drm_file *priv = filp->private_data; 462 struct drm_device *dev = priv->head->dev; 463 struct drm_ctx ctx; 464 465 if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx))) 466 return -EFAULT; 467 468 DRM_DEBUG("%d\n", ctx.handle); 469 drm_context_switch_complete(dev, ctx.handle); 470 471 return 0; 472} 473 474/** 475 * Remove context. 476 * 477 * \param inode device inode. 478 * \param filp file pointer. 479 * \param cmd command. 480 * \param arg user argument pointing to a drm_ctx structure. 481 * \return zero on success or a negative number on failure. 482 * 483 * If not the special kernel context, calls ctxbitmap_free() to free the specified context. 484 */ 485int drm_rmctx(struct inode *inode, struct file *filp, 486 unsigned int cmd, unsigned long arg) 487{ 488 struct drm_file *priv = filp->private_data; 489 struct drm_device *dev = priv->head->dev; 490 struct drm_ctx ctx; 491 492 if (copy_from_user(&ctx, (struct drm_ctx __user *) arg, sizeof(ctx))) 493 return -EFAULT; 494 495 DRM_DEBUG("%d\n", ctx.handle); 496 if (ctx.handle == DRM_KERNEL_CONTEXT + 1) { 497 priv->remove_auth_on_close = 1; 498 } 499 if (ctx.handle != DRM_KERNEL_CONTEXT) { 500 if (dev->driver->context_dtor) 501 dev->driver->context_dtor(dev, ctx.handle); 502 drm_ctxbitmap_free(dev, ctx.handle); 503 } 504 505 mutex_lock(&dev->ctxlist_mutex); 506 if (!list_empty(&dev->ctxlist)) { 507 struct drm_ctx_list *pos, *n; 508 509 list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { 510 if (pos->handle == ctx.handle) { 511 list_del(&pos->head); 512 drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); 513 --dev->ctx_count; 514 } 515 } 516 } 517 mutex_unlock(&dev->ctxlist_mutex); 518 519 return 0; 520} 521 522/*@}*/