LWN.net Logo

 


 
Summary page
Return to the Kernel page
 
Recent Features

LWN.net Weekly Edition for March 18, 2004

LWN.net Weekly Edition for March 11, 2004

The annotated SCO stock price chart

A grumpy editor's calendar search

LWN.net Weekly Edition for March 4, 2004

Printable page
 

 

Driver porting: DMA changes

This article is part of the LWN Porting Drivers to 2.6 series.
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

Copyright (©) 2003, Eklektix, Inc.
Linux (®) is a registered trademark of Linus Torvalds
Powered by Rackspace Managed Hosting.