patch-2.4.4 linux/Documentation/DMA-mapping.txt
Next file: linux/Documentation/DocBook/Makefile
Previous file: linux/Documentation/Configure.help
Back to the patch index
Back to the overall index
- Lines: 137
- Date:
Thu Apr 19 08:38:48 2001
- Orig file:
v2.4.3/linux/Documentation/DMA-mapping.txt
- Orig date:
Tue Mar 6 22:44:15 2001
diff -u --recursive --new-file v2.4.3/linux/Documentation/DMA-mapping.txt linux/Documentation/DMA-mapping.txt
@@ -32,6 +32,35 @@
the dma_addr_t type which should be used everywhere you hold a DMA
(bus) address returned from the DMA mapping functions.
+ What memory is DMA'able?
+
+The first piece of information you must know is what kernel memory can
+be used with the DMA mapping facilitites. There has been an unwritten
+set of rules regarding this, and this text is an attempt to finally
+write them down.
+
+If you acquired your memory via the page allocator
+(i.e. __get_free_page*()) or the generic memory allocators
+(i.e. kmalloc() or kmem_cache_alloc()) then you may DMA to/from
+that memory using the addresses returned from those routines.
+
+This means specifically that you may _not_ use the memory/addresses
+returned from vmalloc() for DMA. It is possible to DMA to the
+_underlying_ memory mapped into a vmalloc() area, but this requires
+walking page tables to get the physical addresses, and then
+translating each of those pages back to a kernel address using
+something like __va().
+
+This rule also means that you may not use kernel image addresses
+(ie. items in the kernel's data/text/bss segment, or your driver's)
+nor may you use kernel stack addresses for DMA. Both of these items
+might be mapped somewhere entirely different than the rest of physical
+memory.
+
+What about block I/O and networking buffers? The block I/O and
+networking subsystems make sure that the buffers they use are valid
+for you to DMA from/to.
+
DMA addressing limitations
Does your device have any DMA addressing limitations? For example, is
@@ -168,16 +197,21 @@
optimizations the hardware allows. To this end, when using
such mappings you must be explicit about what you want to happen.
+Neither type of DMA mapping has alignment restrictions that come
+from PCI, although some devices may have such restrictions.
+
Using Consistent DMA mappings.
-To allocate and map a consistent DMA region, you should do:
+To allocate and map large (PAGE_SIZE or so) consistent DMA regions,
+you should do:
dma_addr_t dma_handle;
cpu_addr = pci_alloc_consistent(dev, size, &dma_handle);
where dev is a struct pci_dev *. You should pass NULL for PCI like buses
-where devices don't have struct pci_dev (like ISA, EISA).
+where devices don't have struct pci_dev (like ISA, EISA). This may be
+called in interrupt context.
This argument is needed because the DMA translations may be bus
specific (and often is private to the bus which the device is attached
@@ -186,7 +220,9 @@
Size is the length of the region you want to allocate.
This routine will allocate RAM for that region, so it acts similarly to
-__get_free_pages (but takes size instead of a page order).
+__get_free_pages (but takes size instead of a page order). If your
+driver needs regions sized smaller than a page, you may prefer using
+the pci_pool interface, described below.
It returns two values: the virtual address which you can use to access
it from the CPU and dma_handle which you pass to the card.
@@ -205,6 +241,51 @@
where dev, size are the same as in the above call and cpu_addr and
dma_handle are the values pci_alloc_consistent returned to you.
+If your driver needs lots of smaller memory regions, you can write
+custom code to subdivide pages returned by pci_alloc_consistent,
+or you can use the pci_pool API to do that. A pci_pool is like
+a kmem_cache, but it uses pci_alloc_consistent not __get_free_pages.
+Also, it understands common hardware constraints for alignment,
+like queue heads needing to be aligned on N byte boundaries.
+
+Create a pci_pool like this:
+
+ struct pci_pool *pool;
+
+ pool = pci_pool_create(name, dev, size, align, alloc, flags);
+
+The "name" is for diagnostics (like a kmem_cache name); dev and size
+are as above. The device's hardware alignment requirement for this
+type of data is "align" (a power of two). The flags are SLAB_ flags
+as you'd pass to kmem_cache_create. Not all flags are understood, but
+SLAB_POISON may help you find driver bugs. If you call this in a non-
+sleeping context (f.e. in_interrupt is true or while holding SMP
+locks), pass SLAB_ATOMIC. If your device has no boundary crossing
+restrictions, pass 0 for alloc; passing 4096 says memory allocated
+from this pool must not cross 4KByte boundaries.
+
+Allocate memory from a pci pool like this:
+
+ cpu_addr = pci_pool_alloc(pool, flags, &dma_handle);
+
+flags are SLAB_KERNEL if blocking is permitted (not in_interrupt nor
+holding SMP locks), SLAB_ATOMIC otherwise. Like pci_alloc_consistent,
+this returns two values, cpu_addr and dma_handle,
+
+Free memory that was allocated from a pci_pool like this:
+
+ pci_pool_free(pool, cpu_addr, dma_handle);
+
+where pool is what you passed to pci_pool_alloc, and cpu_addr and
+dma_handle are the values pci_pool_alloc returned.
+
+Destroy a pci_pool by calling:
+
+ pci_pool_destroy(pool);
+
+Make sure you've called pci_pool_free for all memory allocated
+from a pool before you destroy the pool.
+
DMA Direction
The interfaces described in subsequent portions of this document
@@ -389,9 +470,10 @@
longer, nor should they use bus_to_virt. Some drivers have to be changed a
little bit, because there is no longer an equivalent to bus_to_virt in the
dynamic DMA mapping scheme - you have to always store the DMA addresses
-returned by the pci_alloc_consistent and pci_map_single calls (pci_map_sg
-stores them in the scatterlist itself if the platform supports dynamic DMA
-mapping in hardware) in your driver structures and/or in the card registers.
+returned by the pci_alloc_consistent, pci_pool_alloc, and pci_map_single
+calls (pci_map_sg stores them in the scatterlist itself if the platform
+supports dynamic DMA mapping in hardware) in your driver structures and/or
+in the card registers.
This document, and the API itself, would not be in it's current
form without the feedback and suggestions from numerous individuals.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)