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 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "dev/drm/radeon.h"
   37 #include "dev/drm/drmP.h"
   38 #include "dev/drm/drm.h"
   39 #include "dev/drm/radeon_drm.h"
   40 #include "dev/drm/radeon_drv.h"
   41 
   42 /* Very simple allocator for GART memory, working on a static range
   43  * already mapped into each client's address space.  
   44  */
   45 
   46 static struct mem_block *split_block(struct mem_block *p, int start, int size,
   47                                      DRMFILE filp )
   48 {
   49         /* Maybe cut off the start of an existing block */
   50         if (start > p->start) {
   51                 struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
   52                 if (!newblock) 
   53                         goto out;
   54                 newblock->start = start;
   55                 newblock->size = p->size - (start - p->start);
   56                 newblock->filp = 0;
   57                 newblock->next = p->next;
   58                 newblock->prev = p;
   59                 p->next->prev = newblock;
   60                 p->next = newblock;
   61                 p->size -= newblock->size;
   62                 p = newblock;
   63         }
   64    
   65         /* Maybe cut off the end of an existing block */
   66         if (size < p->size) {
   67                 struct mem_block *newblock = DRM_MALLOC(sizeof(*newblock));
   68                 if (!newblock)
   69                         goto out;
   70                 newblock->start = start + size;
   71                 newblock->size = p->size - size;
   72                 newblock->filp = 0;
   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         for (p = heap->next ; p != heap ; p = p->next) {
   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         for (p = heap->next ; p != heap ; p = p->next) 
  106                 if (p->start == start)
  107                         return p;
  108 
  109         return NULL;
  110 }
  111 
  112 
  113 static void free_block( struct mem_block *p )
  114 {
  115         p->filp = 0;
  116 
  117         /* Assumes a single contiguous range.  Needs a special filp in
  118          * 'heap' to stop it being subsumed.
  119          */
  120         if (p->next->filp == 0) {
  121                 struct mem_block *q = p->next;
  122                 p->size += q->size;
  123                 p->next = q->next;
  124                 p->next->prev = p;
  125                 DRM_FREE(q, sizeof(*q));
  126         }
  127 
  128         if (p->prev->filp == 0) {
  129                 struct mem_block *q = p->prev;
  130                 q->size += p->size;
  131                 q->next = p->next;
  132                 q->next->prev = q;
  133                 DRM_FREE(p, sizeof(*q));
  134         }
  135 }
  136 
  137 /* Initialize.  How to check for an uninitialized heap?
  138  */
  139 static int init_heap(struct mem_block **heap, int start, int size)
  140 {
  141         struct mem_block *blocks = DRM_MALLOC(sizeof(*blocks));
  142 
  143         if (!blocks) 
  144                 return DRM_ERR(ENOMEM);
  145         
  146         *heap = DRM_MALLOC(sizeof(**heap));
  147         if (!*heap) {
  148                 DRM_FREE( blocks, sizeof(*blocks) );
  149                 return DRM_ERR(ENOMEM);
  150         }
  151 
  152         blocks->start = start;
  153         blocks->size = size;
  154         blocks->filp = 0;
  155         blocks->next = blocks->prev = *heap;
  156 
  157         memset( *heap, 0, sizeof(**heap) );
  158         (*heap)->filp = (DRMFILE) -1;
  159         (*heap)->next = (*heap)->prev = blocks;
  160         return 0;
  161 }
  162 
  163 
  164 /* Free all blocks associated with the releasing file.
  165  */
  166 void radeon_mem_release( DRMFILE filp, struct mem_block *heap )
  167 {
  168         struct mem_block *p;
  169 
  170         if (!heap || !heap->next)
  171                 return;
  172 
  173         for (p = heap->next ; p != heap ; p = p->next) {
  174                 if (p->filp == filp) 
  175                         p->filp = 0;
  176         }
  177 
  178         /* Assumes a single contiguous range.  Needs a special filp in
  179          * 'heap' to stop it being subsumed.
  180          */
  181         for (p = heap->next ; p != heap ; p = p->next) {
  182                 while (p->filp == 0 && p->next->filp == 0) {
  183                         struct mem_block *q = p->next;
  184                         p->size += q->size;
  185                         p->next = q->next;
  186                         p->next->prev = p;
  187                         DRM_FREE(q, sizeof(*q));
  188                 }
  189         }
  190 }
  191 
  192 /* Shutdown.
  193  */
  194 void radeon_mem_takedown( struct mem_block **heap )
  195 {
  196         struct mem_block *p;
  197         
  198         if (!*heap)
  199                 return;
  200 
  201         for (p = (*heap)->next ; p != *heap ; ) {
  202                 struct mem_block *q = p;
  203                 p = p->next;
  204                 DRM_FREE(q, sizeof(*q));
  205         }
  206 
  207         DRM_FREE( *heap, sizeof(**heap) );
  208         *heap = 0;
  209 }
  210 
  211 
  212 
  213 /* IOCTL HANDLERS */
  214 
  215 static struct mem_block **get_heap( drm_radeon_private_t *dev_priv,
  216                                    int region )
  217 {
  218         switch( region ) {
  219         case RADEON_MEM_REGION_GART:
  220                 return &dev_priv->gart_heap; 
  221         case RADEON_MEM_REGION_FB:
  222                 return &dev_priv->fb_heap;
  223         default:
  224                 return 0;
  225         }
  226 }
  227 
  228 int radeon_mem_alloc( DRM_IOCTL_ARGS )
  229 {
  230         DRM_DEVICE;
  231         drm_radeon_private_t *dev_priv = dev->dev_private;
  232         drm_radeon_mem_alloc_t alloc;
  233         struct mem_block *block, **heap;
  234 
  235         if ( !dev_priv ) {
  236                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
  237                 return DRM_ERR(EINVAL);
  238         }
  239 
  240         DRM_COPY_FROM_USER_IOCTL( alloc, (drm_radeon_mem_alloc_t *)data,
  241                                   sizeof(alloc) );
  242 
  243         heap = get_heap( dev_priv, alloc.region );
  244         if (!heap || !*heap)
  245                 return DRM_ERR(EFAULT);
  246         
  247         /* Make things easier on ourselves: all allocations at least
  248          * 4k aligned.
  249          */
  250         if (alloc.alignment < 12)
  251                 alloc.alignment = 12;
  252 
  253         block = alloc_block( *heap, alloc.size, alloc.alignment,
  254                              filp );
  255 
  256         if (!block) 
  257                 return DRM_ERR(ENOMEM);
  258 
  259         if ( DRM_COPY_TO_USER( alloc.region_offset, &block->start, 
  260                                sizeof(int) ) ) {
  261                 DRM_ERROR( "copy_to_user\n" );
  262                 return DRM_ERR(EFAULT);
  263         }
  264         
  265         return 0;
  266 }
  267 
  268 
  269 
  270 int radeon_mem_free( DRM_IOCTL_ARGS )
  271 {
  272         DRM_DEVICE;
  273         drm_radeon_private_t *dev_priv = dev->dev_private;
  274         drm_radeon_mem_free_t memfree;
  275         struct mem_block *block, **heap;
  276 
  277         if ( !dev_priv ) {
  278                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
  279                 return DRM_ERR(EINVAL);
  280         }
  281 
  282         DRM_COPY_FROM_USER_IOCTL( memfree, (drm_radeon_mem_free_t *)data,
  283                                   sizeof(memfree) );
  284 
  285         heap = get_heap( dev_priv, memfree.region );
  286         if (!heap || !*heap)
  287                 return DRM_ERR(EFAULT);
  288         
  289         block = find_block( *heap, memfree.region_offset );
  290         if (!block)
  291                 return DRM_ERR(EFAULT);
  292 
  293         if (block->filp != filp)
  294                 return DRM_ERR(EPERM);
  295 
  296         free_block( block );    
  297         return 0;
  298 }
  299 
  300 int radeon_mem_init_heap( DRM_IOCTL_ARGS )
  301 {
  302         DRM_DEVICE;
  303         drm_radeon_private_t *dev_priv = dev->dev_private;
  304         drm_radeon_mem_init_heap_t initheap;
  305         struct mem_block **heap;
  306 
  307         if ( !dev_priv ) {
  308                 DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
  309                 return DRM_ERR(EINVAL);
  310         }
  311 
  312         DRM_COPY_FROM_USER_IOCTL( initheap, (drm_radeon_mem_init_heap_t *)data,
  313                                   sizeof(initheap) );
  314 
  315         heap = get_heap( dev_priv, initheap.region );
  316         if (!heap) 
  317                 return DRM_ERR(EFAULT);
  318         
  319         if (*heap) {
  320                 DRM_ERROR("heap already initialized?");
  321                 return DRM_ERR(EFAULT);
  322         }
  323                 
  324         return init_heap( heap, initheap.start, initheap.size );
  325 }
  326 
  327 

Cache object: d9b268a786c0d5535ce0e71a45417118


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