The direct memory access (DMA) support layer has been extensively changed
in 2.6, but, in many cases, device drivers should work unaltered. For
developers working on new drivers, or for those wanting to keep their code
current with the latest API, there are a fair number of changes to be aware
of.
The most evident change is the creation of the new generic DMA layer. Most
driver programmers will be aware of the pci_* DMA support
functions; SPARC programmers may have also encountered the analogous set of
sbus_* functions. Starting with 2.5.53, a new set of generic DMA
functions was added which is intended to provide a DMA support API that is
not specific to any particular bus. The new functions look much like the
old ones; changing from one API to the other is a fairly automatic job.
The discussion below will note changes in the DMA API without looking at
every new dma_* function. See our DMA API quick reference
page for a concise summary of the mapping from the old PCI interface to
the new generic functions.
Allocating DMA regions
The new and old DMA APIs both distinguish between "consistent" (or
"coherent") and "streaming" memory. Consistent memory is guaranteed to
look the same to the processor and to DMA-capable devices, without problems
caused by caching; it is most often used for long-lasting, bidirectional
I/O buffers. Streaming memory may have cache effects, and is generally
used for a single transfer.
The PCI functions for allocating consistent memory are unchanged from 2.4:
void *pci_alloc_consistent(struct pci_dev *dev, size_t size,
dma_addr_t *dma_handle);
void pci_free_consistent(struct pci_dev *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
The generic version is a little different, adopting the term "coherent" for
this type of memory, and adding an allocation flag:
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, int flag);
void dma_free_coherent(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
Here the added flag argument is the usual memory allocation flag.
pci_alloc_consistent() is deemed to have an implicit
GFP_ATOMIC flag.
For single-buffer streaming allocations, the PCI interface is, once again,
unchanged, and the generic DMA interface is isomorphic to the PCI version.
There is now an enumerated type for describing the direction of the
mapping:
enum dma_data_direction {
DMA_BIDIRECTIONAL = 0,
DMA_TO_DEVICE = 1,
DMA_FROM_DEVICE = 2,
DMA_NONE = 3,
};
The actual mapping and unmapping functions are:
dma_addr_t dma_map_single(struct device *dev, void *addr,
size_t size,
enum dma_data_direction direction);
void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
size_t size,
enum dma_data_direction direction);
dma_addr_t dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction direction);
void dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
size_t size,
enum dma_data_direction direction);
As is the case with the PCI versions of these functions, use of the
offset and size parameters is discouraged unless you
really know what you are doing.
There has been one significant change in the creation of scatter/gather
streaming DMA mappings. The 2.4 version of struct scatterlist
used a char * pointer (called address) for the
buffer to be mapped, with a
struct page pointer that would be used only for high memory
addresses. In 2.6, the address pointer is gone, and all
scatterlists must be built using struct page pointers.
The generic versions of the scatter/gather functions are:
int dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction direction);
void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int nhwentries, enum dma_data_direction direction);
Noncoherent DMA mappings
The generic DMA layer in 2.6 includes a set of functions for the creation
of explicitly noncoherent mappings. Very few drivers will need to use this
interface; it is mostly intended for code that must work on older platforms
that are unable to create coherent mappings. Note that there are no PCI
equivalents for these functions; you must use the generic variants.
A noncoherent mapping is created with:
void *dma_alloc_noncoherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, int flag);
This function behaves identically to dma_alloc_coherent(), except
that the returned mapping might not be in coherent memory. Drivers using
this memory must be careful to follow the ownership rules and call the
appropriate dma_sync_* functions when needed. An additional
function:
void dma_sync_single_range(struct device *dev, dma_addr_t dma_handle,
unsigned long offset, size_t size,
enum dma_data_direction direction);
Will synchronize only a portion of a (larger) noncoherent mapping.
When your driver is done with the mapping, it should be returned to the
system with:
void dma_free_noncoherent(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
Double address cycle addressing
The PCI bus is capable of a "double address cycle" (DAC) mode of
operation. DAC enables the use of 64-bit DMA addresses, greatly expanding
the range of memory which is reachable on systems without I/O memory
mapping units. DAC is also expensive, however, and is not properly
supported by all devices and buses. So the DMA support routines will
normally go out of their way to avoid creating mappings that require DAC -
even when the driver has set an address mask that would allow it.
There are occasions where DAC is useful, however. In particular, very
large DMA mappings may not be possible in the normal, single-cycle address
range. For these rare cases, the PCI layer (but not the generic DMA layer)
provides a special set of functions. Note that the DAC functions can be
very expensive to use; they should generally be avoided unless absolutely
necessary. These functions aren't strictly a 2.6 feature; they were also
added to 2.4.13.
A DAC-capable driver must begin by setting a separate address mask:
int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
The mask describes the address range that your device can
support. If the function returns non-zero, DAC addressing cannot be used
and should not be attempted.
A DAC mapping is created with:
dma64_addr_t pci_dac_page_to_dma(struct pci_dev *dev,
struct page *page,
unsigned long offset,
int direction);
There's a few things to note about DAC mappings. They can only be created
using struct page pointers and offsets; DAC mappings, by their
nature, will be in high memory and thus will not have kernel virtual
addresses. DAC mappings are a straight address translation requiring no
external resources, so there is no need to explicitly unmap them after
use. Finally, all DAC mappings are inconsistent (noncoherent) mappings, so
explicit synchronization is needed to ensure that the device and CPU see
the same memory. For a DAC mapping, use:
void pci_dac_dma_sync_single(struct pci_dev *dev,
dma64_addr_t dma_addr,
size_t len, int direction);
Some other details
On many architectures, no resources are consumed by DMA mappings, and thus
there is no real need to unmap them. The various unmap functions are set
up as no-ops on those architectures, but some programmers evidently dislike
the need to remember DMA mapping addresses and lengths unnecessarily. So
2.6 (and 2.4 as of 2.4.18) has a fairly elaborate bit of preprocessor abuse
which can be used to save a couple words of memory. See
Documentation/DMA-mapping.txt in
the source tree if this appeals to you.
The "PCI pool" interface is definitely not a 2.5-specific feature, since it
first appeared in 2.4.4. That is new enough, however, that some references
(i.e. Linux Device Drivers, Second Edition) do not cover them. The
PCI pool interface enables the use of very small DMA buffers. In the past,
such buffers would often be kept in device-specific structures. Some users
ran into trouble, however, when the DMA buffer shared a cache line with
other members of the same structure. The PCI pool interface was created to
help move tiny DMA buffers into their own space and avoid this sort of
memory corruption. Again, see DMA-mapping.txt for the details. No comments have been posted.
Post one now
|