root/drivers/gpu/drm/drm_context.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. drm_legacy_ctxbitmap_free
  2. drm_legacy_ctxbitmap_next
  3. drm_legacy_ctxbitmap_init
  4. drm_legacy_ctxbitmap_cleanup
  5. drm_legacy_ctxbitmap_flush
  6. drm_legacy_getsareactx
  7. drm_legacy_setsareactx
  8. drm_context_switch
  9. drm_context_switch_complete
  10. drm_legacy_resctx
  11. drm_legacy_addctx
  12. drm_legacy_getctx
  13. drm_legacy_switchctx
  14. drm_legacy_newctx
  15. drm_legacy_rmctx

   1 /*
   2  * Legacy: Generic DRM Contexts
   3  *
   4  * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
   5  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
   6  * All Rights Reserved.
   7  *
   8  * Author: Rickard E. (Rik) Faith <faith@valinux.com>
   9  * Author: Gareth Hughes <gareth@valinux.com>
  10  *
  11  * Permission is hereby granted, free of charge, to any person obtaining a
  12  * copy of this software and associated documentation files (the "Software"),
  13  * to deal in the Software without restriction, including without limitation
  14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15  * and/or sell copies of the Software, and to permit persons to whom the
  16  * Software is furnished to do so, subject to the following conditions:
  17  *
  18  * The above copyright notice and this permission notice (including the next
  19  * paragraph) shall be included in all copies or substantial portions of the
  20  * Software.
  21  *
  22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  25  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  26  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  28  * OTHER DEALINGS IN THE SOFTWARE.
  29  */
  30 
  31 #include <linux/slab.h>
  32 #include <linux/uaccess.h>
  33 
  34 #include <drm/drm_drv.h>
  35 #include <drm/drm_file.h>
  36 #include <drm/drm_print.h>
  37 
  38 #include "drm_legacy.h"
  39 
  40 struct drm_ctx_list {
  41         struct list_head head;
  42         drm_context_t handle;
  43         struct drm_file *tag;
  44 };
  45 
  46 /******************************************************************/
  47 /** \name Context bitmap support */
  48 /*@{*/
  49 
  50 /**
  51  * Free a handle from the context bitmap.
  52  *
  53  * \param dev DRM device.
  54  * \param ctx_handle context handle.
  55  *
  56  * Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
  57  * in drm_device::ctx_idr, while holding the drm_device::struct_mutex
  58  * lock.
  59  */
  60 void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle)
  61 {
  62         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
  63             !drm_core_check_feature(dev, DRIVER_LEGACY))
  64                 return;
  65 
  66         mutex_lock(&dev->struct_mutex);
  67         idr_remove(&dev->ctx_idr, ctx_handle);
  68         mutex_unlock(&dev->struct_mutex);
  69 }
  70 
  71 /**
  72  * Context bitmap allocation.
  73  *
  74  * \param dev DRM device.
  75  * \return (non-negative) context handle on success or a negative number on failure.
  76  *
  77  * Allocate a new idr from drm_device::ctx_idr while holding the
  78  * drm_device::struct_mutex lock.
  79  */
  80 static int drm_legacy_ctxbitmap_next(struct drm_device * dev)
  81 {
  82         int ret;
  83 
  84         mutex_lock(&dev->struct_mutex);
  85         ret = idr_alloc(&dev->ctx_idr, NULL, DRM_RESERVED_CONTEXTS, 0,
  86                         GFP_KERNEL);
  87         mutex_unlock(&dev->struct_mutex);
  88         return ret;
  89 }
  90 
  91 /**
  92  * Context bitmap initialization.
  93  *
  94  * \param dev DRM device.
  95  *
  96  * Initialise the drm_device::ctx_idr
  97  */
  98 void drm_legacy_ctxbitmap_init(struct drm_device * dev)
  99 {
 100         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 101             !drm_core_check_feature(dev, DRIVER_LEGACY))
 102                 return;
 103 
 104         idr_init(&dev->ctx_idr);
 105 }
 106 
 107 /**
 108  * Context bitmap cleanup.
 109  *
 110  * \param dev DRM device.
 111  *
 112  * Free all idr members using drm_ctx_sarea_free helper function
 113  * while holding the drm_device::struct_mutex lock.
 114  */
 115 void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev)
 116 {
 117         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 118             !drm_core_check_feature(dev, DRIVER_LEGACY))
 119                 return;
 120 
 121         mutex_lock(&dev->struct_mutex);
 122         idr_destroy(&dev->ctx_idr);
 123         mutex_unlock(&dev->struct_mutex);
 124 }
 125 
 126 /**
 127  * drm_ctxbitmap_flush() - Flush all contexts owned by a file
 128  * @dev: DRM device to operate on
 129  * @file: Open file to flush contexts for
 130  *
 131  * This iterates over all contexts on @dev and drops them if they're owned by
 132  * @file. Note that after this call returns, new contexts might be added if
 133  * the file is still alive.
 134  */
 135 void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file)
 136 {
 137         struct drm_ctx_list *pos, *tmp;
 138 
 139         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 140             !drm_core_check_feature(dev, DRIVER_LEGACY))
 141                 return;
 142 
 143         mutex_lock(&dev->ctxlist_mutex);
 144 
 145         list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) {
 146                 if (pos->tag == file &&
 147                     pos->handle != DRM_KERNEL_CONTEXT) {
 148                         if (dev->driver->context_dtor)
 149                                 dev->driver->context_dtor(dev, pos->handle);
 150 
 151                         drm_legacy_ctxbitmap_free(dev, pos->handle);
 152                         list_del(&pos->head);
 153                         kfree(pos);
 154                 }
 155         }
 156 
 157         mutex_unlock(&dev->ctxlist_mutex);
 158 }
 159 
 160 /*@}*/
 161 
 162 /******************************************************************/
 163 /** \name Per Context SAREA Support */
 164 /*@{*/
 165 
 166 /**
 167  * Get per-context SAREA.
 168  *
 169  * \param inode device inode.
 170  * \param file_priv DRM file private.
 171  * \param cmd command.
 172  * \param arg user argument pointing to a drm_ctx_priv_map structure.
 173  * \return zero on success or a negative number on failure.
 174  *
 175  * Gets the map from drm_device::ctx_idr with the handle specified and
 176  * returns its handle.
 177  */
 178 int drm_legacy_getsareactx(struct drm_device *dev, void *data,
 179                            struct drm_file *file_priv)
 180 {
 181         struct drm_ctx_priv_map *request = data;
 182         struct drm_local_map *map;
 183         struct drm_map_list *_entry;
 184 
 185         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 186             !drm_core_check_feature(dev, DRIVER_LEGACY))
 187                 return -EOPNOTSUPP;
 188 
 189         mutex_lock(&dev->struct_mutex);
 190 
 191         map = idr_find(&dev->ctx_idr, request->ctx_id);
 192         if (!map) {
 193                 mutex_unlock(&dev->struct_mutex);
 194                 return -EINVAL;
 195         }
 196 
 197         request->handle = NULL;
 198         list_for_each_entry(_entry, &dev->maplist, head) {
 199                 if (_entry->map == map) {
 200                         request->handle =
 201                             (void *)(unsigned long)_entry->user_token;
 202                         break;
 203                 }
 204         }
 205 
 206         mutex_unlock(&dev->struct_mutex);
 207 
 208         if (request->handle == NULL)
 209                 return -EINVAL;
 210 
 211         return 0;
 212 }
 213 
 214 /**
 215  * Set per-context SAREA.
 216  *
 217  * \param inode device inode.
 218  * \param file_priv DRM file private.
 219  * \param cmd command.
 220  * \param arg user argument pointing to a drm_ctx_priv_map structure.
 221  * \return zero on success or a negative number on failure.
 222  *
 223  * Searches the mapping specified in \p arg and update the entry in
 224  * drm_device::ctx_idr with it.
 225  */
 226 int drm_legacy_setsareactx(struct drm_device *dev, void *data,
 227                            struct drm_file *file_priv)
 228 {
 229         struct drm_ctx_priv_map *request = data;
 230         struct drm_local_map *map = NULL;
 231         struct drm_map_list *r_list = NULL;
 232 
 233         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 234             !drm_core_check_feature(dev, DRIVER_LEGACY))
 235                 return -EOPNOTSUPP;
 236 
 237         mutex_lock(&dev->struct_mutex);
 238         list_for_each_entry(r_list, &dev->maplist, head) {
 239                 if (r_list->map
 240                     && r_list->user_token == (unsigned long) request->handle)
 241                         goto found;
 242         }
 243       bad:
 244         mutex_unlock(&dev->struct_mutex);
 245         return -EINVAL;
 246 
 247       found:
 248         map = r_list->map;
 249         if (!map)
 250                 goto bad;
 251 
 252         if (IS_ERR(idr_replace(&dev->ctx_idr, map, request->ctx_id)))
 253                 goto bad;
 254 
 255         mutex_unlock(&dev->struct_mutex);
 256 
 257         return 0;
 258 }
 259 
 260 /*@}*/
 261 
 262 /******************************************************************/
 263 /** \name The actual DRM context handling routines */
 264 /*@{*/
 265 
 266 /**
 267  * Switch context.
 268  *
 269  * \param dev DRM device.
 270  * \param old old context handle.
 271  * \param new new context handle.
 272  * \return zero on success or a negative number on failure.
 273  *
 274  * Attempt to set drm_device::context_flag.
 275  */
 276 static int drm_context_switch(struct drm_device * dev, int old, int new)
 277 {
 278         if (test_and_set_bit(0, &dev->context_flag)) {
 279                 DRM_ERROR("Reentering -- FIXME\n");
 280                 return -EBUSY;
 281         }
 282 
 283         DRM_DEBUG("Context switch from %d to %d\n", old, new);
 284 
 285         if (new == dev->last_context) {
 286                 clear_bit(0, &dev->context_flag);
 287                 return 0;
 288         }
 289 
 290         return 0;
 291 }
 292 
 293 /**
 294  * Complete context switch.
 295  *
 296  * \param dev DRM device.
 297  * \param new new context handle.
 298  * \return zero on success or a negative number on failure.
 299  *
 300  * Updates drm_device::last_context and drm_device::last_switch. Verifies the
 301  * hardware lock is held, clears the drm_device::context_flag and wakes up
 302  * drm_device::context_wait.
 303  */
 304 static int drm_context_switch_complete(struct drm_device *dev,
 305                                        struct drm_file *file_priv, int new)
 306 {
 307         dev->last_context = new;        /* PRE/POST: This is the _only_ writer. */
 308 
 309         if (!_DRM_LOCK_IS_HELD(file_priv->master->lock.hw_lock->lock)) {
 310                 DRM_ERROR("Lock isn't held after context switch\n");
 311         }
 312 
 313         /* If a context switch is ever initiated
 314            when the kernel holds the lock, release
 315            that lock here. */
 316         clear_bit(0, &dev->context_flag);
 317 
 318         return 0;
 319 }
 320 
 321 /**
 322  * Reserve contexts.
 323  *
 324  * \param inode device inode.
 325  * \param file_priv DRM file private.
 326  * \param cmd command.
 327  * \param arg user argument pointing to a drm_ctx_res structure.
 328  * \return zero on success or a negative number on failure.
 329  */
 330 int drm_legacy_resctx(struct drm_device *dev, void *data,
 331                       struct drm_file *file_priv)
 332 {
 333         struct drm_ctx_res *res = data;
 334         struct drm_ctx ctx;
 335         int i;
 336 
 337         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 338             !drm_core_check_feature(dev, DRIVER_LEGACY))
 339                 return -EOPNOTSUPP;
 340 
 341         if (res->count >= DRM_RESERVED_CONTEXTS) {
 342                 memset(&ctx, 0, sizeof(ctx));
 343                 for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
 344                         ctx.handle = i;
 345                         if (copy_to_user(&res->contexts[i], &ctx, sizeof(ctx)))
 346                                 return -EFAULT;
 347                 }
 348         }
 349         res->count = DRM_RESERVED_CONTEXTS;
 350 
 351         return 0;
 352 }
 353 
 354 /**
 355  * Add context.
 356  *
 357  * \param inode device inode.
 358  * \param file_priv DRM file private.
 359  * \param cmd command.
 360  * \param arg user argument pointing to a drm_ctx structure.
 361  * \return zero on success or a negative number on failure.
 362  *
 363  * Get a new handle for the context and copy to userspace.
 364  */
 365 int drm_legacy_addctx(struct drm_device *dev, void *data,
 366                       struct drm_file *file_priv)
 367 {
 368         struct drm_ctx_list *ctx_entry;
 369         struct drm_ctx *ctx = data;
 370         int tmp_handle;
 371 
 372         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 373             !drm_core_check_feature(dev, DRIVER_LEGACY))
 374                 return -EOPNOTSUPP;
 375 
 376         tmp_handle = drm_legacy_ctxbitmap_next(dev);
 377         if (tmp_handle == DRM_KERNEL_CONTEXT) {
 378                 /* Skip kernel's context and get a new one. */
 379                 tmp_handle = drm_legacy_ctxbitmap_next(dev);
 380         }
 381         DRM_DEBUG("%d\n", tmp_handle);
 382         if (tmp_handle < 0) {
 383                 DRM_DEBUG("Not enough free contexts.\n");
 384                 /* Should this return -EBUSY instead? */
 385                 return tmp_handle;
 386         }
 387 
 388         ctx->handle = tmp_handle;
 389 
 390         ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL);
 391         if (!ctx_entry) {
 392                 DRM_DEBUG("out of memory\n");
 393                 return -ENOMEM;
 394         }
 395 
 396         INIT_LIST_HEAD(&ctx_entry->head);
 397         ctx_entry->handle = ctx->handle;
 398         ctx_entry->tag = file_priv;
 399 
 400         mutex_lock(&dev->ctxlist_mutex);
 401         list_add(&ctx_entry->head, &dev->ctxlist);
 402         mutex_unlock(&dev->ctxlist_mutex);
 403 
 404         return 0;
 405 }
 406 
 407 /**
 408  * Get context.
 409  *
 410  * \param inode device inode.
 411  * \param file_priv DRM file private.
 412  * \param cmd command.
 413  * \param arg user argument pointing to a drm_ctx structure.
 414  * \return zero on success or a negative number on failure.
 415  */
 416 int drm_legacy_getctx(struct drm_device *dev, void *data,
 417                       struct drm_file *file_priv)
 418 {
 419         struct drm_ctx *ctx = data;
 420 
 421         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 422             !drm_core_check_feature(dev, DRIVER_LEGACY))
 423                 return -EOPNOTSUPP;
 424 
 425         /* This is 0, because we don't handle any context flags */
 426         ctx->flags = 0;
 427 
 428         return 0;
 429 }
 430 
 431 /**
 432  * Switch context.
 433  *
 434  * \param inode device inode.
 435  * \param file_priv DRM file private.
 436  * \param cmd command.
 437  * \param arg user argument pointing to a drm_ctx structure.
 438  * \return zero on success or a negative number on failure.
 439  *
 440  * Calls context_switch().
 441  */
 442 int drm_legacy_switchctx(struct drm_device *dev, void *data,
 443                          struct drm_file *file_priv)
 444 {
 445         struct drm_ctx *ctx = data;
 446 
 447         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 448             !drm_core_check_feature(dev, DRIVER_LEGACY))
 449                 return -EOPNOTSUPP;
 450 
 451         DRM_DEBUG("%d\n", ctx->handle);
 452         return drm_context_switch(dev, dev->last_context, ctx->handle);
 453 }
 454 
 455 /**
 456  * New context.
 457  *
 458  * \param inode device inode.
 459  * \param file_priv DRM file private.
 460  * \param cmd command.
 461  * \param arg user argument pointing to a drm_ctx structure.
 462  * \return zero on success or a negative number on failure.
 463  *
 464  * Calls context_switch_complete().
 465  */
 466 int drm_legacy_newctx(struct drm_device *dev, void *data,
 467                       struct drm_file *file_priv)
 468 {
 469         struct drm_ctx *ctx = data;
 470 
 471         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 472             !drm_core_check_feature(dev, DRIVER_LEGACY))
 473                 return -EOPNOTSUPP;
 474 
 475         DRM_DEBUG("%d\n", ctx->handle);
 476         drm_context_switch_complete(dev, file_priv, ctx->handle);
 477 
 478         return 0;
 479 }
 480 
 481 /**
 482  * Remove context.
 483  *
 484  * \param inode device inode.
 485  * \param file_priv DRM file private.
 486  * \param cmd command.
 487  * \param arg user argument pointing to a drm_ctx structure.
 488  * \return zero on success or a negative number on failure.
 489  *
 490  * If not the special kernel context, calls ctxbitmap_free() to free the specified context.
 491  */
 492 int drm_legacy_rmctx(struct drm_device *dev, void *data,
 493                      struct drm_file *file_priv)
 494 {
 495         struct drm_ctx *ctx = data;
 496 
 497         if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) &&
 498             !drm_core_check_feature(dev, DRIVER_LEGACY))
 499                 return -EOPNOTSUPP;
 500 
 501         DRM_DEBUG("%d\n", ctx->handle);
 502         if (ctx->handle != DRM_KERNEL_CONTEXT) {
 503                 if (dev->driver->context_dtor)
 504                         dev->driver->context_dtor(dev, ctx->handle);
 505                 drm_legacy_ctxbitmap_free(dev, ctx->handle);
 506         }
 507 
 508         mutex_lock(&dev->ctxlist_mutex);
 509         if (!list_empty(&dev->ctxlist)) {
 510                 struct drm_ctx_list *pos, *n;
 511 
 512                 list_for_each_entry_safe(pos, n, &dev->ctxlist, head) {
 513                         if (pos->handle == ctx->handle) {
 514                                 list_del(&pos->head);
 515                                 kfree(pos);
 516                         }
 517                 }
 518         }
 519         mutex_unlock(&dev->ctxlist_mutex);
 520 
 521         return 0;
 522 }
 523 
 524 /*@}*/

/* [<][>][^][v][top][bottom][index][help] */