'\"macro stdmacro
.if n .pH ddi_dki.rmalloc @(#)rmalloc	40.6 of 1/3/90
.\" Copyright 1989 AT&T
.de IX
.ie '\\n(.z'' .tm .Index: \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9	\\n%
.el \\!.IX \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9
..
.nr X
.if \nX=0 .ds x} rmalloc D3DK "" "DDI/DKI" "\&"
.if \nX=1 .ds x} rmalloc D3DK "" "DDI/DKI"
.if \nX=2 .ds x} rmalloc D3DK "" "\&"
.if \nX=3 .ds x} rmalloc "" "" "\&"
.TH \*(x}
.IX "\f4rmalloc\fP(D3DK)"
.SH NAME
\f4rmalloc\f1 \- allocate space from a private space management map
.SH SYNOPSIS
.nf
.na
\f4#include <sys/map.h>
\f4#include <sys/ddi.h>
.sp 0.5
unsigned long rmalloc(struct map *\f2mp, \f4long \f2size\f4);\f1
.ad
.fi
.SH ARGUMENTS
.RS 0n 10
.IP "\f2mp\f1" 10n
Memory map from where the resource is drawn.
.IP "\f2size\f1" 10n
Number of units of the resource.
.RE
.SH DESCRIPTION
\f4rmalloc\f1 is used by a driver to allocate space from a previously
defined and initialized private space management map.  The map itself is
declared as a structure using the driver prefix in the form
\f2prefix\f1\f4map\f1.  Memory is initially allocated for the map
either by a data array, or by the \f4kmem_alloc\f1(D3DK) function.
\f4rmalloc\f1 is one of five functions used for private map
management.  The other functions include   
.P
.RS 4n
.PD 0
.TP 14
\f4rmfree\f1
Return previously allocated space to a map.
.TP
\f4rminit\f1
Define a map structure and initialize a map table.
.TP
\f4rmwant\f1
Return the number of processes waiting for free space.
.TP
\f4rmsetwant\f1
Increment the count of the number of processes
waiting for free space in the map.
.PD
.RE
.P
The \f4rmalloc\f1 function allocates space from a memory map in terms
of arbitrary units.  The system maintains the \f4map\f1 structure by
size and index, computed in units appropriate for the memory map.
For example, units may be byte addresses, pages of memory, or blocks.
The elements of the memory map are sorted by index, and the system uses
the \f2size\f1 member to combine adjacent objects into one memory map
entry.  The system allocates objects from the memory map on a first-fit
basis.  The normal return value is an unsigned long set to the value of 
\f4m_addr\f1 from the \f4map\f1 structure.
.SH RETURN VALUE
Under normal conditions, \f4rmalloc\f1 returns the base of the
allocated space.  Otherwise, \f4rmalloc\f1 function
returns a \f40\f1 if all memory map entries are already allocated.
.SH LEVEL
Base
.P
Interrupt if \f4rmwant\f1 is not set
.SH SEE ALSO
\f2BCI Driver Development Guide\f1, Chapter 6, ``Input/Output Operations''
.P
.na
\f4dma_pageio\f1(D3D),
\f4rminit\f1(D3DK),
\f4rmwant\f1(D3DK),
\f4rmfree\f1(D3DK)
.ad
.SH EXAMPLE
The following example is a simple memory map, but it illustrates
the principles of map management.  A driver initializes the map table by
calling both the \f4rminit\f1(D3DK) and \f4rmfree\f1(D3DK) functions.
\f4rminit\f1(D3DK) establishes the number of slots or entries in the
map, and \f4rmfree\f1 to initialize the total buffer area the map is
to manage.  The following example is a fragment from a hypothetical
\f4start\f1 routine and illustrates the following procedures:
.IP
Declaration of the map structure (line 4).  The defined map array must
be initialized to zero before calling \f4rminit\f1.
.IP
The use of \f4kmem_alloc\f1(D3DK) to allocate memory for the map.  This
example panics the system if the required amount of memory can not be
allocated (lines 10\-14).
.IP
The use of \f4mapinit\f1 to configure the total number of entries in
the map, and of \f4rmfree\f1 to configure the total buffer area.
.ne 4
.P
.nf
.ft 4
.ps 7
1   #define XX_MAPSIZE    12
2   #define XX_BUFSIZE  2560
3
4   struct map  xx_map[XX_MAPSIZE]; /* Space management map for */
5                                   /*   a private buffer       */
    ...
6   xx_start()
7        /*
8         *  Allocate private buffer.  If insufficient memory, 
9         *  display message and halt system.
10        */
11  {
12      register caddr_t bp;

13      if ((bp = kmem_alloc(XX_BUFSIZE, KM_NOSLEEP) == 0)  { 
14  
15          cmn_err(CE_PANIC, "xx_start: kmem_alloc failed before %d buffer
                    allocation", XX_BUFSIZE);
16      } /* endif */
17       /*  
18        * Initialize space management map with number 
19        * of slots in map.
20        */
21  rminit(xx_map, XX_MAPSIZE);
22       /*
23        * Initialize space management map with total 
24        * buffer area it is to manage.
25        */
26  rmfree(xx_map, XX_BUFSIZE, bp);
    \&...
.ps
.ft 1
.fi
.P
.FG "Initializing the map structure"
.P
The \f4rmalloc\f1(D3DK) function is then used by the driver's \f4read\f1 or
\f4write\f1 routine to allocate buffers for specific data transfers.
If the appropriate space cannot be allocated, the \f4rmsetwant\f1(D3DK)
function is used to wait for a free buffer and the process is put to
sleep until a buffer is available.  When a buffer becomes available,
the \f4rmfree\f1(D3DK) function is called to return the buffer to
the map and to wake the sleeping process (no \f4wakeup\f1(D3DK) call
is required).  The \f4uiomove\f1(D3DK) function is used to move the
data between user space and local\p
.br
.ne .5i
driver memory.  The device then moves
data between itself and local driver memory through \s-1DMA\s0.
.P
The next example illustrates the following procedures:
.IP
The size of the I/O request is calculated and stored in the \f4size\f1
variable 
(lines 14\-15).
.IP
While buffers are available, buffers are allocated through the
\f4rmalloc\f1 function using the \f4size\f1 value (line 25).
.IP
If there are not enough buffers free for use, the
\f4rmsetwant\f1(D3DK) function is called, and the process is put to
sleep (lines 26\-28).  When a buffer becomes available, the
\f4rmfree\f1(D3DK) function returns the buffer to the map and wakes
the process. 
.IP
The \f4uiomove\f1(D3DK) function is used to move data to the
allocated buffer (line 35).
.IP
If the address passed to the \f4uiomove\f1 function is invalid, the
\f4rmfree\f1 function is called to release the previously allocated
buffer, and an \f4EFAULT\f1 error is returned.
.IX "\f4rmalloc\fP(D3DK), example"
.IX "\f4rmsetwant\fP(D3DK), example"
.ne 4
.P
.nf
.ft 4
.ps 7
1   #define XX_MAPPRIO (PZERO + 6)
2   #define XX_MAPSIZE    12
3   #define XX_BUFSIZE  2560
4   #define XX_MAXSIZE  (XX_BUFSIZE / 4)
5
6   struct map  xx_map[XX_MAPSIZE];         /* Private buffer space map */
7          char xx_buffer[XX_BUFSIZE];        /* driver xx_ buffer area */
    ...
8   read(dev, uio_p, cred_p)
9       dev_t   dev;
10      uio_t   uio_p;         /* Pointer to uio structure for I/O */
11      cred_t  cred_p;
12
13  register caddr_t addr;
14  register int     size;
15      size = min(COUNT, XX_MAXSIZE);  /* Break large I/O request */
16                                                   /* into small ones */
17       /*
18        * Get buffer.  If space is not available, then 
19        * request a wakeup when space is returned. Wait 
20        * for space; rmfree will check rmsetwant and 
21        * supply the wakeup call.
22        */
23      oldlevel = spl4();
24
25      while((addr = (caddr_t)rmalloc(xx_map, size)) == NULL) {  
26          rmsetwant(xx_map)
27          sleep(xx_map, XX_MAXPRIO);
28      } /* endwhile */
29      splx(oldlevel);
30
31       /*
32        * Move data to buffer.  If invalid address is found,
33        * return buffer to map and return error code.
34        */
35      if (uiomove(addr, size, UIO_READ, uio_p) == -1)  {
36          oldlevel = spl4();
37          rmfree(xx_map, size, addr);
38          splx(oldlevel);
39          return(EFAULT);
40      } /* endif */
.ps
.ft 1
.fi
.P
.FG "Allocating memory from a memory map"
