Specifications

D
evice Driver Programming
12-2
system loads it from disk back into RAM. This activity is not under the control of the user
and may happen at any time. Memory must not be swapped out when DMA is occurring to
it for obvious reasons.
Block device drivers, which contain a strategy() entry point, do not need to worry
about this issue because the memory defined by the buf header is already locked down
when the strategy() routine is called. However, if the driver uses a character interface,
or if it performs DMA as a result of ioctl() calls, then the driver must handle the
locking of memory.
The current release does not provide a generally available routine to perform memory
locking. One alternative is to make use of the routine physiock(D3), which is designed
for use within block device drivers. This routine is frequently used in the character
read()/write() routines of a block/character device driver to convert a character I/O
request into a block I/O request, which is then delivered to the driver's strategy() rou-
tine. The physiock() routine locks down the user's buffers so that DMA operations
may take place.
A character driver may make use of this routine to call a pseudo-strategy() routine in
much the same fashion. To do this, the driver must allocate and populate a uio(D4)
structure, and an associated iovec(D4) structure. These structures are used to describe
the virtual buffer to physiock(). The uio structure is passed to physiock() along
with a function pointer that identifies your pseudo-strategy routine.
NOTE
There are two versions of physiock(), one utilized by large
offset drivers and one utilized by small offset drivers. The selec-
tions is automatically made at compile time (that is, drivers sim-
ply invoke physiock() and compile time options take care of
pointing the name physiock to the correct version).
The physiock() routine will allocate a buf(D4) header and populate it. It will also
lock down the virtual memory described by the uio structure. It will then call your
pseudo-strategy() routine, passing a pointer to the buf header as the only argument.
Your pseudo-strategy() routine should pull out the virtual address and byte count
from the buf header and queue the I/O as usual. When your pseudo-strategy()
routine returns to physiock(), it will go to sleep on an event associated with the buf
header.
When the I/O completes, you must call biodone(D3) to notify physiock() that the
I/O has completed. The biodone() routine takes the address of the buf header as its
only argument. Once biodone() has been called, the sleeping context will wake up, and
physiock() will return to your driver.
DMA into Discontiguous Physical Memory 12
Another factor to be considered is physically discontiguous transfers. While the virtual
address space assigned to a buffer will be contiguous, it may be made up of discontiguous