|
|
#include <sys/types.h> #include <sys/map.h> #include <sys/ddi.h>ulong_t rmalloc(struct map *mp, size_t size);
On systems where the rmallocmap function is available, the map must have been allocated by a call to rmallocmap(D3) and the space managed by the map must have been added using rmfree(D3) prior to the first call to rmalloc for the map.
On systems where the rmallocmap function is not available, the map must be initially allocated either as a data array, or by the kmem_alloc(D3) function. The map must have been initialized by a call to rminit(D3) and the space managed by the map must have been added using rmfree(D3) prior to the first call to rmalloc for the map.
size specifies the amount of space to allocate and is in arbitrary units. The driver using the map places whatever semantics on the units are appropriate for the type of space being managed. For example, units may be byte addresses, pages of memory, or blocks on a device.
The system allocates space from the memory map on a first-fit basis and coalesces adjacent space fragments when space is returned to the map by rmfree.
In the driver's read(D2) and write(D2) routines, we use rmalloc to allocate buffers for data transfer. This example illustrates the write routine. Assuming the device can only transfer XX_MAXBUFSZ bytes at a time, we calculate the amount of data to copy (line 22) and use rmalloc to allocate some space from the map. The call to rmalloc is protected against interrupts (line 23) from the device that may result in freeing map space. This way, if space is freed, we won't miss the corresponding wakeup(D3).
If the appropriate space cannot be allocated, we use rmsetwant(D3) to indicate that we want space (line 25) and then we sleep until a buffer is available. When a buffer becomes available, rmfree is called to return the space to the map and to wake the sleeping process. Then the call to rmalloc will succeed and the driver can then transfer data.
1 #define XX_MAPSIZE 35 2 #define XX_MEMSIZE (16*1024) 3 #define XX_MAXBUFSZ 10244 struct map xx_map[XX_MAPSIZE]; ... 5 xx_start() 6 { 7 caddr_t bp;
8 if ((bp = kmem_alloc(XX_MEMSIZE, KM_NOSLEEP)) == 0) 9 cmn_err(CE_WARN, "xx_start: could not allocate %d bytes", XX_MEMSIZE); 10 rminit(xx_map, XX_MAPSIZE); 11 rmfree(xx_map, XX_MEMSIZE, bp); 12 } ... 13 xx_write(dev, uiop, crp) 14 dev_t dev; 15 uio_t *uiop; 16 cred_t *crp; 17 { 18 caddr_t addr; 19 size_t size; 20 int s; ... 21 while (uiop->uio_resid > 0) { 22 size = min(uiop->uio_resid, XX_MAXBUFSZ); 23 s = spl4(); 24 while ((addr = (caddr_t)rmalloc(xx_map, size)) == NULL) { 25 rmsetwant(xx_map); 26 sleep((caddr_t)xx_map, PZERO); 27 } 28 splx(s); ... 29 } ...
On systems where the rmallocmap function is available, line 4 could become:
struct map *xx_map;and line 10 could become:
if ((mp=rmallocmap(xx_MAPSIZE) == 0 cmn_err (CE_WARN, "xx_start: could not allocate map");