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/atm/hea/eni_buffer.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  *
    3  * ===================================
    4  * HARP  |  Host ATM Research Platform
    5  * ===================================
    6  *
    7  *
    8  * This Host ATM Research Platform ("HARP") file (the "Software") is
    9  * made available by Network Computing Services, Inc. ("NetworkCS")
   10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
   11  * support of any kind.
   12  *
   13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
   14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
   15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
   16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
   17  * In no event shall NetworkCS be responsible for any damages, including
   18  * but not limited to consequential damages, arising from or relating to
   19  * any use of the Software or related support.
   20  *
   21  * Copyright 1994-1998 Network Computing Services, Inc.
   22  *
   23  * Copies of this Software may be made, however, the above copyright
   24  * notice must be reproduced on all copies.
   25  *
   26  *      @(#) $FreeBSD: src/sys/dev/hea/eni_buffer.c,v 1.5 1999/08/28 00:41:43 peter Exp $
   27  */
   28 
   29 /*
   30  * Efficient ENI Adapter Support
   31  * -----------------------------
   32  *
   33  * Handle adapter memory buffers for ENI adapters
   34  *
   35  */
   36 
   37 #include <netproto/atm/kern_include.h>
   38 
   39 #include "eni_stats.h"
   40 #include "eni.h"
   41 #include "eni_var.h"
   42 
   43 static int      eni_test_memory (Eni_unit *);
   44 
   45 /*
   46  * The host is going to manage (that is, allocate and free) buffers
   47  * in the adapters RAM space. We are going to implement this as a
   48  * linked list describing FREE and INUSE memory segments. Initially,
   49  * the list contains one element with all memory marked free. As requests
   50  * are made, we search the list until we find the first free element
   51  * which can satisfy the request. If necessary, we will break the free
   52  * element into an INUSE element, and a new FREE element. When freeing
   53  * memory, we look at adjacent elements and if one or more are free,
   54  * we will combine into a single larger FREE element.
   55  */
   56 
   57 /*
   58  * This is for testing purposes. Since there are two versions of
   59  * the Efficient adapter with different memory sizes, this allows
   60  * us to fool an adapter with more memory into thinking it has less.
   61  */
   62 static int eni_mem_max = MAX_ENI_MEM;   /* Default to all available memory */
   63 
   64 /*
   65  * Size and test adapter RAM
   66  *
   67  * Walk through adapter RAM writing known patterns and reading back
   68  * for comparison. We write more than one pattern on the off chance
   69  * that we "get lucky" and read what we expected.
   70  *
   71  * Arguments:
   72  *      eup             pointer to device unit structure
   73  *
   74  * Returns
   75  *      size            memory size in bytes
   76  */
   77 static int
   78 eni_test_memory(Eni_unit *eup)
   79 {
   80         int     ram_size = 0;
   81         int     i;
   82         Eni_mem mp;
   83 
   84         /*
   85          * Walk through to maximum looking for RAM
   86          */
   87         for ( i = 0; i < MAX_ENI_MEM; i += TEST_STEP ) {
   88                 mp = (Eni_mem)((int)eup->eu_ram + i);
   89                 /* write pattern */
   90                 *mp = (u_long)TEST_PAT;
   91                 /* read pattern, match? */
   92                 if ( *mp == (u_long)TEST_PAT ) {
   93                         /* yes - write inverse pattern */
   94                         *mp = (u_long)~TEST_PAT;
   95                         /* read pattern, match? */
   96                         if ( *mp == (u_long)~TEST_PAT ) {
   97                                 /* yes - assume another 1K available */
   98                                 ram_size = i + TEST_STEP;
   99                         } else
  100                             break;
  101                 } else
  102                         break;
  103         }
  104         /*
  105          * Clear all RAM to initial value of zero.
  106          * This makes sure we don't leave anything funny in the
  107          * queues.
  108          */
  109         KM_ZERO ( eup->eu_ram, ram_size );
  110 
  111         /*
  112          * If we'd like to claim to have less memory, here's where
  113          * we do so. We take the minimum of what we'd like and what
  114          * we really found on the adapter.
  115          */
  116         ram_size = MIN ( ram_size, eni_mem_max ); 
  117 
  118         return ( ram_size );
  119 
  120 }
  121 
  122 /*
  123  * Initialize our memory allocator.
  124  *
  125  * Arguments:
  126  *      eup             Pointer to per unit structure
  127  *
  128  * Returns:
  129  *      size            Physical RAM size
  130  *      -1              failed to initialize memory
  131  *
  132  */
  133 int
  134 eni_init_memory(Eni_unit *eup)
  135 {
  136 
  137         /*
  138          * Have we (somehow) been called before?
  139          */
  140         if ( eup->eu_memmap != NULL )
  141         {
  142                 /* Oops  - it's already been initialized */
  143                 return -1;
  144         }
  145 
  146         /*
  147          * Allocate initial element which will hold all of memory
  148          */
  149         eup->eu_memmap = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_WAITOK);
  150 
  151         /*
  152          * Test and size memory
  153          */
  154         eup->eu_ramsize = eni_test_memory ( eup );
  155 
  156         /*
  157          * Initialize a one element list which contains
  158          * all buffer memory
  159          */
  160         eup->eu_memmap->prev = eup->eu_memmap->next = NULL;
  161         eup->eu_memmap->base = (caddr_t)SEGBUF_BASE;
  162         eup->eu_memmap->size = eup->eu_ramsize - SEGBUF_BASE;
  163         eup->eu_memmap->state = MEM_FREE;
  164 
  165         return ( eup->eu_ramsize );
  166 }
  167 
  168 /*
  169  * Allocate a buffer from adapter RAM. Due to constraints on the card,
  170  * we may roundup the size request to the next largest chunksize. Note
  171  * also that we must pay attention to address alignment within adapter
  172  * memory as well.
  173  *
  174  * Arguments:
  175  *      eup             pointer to per unit structure
  176  *      size            pointer to requested size - in bytes
  177  *
  178  * Returns:
  179  *      addr            address relative to adapter of allocated memory
  180  *      size            modified to reflect actual size of buffer
  181  *
  182  */
  183 caddr_t
  184 eni_allocate_buffer(Eni_unit *eup, u_long *size)
  185 {
  186         int     nsize;
  187         int     nclicks;
  188         Mbd     *eptr = eup->eu_memmap;
  189 
  190         /*
  191          * Initial size requested
  192          */
  193         nsize = *size;
  194 
  195         /*
  196          * Find the buffer size which will hold this request. There
  197          * are 8 possible sizes, each a power of two up, starting at
  198          * 256 words or 1024 bytes.
  199          */
  200         for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ )
  201                 if ( ( 1 << nclicks ) * ENI_BUF_PGSZ >= nsize )
  202                         break;
  203 
  204         /*
  205          * Request was for larger then the card supports
  206          */
  207         if ( nclicks >= ENI_BUF_NBIT ) {
  208                 eup->eu_stats.eni_st_drv.drv_mm_toobig++;
  209                 /* Indicate 0 bytes allocated */
  210                 *size = 0;
  211                 /* Return NULL buffer */
  212                 return ( NULL );
  213         }
  214 
  215         /*
  216          * New size will be buffer size
  217          */
  218         nsize = ( 1 << nclicks ) * ENI_BUF_PGSZ;
  219 
  220         /*
  221          * Look through memory for a segment large enough to
  222          * hold request
  223          */
  224         while ( eptr ) {
  225             /*
  226              * State must be FREE and size must hold request
  227              */
  228             if ( eptr->state == MEM_FREE && eptr->size >= nsize )
  229             {
  230                 /*
  231                  * Request will fit - now check if the
  232                  * alignment needs fixing
  233                  */
  234                 if ( ((u_int)eptr->base & (nsize-1)) != 0 )
  235                 {
  236                     caddr_t     nbase;
  237 
  238                     /*
  239                      * Calculate where the buffer would have to
  240                      * fall to be aligned.
  241                      */
  242                     nbase = (caddr_t)((u_int)( eptr->base + nsize ) &
  243                         ~(nsize-1));
  244                     /*
  245                      * If we use this alignment, will it still fit?
  246                      */
  247                     if ( (eptr->size - (nbase - eptr->base)) >= 0 )
  248                     {
  249                         Mbd     *etmp;
  250 
  251                         /* Yep - create a new segment */
  252                         etmp = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_WAITOK);
  253                         /* Place it in the list */
  254                         etmp->next = eptr->next;
  255                         if ( etmp->next )
  256                             etmp->next->prev = etmp;
  257                         etmp->prev = eptr;
  258                         eptr->next = etmp;
  259                         /* Fill in new base and size */
  260                         etmp->base = nbase;
  261                         etmp->size = eptr->size - ( nbase - eptr->base );
  262                         /* Adjust old size */
  263                         eptr->size -= etmp->size;
  264                         /* Mark its state */
  265                         etmp->state = MEM_FREE;
  266                         eptr = etmp;
  267                         /* Done - outa here */
  268                         break;
  269                     }
  270                 } else
  271                     break;              /* Alignment is okay  - we're done */
  272             }
  273             /* Haven't found anything yet - keep looking */
  274             eptr = eptr->next;
  275         }
  276 
  277         if ( eptr != NULL )
  278         {
  279             /* Found a usable segment - grab what we need */
  280             /* Exact fit? */
  281             if ( eptr->size == nsize )
  282                 /* Mark it as INUSE */
  283                 eptr->state = MEM_INUSE;
  284             else
  285             {
  286                 Mbd     *etmp;
  287                 /* larger then we need - split it */
  288 
  289                 etmp = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_WAITOK);
  290                 /* Place new element in list */
  291                 etmp->next = eptr->next;
  292                 if ( etmp->next )
  293                     etmp->next->prev = etmp;
  294                 etmp->prev = eptr;
  295                 eptr->next = etmp;
  296                 /* Set new base, size and state */
  297                 etmp->base = eptr->base + nsize;
  298                 etmp->size = eptr->size - nsize;
  299                 etmp->state = MEM_FREE;
  300                 /* Adjust size and state of element we intend to use */
  301                 eptr->size = nsize;
  302                 eptr->state = MEM_INUSE;
  303             }
  304         }
  305 
  306         /* After all that, did we find a usable buffer? */
  307         if ( eptr )
  308         {
  309                 /* Record another inuse buffer of this size */
  310                 if ( eptr->base )
  311                         eup->eu_memclicks[nclicks]++;
  312 
  313                 /*
  314                  * Return true size of allocated buffer
  315                  */
  316                 *size = eptr->size;
  317                 /*
  318                  * Make address relative to start of RAM since
  319                  * its (the address) for use by the adapter, not
  320                  * the host.
  321                  */
  322                 return ((caddr_t)eptr->base);
  323         } else {
  324                 eup->eu_stats.eni_st_drv.drv_mm_nobuf++;
  325                 /* No buffer to return - indicate zero length */
  326                 *size = 0;
  327                 /* Return NULL buffer */
  328                 return ( NULL );
  329         }
  330 }
  331 
  332 /*
  333  * Procedure to release a buffer previously allocated from adapter
  334  * RAM. When possible, we'll compact memory.
  335  *
  336  * Arguments:
  337  *      eup             pointer to per unit structure
  338  *      base            base adapter address of buffer to be freed
  339  *
  340  * Returns:
  341  *      none
  342  *
  343  */
  344 void
  345 eni_free_buffer(Eni_unit *eup, caddr_t base)
  346 {
  347         Mbd     *eptr = eup->eu_memmap;
  348         int     nclicks;
  349 
  350         /* Look through entire list */
  351         while ( eptr )
  352         {
  353                 /* Is this the buffer to be freed? */
  354                 if ( eptr->base == base )
  355                 {
  356                         /*
  357                          * We're probably asking for trouble but,
  358                          * assume this is it.
  359                          */
  360                         if ( eptr->state != MEM_INUSE )
  361                         {
  362                                 eup->eu_stats.eni_st_drv.drv_mm_notuse++;
  363                                 /* Huh? Something's wrong */
  364                                 return;
  365                         }
  366                         /* Reset state to FREE */
  367                         eptr->state = MEM_FREE;
  368 
  369                         /* Determine size for stats info */
  370                         for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ )
  371                             if ( ( 1 << nclicks ) * ENI_BUF_PGSZ == eptr->size )
  372                                 break;
  373 
  374                         /* Valid size? Yes - decrement inuse count */
  375                         if ( nclicks < ENI_BUF_NBIT )
  376                                 eup->eu_memclicks[nclicks]--;
  377 
  378                         /* Try to compact neighbors */
  379                         /* with previous */
  380                         if ( eptr->prev )
  381                             if ( eptr->prev->state == MEM_FREE )
  382                             {
  383                                 Mbd     *etmp = eptr;
  384                                 /* Add to previous block */
  385                                 eptr->prev->size += eptr->size;
  386                                 /* Set prev block to skip this one */
  387                                 eptr->prev->next = eptr->next;
  388                                 /* Set next block to skip this one */
  389                                 if ( eptr->next )
  390                                         eptr->next->prev = eptr->prev;
  391                                 /* Reset to where we want to be */
  392                                 eptr = eptr->prev;
  393                                 /* and free this element */
  394                                 (void)KM_FREE(etmp, etmp->size, M_DEVBUF);
  395                             }
  396                         /* with next */
  397                         if ( eptr->next )
  398                             if ( eptr->next->state == MEM_FREE )
  399                             {
  400                                 Mbd     *etmp = eptr->next;
  401 
  402                                 /* add following block in */
  403                                 eptr->size += etmp->size;
  404                                 /* set next next block to skip next block */
  405                                 if ( etmp->next )
  406                                         etmp->next->prev = eptr;
  407                                 /* skip next block */
  408                                 eptr->next = etmp->next;
  409                                 /* and free next element */
  410                                 (void)KM_FREE(etmp, etmp->size, M_DEVBUF);
  411                             }
  412                         /*
  413                          * We've freed the buffer and done any compaction,
  414                          * we needn't look any further...
  415                          */
  416                         return;
  417                 }
  418                 eptr = eptr->next;
  419         }
  420 
  421         if ( eptr == NULL )
  422         {
  423                 /* Oops - failed to find the buffer. This is BAD */
  424                 eup->eu_stats.eni_st_drv.drv_mm_notfnd++;
  425         }
  426 
  427 }
  428 

Cache object: 55d9d823f4f4ffd3c1f8126f7948a044


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