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_gem.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2011 The FreeBSD Foundation
    5  *
    6  * This software was developed by Konstantin Belousov under sponsorship from
    7  * the FreeBSD Foundation.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include "opt_vm.h"
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/limits.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 
   42 #include <vm/vm.h>
   43 #include <vm/vm_page.h>
   44 
   45 #include <dev/drm2/drmP.h>
   46 #include <dev/drm2/drm.h>
   47 #include <dev/drm2/drm_sarea.h>
   48 
   49 /*
   50  * We make up offsets for buffer objects so we can recognize them at
   51  * mmap time.
   52  */
   53 
   54 /* pgoff in mmap is an unsigned long, so we need to make sure that
   55  * the faked up offset will fit
   56  */
   57 
   58 #if BITS_PER_LONG == 64
   59 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
   60 #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
   61 #else
   62 #define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
   63 #define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
   64 #endif
   65 
   66 /**
   67  * Initialize the GEM device fields
   68  */
   69 
   70 int
   71 drm_gem_init(struct drm_device *dev)
   72 {
   73         struct drm_gem_mm *mm;
   74 
   75         drm_gem_names_init(&dev->object_names);
   76 
   77         mm = malloc(sizeof(*mm), DRM_MEM_DRIVER, M_NOWAIT);
   78         if (!mm) {
   79                 DRM_ERROR("out of memory\n");
   80                 return -ENOMEM;
   81         }
   82 
   83         dev->mm_private = mm;
   84 
   85         if (drm_ht_create(&mm->offset_hash, 19)) {
   86                 free(mm, DRM_MEM_DRIVER);
   87                 return -ENOMEM;
   88         }
   89 
   90         mm->idxunr = new_unrhdr(0, DRM_GEM_MAX_IDX, NULL);
   91 
   92         return 0;
   93 }
   94 
   95 void
   96 drm_gem_destroy(struct drm_device *dev)
   97 {
   98         struct drm_gem_mm *mm = dev->mm_private;
   99 
  100         dev->mm_private = NULL;
  101         drm_ht_remove(&mm->offset_hash);
  102         delete_unrhdr(mm->idxunr);
  103         free(mm, DRM_MEM_DRIVER);
  104         drm_gem_names_fini(&dev->object_names);
  105 }
  106 
  107 int drm_gem_object_init(struct drm_device *dev,
  108                         struct drm_gem_object *obj, size_t size)
  109 {
  110         KASSERT((size & (PAGE_SIZE - 1)) == 0,
  111             ("Bad size %ju", (uintmax_t)size));
  112 
  113         obj->dev = dev;
  114         obj->vm_obj = vm_pager_allocate(OBJT_SWAP, NULL, size,
  115             VM_PROT_READ | VM_PROT_WRITE, 0, curthread->td_ucred);
  116 
  117         obj->refcount = 1;
  118         obj->handle_count = 0;
  119         obj->size = size;
  120 
  121         return 0;
  122 }
  123 EXPORT_SYMBOL(drm_gem_object_init);
  124 
  125 /**
  126  * Initialize an already allocated GEM object of the specified size with
  127  * no GEM provided backing store. Instead the caller is responsible for
  128  * backing the object and handling it.
  129  */
  130 int drm_gem_private_object_init(struct drm_device *dev,
  131                         struct drm_gem_object *obj, size_t size)
  132 {
  133         MPASS((size & (PAGE_SIZE - 1)) == 0);
  134 
  135         obj->dev = dev;
  136         obj->vm_obj = NULL;
  137 
  138         obj->refcount = 1;
  139         atomic_store_rel_int(&obj->handle_count, 0);
  140         obj->size = size;
  141 
  142         return 0;
  143 }
  144 EXPORT_SYMBOL(drm_gem_private_object_init);
  145 
  146 struct drm_gem_object *
  147 drm_gem_object_alloc(struct drm_device *dev, size_t size)
  148 {
  149         struct drm_gem_object *obj;
  150 
  151         obj = malloc(sizeof(*obj), DRM_MEM_DRIVER, M_NOWAIT | M_ZERO);
  152         if (!obj)
  153                 goto free;
  154 
  155         if (drm_gem_object_init(dev, obj, size) != 0)
  156                 goto free;
  157 
  158         if (dev->driver->gem_init_object != NULL &&
  159             dev->driver->gem_init_object(obj) != 0) {
  160                 goto dealloc;
  161         }
  162         return obj;
  163 dealloc:
  164         vm_object_deallocate(obj->vm_obj);
  165 free:
  166         free(obj, DRM_MEM_DRIVER);
  167         return NULL;
  168 }
  169 EXPORT_SYMBOL(drm_gem_object_alloc);
  170 
  171 #if defined(FREEBSD_NOTYET)
  172 static void
  173 drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
  174 {
  175         if (obj->import_attach) {
  176                 drm_prime_remove_buf_handle(&filp->prime,
  177                                 obj->import_attach->dmabuf);
  178         }
  179         if (obj->export_dma_buf) {
  180                 drm_prime_remove_buf_handle(&filp->prime,
  181                                 obj->export_dma_buf);
  182         }
  183 }
  184 #endif
  185 
  186 /**
  187  * Removes the mapping from handle to filp for this object.
  188  */
  189 int
  190 drm_gem_handle_delete(struct drm_file *filp, u32 handle)
  191 {
  192         struct drm_device *dev;
  193         struct drm_gem_object *obj;
  194 
  195         obj = drm_gem_names_remove(&filp->object_names, handle);
  196         if (obj == NULL) {
  197                 return -EINVAL;
  198         }
  199         dev = obj->dev;
  200 
  201 #if defined(FREEBSD_NOTYET)
  202         drm_gem_remove_prime_handles(obj, filp);
  203 #endif
  204 
  205         if (dev->driver->gem_close_object)
  206                 dev->driver->gem_close_object(obj, filp);
  207         drm_gem_object_handle_unreference_unlocked(obj);
  208 
  209         return 0;
  210 }
  211 EXPORT_SYMBOL(drm_gem_handle_delete);
  212 
  213 /**
  214  * Create a handle for this object. This adds a handle reference
  215  * to the object, which includes a regular reference count. Callers
  216  * will likely want to dereference the object afterwards.
  217  */
  218 int
  219 drm_gem_handle_create(struct drm_file *file_priv,
  220                        struct drm_gem_object *obj,
  221                        u32 *handlep)
  222 {
  223         struct drm_device *dev = obj->dev;
  224         int ret;
  225 
  226         *handlep = 0;
  227         ret = drm_gem_name_create(&file_priv->object_names, obj, handlep);
  228         if (ret != 0)
  229                 return ret;
  230 
  231         drm_gem_object_handle_reference(obj);
  232 
  233         if (dev->driver->gem_open_object) {
  234                 ret = dev->driver->gem_open_object(obj, file_priv);
  235                 if (ret) {
  236                         drm_gem_handle_delete(file_priv, *handlep);
  237                         return ret;
  238                 }
  239         }
  240 
  241         return 0;
  242 }
  243 EXPORT_SYMBOL(drm_gem_handle_create);
  244 
  245 void
  246 drm_gem_free_mmap_offset(struct drm_gem_object *obj)
  247 {
  248         struct drm_device *dev = obj->dev;
  249         struct drm_gem_mm *mm = dev->mm_private;
  250         struct drm_hash_item *list = &obj->map_list;
  251 
  252         if (!obj->on_map)
  253                 return;
  254 
  255         drm_ht_remove_item(&mm->offset_hash, list);
  256         free_unr(mm->idxunr, list->key);
  257         obj->on_map = false;
  258 }
  259 EXPORT_SYMBOL(drm_gem_free_mmap_offset);
  260 
  261 int
  262 drm_gem_create_mmap_offset(struct drm_gem_object *obj)
  263 {
  264         struct drm_device *dev = obj->dev;
  265         struct drm_gem_mm *mm = dev->mm_private;
  266         int ret;
  267 
  268         if (obj->on_map)
  269                 return 0;
  270 
  271         obj->map_list.key = alloc_unr(mm->idxunr);
  272         ret = drm_ht_insert_item(&mm->offset_hash, &obj->map_list);
  273         if (ret) {
  274                 DRM_ERROR("failed to add to map hash\n");
  275                 free_unr(mm->idxunr, obj->map_list.key);
  276                 return ret;
  277         }
  278         obj->on_map = true;
  279 
  280         return 0;
  281 }
  282 EXPORT_SYMBOL(drm_gem_create_mmap_offset);
  283 
  284 /** Returns a reference to the object named by the handle. */
  285 struct drm_gem_object *
  286 drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
  287                       u32 handle)
  288 {
  289         struct drm_gem_object *obj;
  290 
  291         obj = drm_gem_name_ref(&filp->object_names, handle,
  292             (void (*)(void *))drm_gem_object_reference);
  293 
  294         return obj;
  295 }
  296 EXPORT_SYMBOL(drm_gem_object_lookup);
  297 
  298 int
  299 drm_gem_close_ioctl(struct drm_device *dev, void *data,
  300                     struct drm_file *file_priv)
  301 {
  302         struct drm_gem_close *args = data;
  303         int ret;
  304 
  305         if (!(dev->driver->driver_features & DRIVER_GEM))
  306                 return -ENODEV;
  307 
  308         ret = drm_gem_handle_delete(file_priv, args->handle);
  309 
  310         return ret;
  311 }
  312 
  313 int
  314 drm_gem_flink_ioctl(struct drm_device *dev, void *data,
  315                     struct drm_file *file_priv)
  316 {
  317         struct drm_gem_flink *args = data;
  318         struct drm_gem_object *obj;
  319         int ret;
  320 
  321         if (!(dev->driver->driver_features & DRIVER_GEM))
  322                 return -ENODEV;
  323 
  324         obj = drm_gem_object_lookup(dev, file_priv, args->handle);
  325         if (obj == NULL)
  326                 return -ENOENT;
  327 
  328         ret = drm_gem_name_create(&dev->object_names, obj, &obj->name);
  329         if (ret != 0) {
  330                 if (ret == -EALREADY)
  331                         ret = 0;
  332                 drm_gem_object_unreference_unlocked(obj);
  333         }
  334         if (ret == 0)
  335                 args->name = obj->name;
  336         return ret;
  337 }
  338 
  339 int
  340 drm_gem_open_ioctl(struct drm_device *dev, void *data,
  341                    struct drm_file *file_priv)
  342 {
  343         struct drm_gem_open *args = data;
  344         struct drm_gem_object *obj;
  345         int ret;
  346         u32 handle;
  347 
  348         if (!(dev->driver->driver_features & DRIVER_GEM))
  349                 return -ENODEV;
  350 
  351         obj = drm_gem_name_ref(&dev->object_names, args->name,
  352             (void (*)(void *))drm_gem_object_reference);
  353         if (!obj)
  354                 return -ENOENT;
  355 
  356         ret = drm_gem_handle_create(file_priv, obj, &handle);
  357         drm_gem_object_unreference_unlocked(obj);
  358         if (ret)
  359                 return ret;
  360 
  361         args->handle = handle;
  362         args->size = obj->size;
  363 
  364         return 0;
  365 }
  366 
  367 void
  368 drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
  369 {
  370 
  371         drm_gem_names_init(&file_private->object_names);
  372 }
  373 
  374 static int
  375 drm_gem_object_release_handle(uint32_t name, void *ptr, void *data)
  376 {
  377         struct drm_file *file_priv = data;
  378         struct drm_gem_object *obj = ptr;
  379         struct drm_device *dev = obj->dev;
  380 
  381 #if defined(FREEBSD_NOTYET)
  382         drm_gem_remove_prime_handles(obj, file_priv);
  383 #endif
  384 
  385         if (dev->driver->gem_close_object)
  386                 dev->driver->gem_close_object(obj, file_priv);
  387 
  388         drm_gem_object_handle_unreference_unlocked(obj);
  389 
  390         return 0;
  391 }
  392 
  393 void
  394 drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
  395 {
  396         drm_gem_names_foreach(&file_private->object_names,
  397             drm_gem_object_release_handle, file_private);
  398 
  399         drm_gem_names_fini(&file_private->object_names);
  400 }
  401 
  402 void
  403 drm_gem_object_release(struct drm_gem_object *obj)
  404 {
  405 
  406         /*
  407          * obj->vm_obj can be NULL for private gem objects.
  408          */
  409         vm_object_deallocate(obj->vm_obj);
  410 }
  411 EXPORT_SYMBOL(drm_gem_object_release);
  412 
  413 void
  414 drm_gem_object_free(struct drm_gem_object *obj)
  415 {
  416         struct drm_device *dev = obj->dev;
  417 
  418         DRM_LOCK_ASSERT(dev);
  419         if (dev->driver->gem_free_object != NULL)
  420                 dev->driver->gem_free_object(obj);
  421 }
  422 EXPORT_SYMBOL(drm_gem_object_free);
  423 
  424 void drm_gem_object_handle_free(struct drm_gem_object *obj)
  425 {
  426         struct drm_device *dev = obj->dev;
  427         struct drm_gem_object *obj1;
  428 
  429         if (obj->name) {
  430                 obj1 = drm_gem_names_remove(&dev->object_names, obj->name);
  431                 obj->name = 0;
  432                 drm_gem_object_unreference(obj1);
  433         }
  434 }
  435 
  436 static struct drm_gem_object *
  437 drm_gem_object_from_offset(struct drm_device *dev, vm_ooffset_t offset)
  438 {
  439         struct drm_gem_object *obj;
  440         struct drm_gem_mm *mm;
  441         struct drm_hash_item *map_list;
  442 
  443         if ((offset & DRM_GEM_MAPPING_MASK) != DRM_GEM_MAPPING_KEY)
  444                 return (NULL);
  445         offset &= ~DRM_GEM_MAPPING_KEY;
  446         mm = dev->mm_private;
  447         if (drm_ht_find_item(&mm->offset_hash, DRM_GEM_MAPPING_IDX(offset),
  448             &map_list) != 0) {
  449         DRM_DEBUG("drm_gem_object_from_offset: offset 0x%jx obj not found\n",
  450                     (uintmax_t)offset);
  451                 return (NULL);
  452         }
  453         obj = __containerof(map_list, struct drm_gem_object, map_list);
  454         return (obj);
  455 }
  456 
  457 int
  458 drm_gem_mmap_single(struct drm_device *dev, vm_ooffset_t *offset, vm_size_t size,
  459     struct vm_object **obj_res, int nprot)
  460 {
  461         struct drm_gem_object *gem_obj;
  462         struct vm_object *vm_obj;
  463 
  464         DRM_LOCK(dev);
  465         gem_obj = drm_gem_object_from_offset(dev, *offset);
  466         if (gem_obj == NULL) {
  467                 DRM_UNLOCK(dev);
  468                 return (-ENODEV);
  469         }
  470         drm_gem_object_reference(gem_obj);
  471         DRM_UNLOCK(dev);
  472         vm_obj = cdev_pager_allocate(gem_obj, OBJT_MGTDEVICE,
  473             dev->driver->gem_pager_ops, size, nprot,
  474             DRM_GEM_MAPPING_MAPOFF(*offset), curthread->td_ucred);
  475         if (vm_obj == NULL) {
  476                 drm_gem_object_unreference_unlocked(gem_obj);
  477                 return (-EINVAL);
  478         }
  479         *offset = DRM_GEM_MAPPING_MAPOFF(*offset);
  480         *obj_res = vm_obj;
  481         return (0);
  482 }
  483 
  484 void
  485 drm_gem_pager_dtr(void *handle)
  486 {
  487         struct drm_gem_object *obj;
  488         struct drm_device *dev;
  489 
  490         obj = handle;
  491         dev = obj->dev;
  492 
  493         DRM_LOCK(dev);
  494         drm_gem_free_mmap_offset(obj);
  495         drm_gem_object_unreference(obj);
  496         DRM_UNLOCK(dev);
  497 }

Cache object: 5db84e628bcd9b03099f67393a0bbe18


[ 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.