The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm2/drm_context.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: e9e335e2d2b6dd1a988511e2d6c4e847


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.