Using the dio Structure
A device driver can use the dio structure in many ways.
- Pass a list of virtual addresses and lengths of buffers to the d_map_list and d_map_slave services.
- Receive the resulting list of bus addresses (d_map_list only)
for use by the device in the data transfer. Note: The driver does not need a dio bus list for calls to d_map_slave because the address generation for slaves is hidden.
Typically, a device driver provides a dio structure that contains only one virtual buffer and one length in the list. If the virtual buffer length spans many pages, the bus address list contains multiple entries that reflect the physical locations of the virtually contiguous buffer. The driver can provide multiple virtual buffers in the virtual list. The driver can then place many buffer requests in one I/O operation.
sys/dma.h header file. The driver must have
at least two dio structures. One is needed
for passing in the virtual list. Another is needed to accept the resulting
bus list. The driver can have many dio lists
if it plans to have multiple outstanding I/O commands to its device.
The length of each list is dependent on the use of the device and
driver. The virtual list needs as many elements as the device could
place in one operation at the same time. A formula for estimating
how many elements the bus address list needs is the sum of each of
the virtual buffers lengths divided by page size plus 2. Or,
sum [i=0 to n] ((vlist[i].length / PSIZE) + 2).
This formula handles a worst-case situation. For a contiguous
virtual buffer that spans multiple pages, each physical page is discontiguous,
and neither the starting nor ending addresses are page-aligned.If the d_map_list service runs out of space when filling in the dio bus list, a DMA_DIOFULL error is returned to the device driver and the bytes_done field of the dio virtual list is set to the number of bytes successfully mapped in the bus list. This byte count is guaranteed to be a multiple of the minxfer field provided to the d_map_list or d_map_slave services. Also, the resid_iov field of the virtual list is set to the index of the first d_iovec entry that represents the remainder of iovecs that could not be mapped.
- Initiate a partial transfer on its device and leave the remainder
on its device queue.
If the driver chooses not to initiate the partial transfer, it must still make a call to d_unmap_list to undo the partial mapping.
- Make another call to the d_map_list with new dio lists for the remainder and setup its device for the full transfer that was originally intended.
If d_map_list or d_map_slave encounter an access violation on a page within the virtual list, then a DMA_NOACC error is returned to the device driver and the bytes_done field of the dio virtual list is set to the number of bytes that preceded the faulting iovec. In this case, the resid_iov field is set to the index of the d_iovec entry that encountered the violation. From this information, the driver can determine which virtual buffer contained the faulting page and fail that request back to the originator.
- Initiate a partial transfer on its device and leave the remainder on its device queue
If the driver chooses not to initiate the partial transfer, it still must make a call to d_unmap_list or d_unmap_slave (for slaves) to undo the partial mapping.
- Choose to leave the entire request on its device queue and wait for resources to free up (for example, after a device interrupt from a previous operation).