Yesterday i talked a little about "what DMA is". Today i want to talk a little bit about how devices use DMA)
DMA to a Driver
From the driver's point of view there are two aspects to DMA. The first is how you prepare your data for DMA transfers. The second is how you program the device to initiate the transfers & how you notice that a transfer is done. Let's talk about the second part first.
There are an infinite number of models for programming your device to start a DMA. Each introduces its own limitations. I'll go over a few of the common ones i've seen:
- The device takes a single physical address base and a length for an operation. This is very simple to program, but requres the transfer to be physically contiguous, which is unlikely for anything other than the smallest transfers (physical memory is often very fragmented, so the chance of two adjoining virtual pages using adjoining physical pages is pretty small). The device will usually interrupt when the DMA transfer is complete.
- The device takes a single physical address base & a length for each fragment of an operation. It interrupts when it's done transferring each fragment, allowing your driver to program in the next one. This is going to be slow because of the latency between each fragment, but is still easy to implement.
- The device takes a sequence of (physical-address, length) pairs which describe all the fragments of the transfer. This sequence is called a "scatter-gather list" (SG List). The device can then transfer each fragment on its own without the need to interrupt the CPU until all sections are done. In the simplest version of this, the driver programs the SG list to the controller through its registers/ports - writing each element into the device's internal memory. The device will only have a limited space for the SG list, so you may only be able to handle 16 fragments in a given transfer.
- In the more complex version of 3, the SG list itself is stored in DMA accessible system memory and the device is programmed with the physical address and length of the scatter-gather list itself. The device can then use DMA to transfer the SG list entries into its own internal buffers. This can reduce the limitations on the length of the SG list, but requires more complex logic in the DMA controller to handle it. However this would require the memory holding the SG list to be physically contiguous.
All of these models have the same basic characteristics. You tell the controller one or more physical address ranges from/to which to transfer data & you tell it to start transferring data. Some time in the future the transfer finishes and your driver finds out about it somehow. Hopefully this "somehow" is through an interrupt but it might also involve polling. The problem with polling is that you are, once again, wasting a very expensive CPU doing something mundane - in this case spinning and waiting on a bit in a register.
Next time i'll talk some about how you get those physical address ranges in the first place.