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/drm/radeon_mem.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 /* radeon_mem.c -- Simple GART/fb memory manager for radeon -*- linux-c -*- */
    2 /*-
    3  * Copyright (C) The Weather Channel, Inc.  2002.  All Rights Reserved.
    4  *
    5  * The Weather Channel (TM) funded Tungsten Graphics to develop the
    6  * initial release of the Radeon 8500 driver under the XFree86 license.
    7  * This notice must be preserved.
    8  *
    9  * Permission is hereby granted, free of charge, to any person obtaining a
   10  * copy of this software and associated documentation files (the "Software"),
   11  * to deal in the Software without restriction, including without limitation
   12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   13  * and/or sell copies of the Software, and to permit persons to whom the
   14  * Software is furnished to do so, subject to the following conditions:
   15  *
   16  * The above copyright notice and this permission notice (including the next
   17  * paragraph) shall be included in all copies or substantial portions of the
   18  * Software.
   19  *
   20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
   23  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
   24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
   25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   26  * DEALINGS IN THE SOFTWARE.
   27  *
   28  * Authors:
   29  *    Keith Whitwell <keith@tungstengraphics.com>
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/6.4/sys/dev/drm/radeon_mem.c 153401 2005-12-14 00:52:59Z anholt $");
   34 
   35 #include "dev/drm/drmP.h"
   36 #include "dev/drm/drm.h"
   37 #include "dev/drm/radeon_drm.h"
   38 #include "dev/drm/radeon_drv.h"
   39 
   40 /* Very simple allocator for GART memory, working on a static range
   41  * already mapped into each client's address space.
   42  */
   43 
   44 static struct mem_block *split_block(struct mem_block *p, int start, int size,
   45                                      DRMFILE filp)
   46 {
   47         /* Maybe cut off the start of an existing block */
   48         if (start > p->start) {
   49                 struct mem_block *newblock =
   50                     drm_alloc(sizeof(*newblock), DRM_MEM_BUFS);
   51                 if (!newblock)
   52                         goto out;
   53                 newblock->start = start;
   54                 newblock->size = p->size - (start - p->start);
   55                 newblock->filp = NULL;
   56                 newblock->next = p->next;
   57                 newblock->prev = p;
   58                 p->next->prev = newblock;
   59                 p->next = newblock;
   60                 p->size -= newblock->size;
   61                 p = newblock;
   62         }
   63 
   64         /* Maybe cut off the end of an existing block */
   65         if (size < p->size) {
   66                 struct mem_block *newblock =
   67                     drm_alloc(sizeof(*newblock), DRM_MEM_BUFS);
   68                 if (!newblock)
   69                         goto out;
   70                 newblock->start = start + size;
   71                 newblock->size = p->size - size;
   72                 newblock->filp = NULL;
   73                 newblock->next = p->next;
   74                 newblock->prev = p;
   75                 p->next->prev = newblock;
   76                 p->next = newblock;
   77                 p->size = size;
   78         }
   79 
   80       out:
   81         /* Our block is in the middle */
   82         p->filp = filp;
   83         return p;
   84 }
   85 
   86 static struct mem_block *alloc_block(struct mem_block *heap, int size,
   87                                      int align2, DRMFILE filp)
   88 {
   89         struct mem_block *p;
   90         int mask = (1 << align2) - 1;
   91 
   92         list_for_each(p, heap) {
   93                 int start = (p->start + mask) & ~mask;
   94                 if (p->filp == 0 && start + size <= p->start + p->size)
   95                         return split_block(p, start, size, filp);
   96         }
   97 
   98         return NULL;
   99 }
  100 
  101 static struct mem_block *find_block(struct mem_block *heap, int start)
  102 {
  103         struct mem_block *p;
  104 
  105         list_for_each(p, heap)
  106                 if (p->start == start)
  107                         return p;
  108 
  109         return NULL;
  110 }
  111 
  112 static void free_block(struct mem_block *p)
  113 {
  114         p->filp = NULL;
  115 
  116         /* Assumes a single contiguous range.  Needs a special filp in
  117          * 'heap' to stop it being subsumed.
  118          */
  119         if (p->next->filp == 0) {
  120                 struct mem_block *q = p->next;
  121                 p->size += q->size;
  122                 p->next = q->next;
  123                 p->next->prev = p;
  124                 drm_free(q, sizeof(*q), DRM_MEM_BUFS);
  125         }
  126 
  127         if (p->prev->filp == 0) {
  128                 struct mem_block *q = p->prev;
  129                 q->size += p->size;
  130                 q->next = p->next;
  131                 q->next->prev = q;
  132                 drm_free(p, sizeof(*q), DRM_MEM_BUFS);
  133         }
  134 }
  135 
  136 /* Initialize.  How to check for an uninitialized heap?
  137  */
  138 static int init_heap(struct mem_block **heap, int start, int size)
  139 {
  140         struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS);
  141 
  142         if (!blocks)
  143                 return DRM_ERR(ENOMEM);
  144 
  145         *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS);
  146         if (!*heap) {
  147                 drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS);
  148                 return DRM_ERR(ENOMEM);
  149         }
  150 
  151         blocks->start = start;
  152         blocks->size = size;
  153         blocks->filp = NULL;
  154         blocks->next = blocks->prev = *heap;
  155 
  156         memset(*heap, 0, sizeof(**heap));
  157         (*heap)->filp = (DRMFILE) - 1;
  158         (*heap)->next = (*heap)->prev = blocks;
  159         return 0;
  160 }
  161 
  162 /* Free all blocks associated with the releasing file.
  163  */
  164 void radeon_mem_release(DRMFILE filp, struct mem_block *heap)
  165 {
  166         struct mem_block *p;
  167 
  168         if (!heap || !heap->next)
  169                 return;
  170 
  171         list_for_each(p, heap) {
  172                 if (p->filp == filp)
  173                         p->filp = NULL;
  174         }
  175 
  176         /* Assumes a single contiguous range.  Needs a special filp in
  177          * 'heap' to stop it being subsumed.
  178          */
  179         list_for_each(p, heap) {
  180                 while (p->filp == 0 && p->next->filp == 0) {
  181                         struct mem_block *q = p->next;
  182                         p->size += q->size;
  183                         p->next = q->next;
  184                         p->next->prev = p;
  185                         drm_free(q, sizeof(*q), DRM_MEM_DRIVER);
  186                 }
  187         }
  188 }
  189 
  190 /* Shutdown.
  191  */
  192 void radeon_mem_takedown(struct mem_block **heap)
  193 {
  194         struct mem_block *p;
  195 
  196         if (!*heap)
  197                 return;
  198 
  199         for (p = (*heap)->next; p != *heap;) {
  200                 struct mem_block *q = p;
  201                 p = p->next;
  202                 drm_free(q, sizeof(*q), DRM_MEM_DRIVER);
  203         }
  204 
  205         drm_free(*heap, sizeof(**heap), DRM_MEM_DRIVER);
  206         *heap = NULL;
  207 }
  208 
  209 /* IOCTL HANDLERS */
  210 
  211 static struct mem_block **get_heap(drm_radeon_private_t * dev_priv, int region)
  212 {
  213         switch (region) {
  214         case RADEON_MEM_REGION_GART:
  215                 return &dev_priv->gart_heap;
  216         case RADEON_MEM_REGION_FB:
  217                 return &dev_priv->fb_heap;
  218         default:
  219                 return NULL;
  220         }
  221 }
  222 
  223 int radeon_mem_alloc(DRM_IOCTL_ARGS)
  224 {
  225         DRM_DEVICE;
  226         drm_radeon_private_t *dev_priv = dev->dev_private;
  227         drm_radeon_mem_alloc_t alloc;
  228         struct mem_block *block, **heap;
  229 
  230         if (!dev_priv) {
  231                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
  232                 return DRM_ERR(EINVAL);
  233         }
  234 
  235         DRM_COPY_FROM_USER_IOCTL(alloc, (drm_radeon_mem_alloc_t __user *) data,
  236                                  sizeof(alloc));
  237 
  238         heap = get_heap(dev_priv, alloc.region);
  239         if (!heap || !*heap)
  240                 return DRM_ERR(EFAULT);
  241 
  242         /* Make things easier on ourselves: all allocations at least
  243          * 4k aligned.
  244          */
  245         if (alloc.alignment < 12)
  246                 alloc.alignment = 12;
  247 
  248         block = alloc_block(*heap, alloc.size, alloc.alignment, filp);
  249 
  250         if (!block)
  251                 return DRM_ERR(ENOMEM);
  252 
  253         if (DRM_COPY_TO_USER(alloc.region_offset, &block->start, sizeof(int))) {
  254                 DRM_ERROR("copy_to_user\n");
  255                 return DRM_ERR(EFAULT);
  256         }
  257 
  258         return 0;
  259 }
  260 
  261 int radeon_mem_free(DRM_IOCTL_ARGS)
  262 {
  263         DRM_DEVICE;
  264         drm_radeon_private_t *dev_priv = dev->dev_private;
  265         drm_radeon_mem_free_t memfree;
  266         struct mem_block *block, **heap;
  267 
  268         if (!dev_priv) {
  269                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
  270                 return DRM_ERR(EINVAL);
  271         }
  272 
  273         DRM_COPY_FROM_USER_IOCTL(memfree, (drm_radeon_mem_free_t __user *) data,
  274                                  sizeof(memfree));
  275 
  276         heap = get_heap(dev_priv, memfree.region);
  277         if (!heap || !*heap)
  278                 return DRM_ERR(EFAULT);
  279 
  280         block = find_block(*heap, memfree.region_offset);
  281         if (!block)
  282                 return DRM_ERR(EFAULT);
  283 
  284         if (block->filp != filp)
  285                 return DRM_ERR(EPERM);
  286 
  287         free_block(block);
  288         return 0;
  289 }
  290 
  291 int radeon_mem_init_heap(DRM_IOCTL_ARGS)
  292 {
  293         DRM_DEVICE;
  294         drm_radeon_private_t *dev_priv = dev->dev_private;
  295         drm_radeon_mem_init_heap_t initheap;
  296         struct mem_block **heap;
  297 
  298         if (!dev_priv) {
  299                 DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
  300                 return DRM_ERR(EINVAL);
  301         }
  302 
  303         DRM_COPY_FROM_USER_IOCTL(initheap,
  304                                  (drm_radeon_mem_init_heap_t __user *) data,
  305                                  sizeof(initheap));
  306 
  307         heap = get_heap(dev_priv, initheap.region);
  308         if (!heap)
  309                 return DRM_ERR(EFAULT);
  310 
  311         if (*heap) {
  312                 DRM_ERROR("heap already initialized?");
  313                 return DRM_ERR(EFAULT);
  314         }
  315 
  316         return init_heap(heap, initheap.start, initheap.size);
  317 }

Cache object: eaf232384e71b8f1fc3d5cf48722d40a


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