Using the dio Structure

A device driver can use the dio structure in many ways.

It can be used to:
  • 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.

The device driver is responsible for allocating the storage for all the dio lists it needs. For more information, see the DIO_INIT and DIO_FREE macros in the 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.

The device driver can:
  • 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.

Note: If the DMA_NOACC error is returned, the bytes_done count is not guaranteed to be a multiple of the minxfer field provided to the d_map_list or d_map_slave services, and no partial mapping is done. For slaves, setup of the address generation hardware is not done. For masters, the bus list is undefined. If the driver desires a partial transfer, it must make another call to the mapping service with the dio list adjusted to not include the faulting buffer.
If either the d_map_list or d_map_slave services run out of resources when mapping a transfer, a DMA_NORES error is returned to the device driver. In this case, the bytes_done field of the dio virtual list is set to the number of bytes that were 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 of the remaining iovecs that could not be mapped. The device driver can:
  • 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).
Note: If the DMA_ENABLE_64 flag is indicated on the d_map_init call or the d_map_init_ext call, the programming model is the same with one exception. The dio_64 and d_iovec_64 structures are used in addition to 64-bit address fields on d_map_page and d_unmap_page calls.