Writing Device Drivers

DMA Changes

In the SunOS 4.1 system, to do a DMA transfer the driver mapped a buffer into the DMA space, retrieved the DMA address and programed the device, did the transfer, and freed the mapping. This was accomplished in this sequence:

  1. mb_mapalloc()( ) - Map buffer into DMA space

  2. MBI_ADDR()( ) - Retrieve address from returned cookie

  3. Program the device and start the DMA

  4. mb_mapfree()( ) - Free mapping when DMA is complete

The first three usually occurred in a start()( ) routine, and the last in the interrupt routine.

The SunOS 5.7 DMA model is similar, but it has been extended. The goal of the new DMA model is to abstract the platform-dependent details of DMA away from the driver. A sliding DMA window has been added for drivers that need to do DMA to large objects, and the DMA routines can be informed of device limitations (such as 24-bit addressing).

The sequence for DMA is as follows: The driver allocates a DMA handle using ddi_dma_alloc_handle(9F). The DMA handle can be reused for subsequent DMA transfers. Then the driver commits DMA resources using either ddi_dma_buf_bind_handle(9F) or ddi_dma_addr_bind_handle(9F), retrieves the DMA address from the DMA cookie to do the DMA, and frees the mapping with ddi_dma_unbind_handle(9F). The new sequence is something like this:

  1. ddi_dma_alloc_handle(9F) - Allocate a DMA handle

  2. ddi_dma_buf_bind_handle(9F) - Allocate DMA resources and retrieve address from the returned cookie

  3. Program the device and start the DMA

  4. Perform the transfer.

Note -

If the transfer involves several windows, you can call ddi_dma_getwin(9F) to move to subsequent windows.

  1. ddi_dma_unbind_handle(9F) - Free mapping when DMA is complete

  2. ddi_dma_free_handle(9F) - Free DMA handle when no longer needed

Additional routines have been added to synchronize any underlying caches and buffers, and handle IOPB memory. See Chapter 7, DMA, for details.

In addition, in the SunOS 4.1 system, the driver had to inform the system that it might do DMA, either through the mb_driver structure or with a call to adddma()( ). This was needed because the kernel might need to block interrupts to prevent DMA, but needed to know the highest interrupt level to block. Because the new implementation uses mutexes, this is no longer needed.