DMA in linux journal



       Dynamic DMA mapping Guide动态DMA映射
       =========================

   David S. Miller <davem@redhat.com>
   Richard Henderson <rth@cygnus.com>
    Jakub Jelinek <jakub@redhat.com>

This is a guide to device driver writers on how to use the DMA API
with example pseudo-code.  For a concise description of the API, see
DMA-API.txt.
这是用伪代码示例的如何使用DMA API的文章。参看DMA-API,可以获得API的简单描述。

                       CPU and DMA addresses
        CPU 和 DMA 地址

There are several kinds of addresses involved in the DMA API, and it's
important to understand the differences.
在DMA API函数中有几种地址。理解这几种地址的区别,对理解DMA API函数很重要。

The kernel normally uses virtual addresses.  Any address returned by
kmalloc(), vmalloc(), and similar interfaces is a virtual address and can
be stored in a "void *".
内核通常使用虚拟地址。kmalloc和vmalloc等函数返回的地址是虚拟地址,通常是void *类型。

The virtual memory system (TLB, page tables, etc.) translates virtual
addresses to CPU physical addresses, which are stored as "phys_addr_t" or
"resource_size_t".  The kernel manages device resources like registers as
physical addresses.  These are the addresses in /proc/iomem.  The physical
address is not directly useful to a driver; it must use ioremap() to map
the space and produce a virtual address.
虚拟地址系统(TLB, 页表等)把虚拟地址转换为物理地址,通常是phys_addr_t或resource_size_t类型。
内核用物理地址管理寄存器等设备资源。物理地址在/proc/iomem文件中可以找到。驱动程序不能直接
使用物理地址,驱动程序必须使用ioremap函数来映射物理地址空间,产生一个虚拟地址。

I/O devices use a third kind of address: a "bus address".  If a device has
registers at an MMIO address, or if it performs DMA to read or write system
memory, the addresses used by the device are bus addresses.  In some
systems, bus addresses are identical to CPU physical addresses, but in
general they are not.  IOMMUs and host bridges can produce arbitrary
mappings between physical and bus addresses.
I/O设备使用另外一种地址,总线地址。如果设备在MMIO地址有寄存器,或者如果设备执行DMA来读
取或者写入主机系统内存,这时设备使用的地址就是总线地址。在一些系统中,总线地址就是物理地
址,但总的来讲,总线地址并不总是物理地址。IOMMUs和主机桥能在物理和总线地址生成强制映射。

From a device's point of view, DMA uses the bus address space, but it may
be restricted to a subset of that space.  For example, even if a system
supports 64-bit addresses for main memory and PCI BARs, it may use an IOMMU
so devices only need to use 32-bit DMA addresses.
对于设备来说,DMA使用总线地址空间,设备只限制在这个总线地址空间的一个子集。例如,即使系
统支持64位的物理内存地址和PCI BARs, 系统只使用一个IOMMU,因此设备只使用32位的DMA地址。

Here's a picture and some examples:
下面是一个图和一些例子。


               CPU                  CPU                  Bus
             Virtual              Physical             Address
             Address              Address               Space
              Space                Space

            +-------+             +------+             +------+
            |       |             |MMIO  |   Offset    |      |
            |       |  Virtual    |Space |   applied   |      |
          C +-------+ --------> B +------+ ----------> +------+ A
            |       |  mapping    |      |   by host   |      |
  +-----+   |       |             |      |   bridge    |      |   +--------+
  |     |   |       |             +------+             |      |   |        |
  | CPU |   |       |             | RAM  |             |      |   | Device |
  |     |   |       |             |      |             |      |   |        |
  +-----+   +-------+             +------+             +------+   +--------+
            |       |  Virtual    |Buffer|   Mapping   |      |
          X +-------+ --------> Y +------+ <---------- +------+ Z
            |       |  mapping    | RAM  |   by IOMMU
            |       |             |      |
            |       |             |      |
            +-------+             +------+

During the enumeration process, the kernel learns about I/O devices and
their MMIO space and the host bridges that connect them to the system.  For
example, if a PCI device has a BAR, the kernel reads the bus address (A)
from the BAR and converts it to a CPU physical address (B).  The address B
is stored in a struct resource and usually exposed via /proc/iomem.  When a
driver claims a device, it typically uses ioremap() to map physical address
B at a virtual address (C).  It can then use, e.g., ioread32(C), to access
the device registers at bus address A.
在设备交互过程中,内核熟悉I/O设备和设备的MMIO地址空间,主机桥接把设备连接到系统。例如,
如果一个PCI设备有一个BAR,内核通过BAR读取总线地址A,并把总线地址A转换为CPU虚拟地址B。地址B保
存在struct resource中,并通过/proc/iomem发表出去。当驱动程序管理设备时,驱动程序通常使用ioremap函
数把物理地址B映射为虚拟地址C。最后驱动程序使用ioread32(C)等函数来访问设备中的总线地址A处的寄存器。

If the device supports DMA, the driver sets up a buffer using kmalloc() or
a similar interface, which returns a virtual address (X).  The virtual
memory system maps X to a physical address (Y) in system RAM.  The driver
can use virtual address X to access the buffer, but the device itself
cannot because DMA doesn't go through the CPU virtual memory system.
如果设备支持DMA, 驱动程序使用kmalloc等函数申请缓存,这个缓存带有虚拟地址X。虚拟内存系
统在系统内存中把虚拟地址X映射为物理地址Y。驱动程序可以使用虚拟地址X来访问缓存,但是设备
不能访问缓存,因为DMA不能通过CPU虚拟内存系统。

In some simple systems, the device can do DMA directly to physical address
Y.  But in many others, there is IOMMU hardware that translates DMA
addresses to physical addresses, e.g., it translates Z to Y.  This is part
of the reason for the DMA API: the driver can give a virtual address X to
an interface like dma_map_single(), which sets up any required IOMMU
mapping and returns the DMA address Z.  The driver then tells the device to
do DMA to Z, and the IOMMU maps it to the buffer at address Y in system
RAM.
在一些简单的系统中,设备可以直接对物理地址作DMA。但是在其它的一些系统中,IOMMU硬
件设备把DMA地址Z转换为物理地址Y。这是DMA API的一部分功能:驱动程序把虚拟地址X通过dma_map_single
等函数映射为DMA地址Z。驱动程序让设备对地址Z做DMA,然后IOMMU把地址Z映射为系统内存中的物理地址Y。

So that Linux can use the dynamic DMA mapping, it needs some help from the
drivers, namely it has to take into account that DMA addresses should be
mapped only for the time they are actually used and unmapped after the DMA
transfer.
为了Linux可以使用动态DMA映射,驱动程序需要提供一些帮助. 即驱动程序在DMA被使用
时映射DMA地址,在使用完成后, DMA映射被释放.

The following API will work of course even on platforms where no such
hardware exists.
下面的API函数在没有硬件的情况下仍然可以工作.

Note that the DMA API works with any bus independent of the underlying
microprocessor architecture. You should use the DMA API rather than the
bus-specific DMA API, i.e., use the dma_map_*() interfaces rather than the
pci_map_*() interfaces.
注意DMA API函数独立于底层的处理器架构. 应该使用DMA API函数而不是与总线相关
的DMA API函数, 例如应该使用dma_map_*函数,而不是pci_mac_*函数。

First of all, you should make sure

首先,下面的头文件应该被包含进来。

#include <linux/dma-mapping.h>

is in your driver, which provides the definition of dma_addr_t.  This type
can hold any valid DMA address for the platform and should be used
everywhere you hold a DMA address returned from the DMA mapping functions.
这个头文件提供了dma_addr_t结构。这个结构体包含了在所有平台上都合法的DMA地址。

    What memory is DMA'able? 可以做DMA的内存

The first piece of information you must know is what kernel memory can
be used with the DMA mapping facilities.  There has been an unwritten
set of rules regarding this, and this text is an attempt to finally
write them down.
首先需要了解内核中的哪些内存可以做DMA映射。本文将尽力解释这部分。

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.
如果你通过页分配器(__get_free_page)来获得内存,或者通用的内存分配函数(kmalloc或
kmem_cache_alloc).然后你就可以写入或读取数据。

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().  [ EDIT: Update this when we integrate
Gerd Knorr's generic code which does this. ]
这意味着你不能使用从vmalloc函数获得的内存/地址做DMA。对于DMA, 可以把DMA作为底下的内存影
射到vmalloc区域。这要求遍历页表来获得物理地址,然后把物理地址通过__va转换为虚拟地址,

This rule also means that you may use neither kernel image addresses
(items in data/text/bss segments), nor module image addresses, nor
stack addresses for DMA.  These could all be mapped somewhere entirely
different than the rest of physical memory.  Even if those classes of
memory could physically work with DMA, you'd need to ensure the I/O
buffers were cacheline-aligned.  Without that, you'd see cacheline
sharing problems (data corruption) on CPUs with DMA-incoherent caches.
(The CPU could write to one word, DMA would write to a different one
in the same cache line, and one of them could be overwritten.)
上面的规则,使得kerenl的影射地址(data/text/bss段中的项),模块的影射地址,栈的地址,都
不能做dma用。这些地址都能被影射到非物理地址的其它地方。即使这些内存可以配合DMA工作,
你需要保证I/O缓存是cacheline-aligned. 否则,在DMA不同步的cache的CPU上,你会遇到cacheline共
享的问题(数据被破坏)。(在同一个cache line上,CPU写入一个word,DMA写入另外
一个word。一个word会被另外一个覆盖)

Also, this means that you cannot take the return of a kmap()
call and DMA to/from that.  This is similar to vmalloc().
你也不能把kmap的返回值与DMA一起使用。这与vmalloc类似。

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.
块设备I/O与网络的缓存怎么使用DMA呢?块设备和网络子系统保证他们使用合法的DMA。


   DMA addressing limitations DMA地址限制

Does your device have any DMA addressing limitations?  For example, is
your device only capable of driving the low order 24-bits of address?
If so, you need to inform the kernel of this fact.
你的设备有DMA地址的限制吗? 例如,你的设备只能处理地址的低24位?如果有,你需要通知内核这个限制。

By default, the kernel assumes that your device can address the full
32-bits.  For a 64-bit capable device, this needs to be increased.
And for a device with limitations, as discussed in the previous
paragraph, it needs to be decreased.
内核默认你的设备能使用所有32位地址。对于64位设备,内核认为能使用64位地址。对于
有地址限制的设备,如上段所述,你需要通知内核这个限制。

Special note about PCI: PCI-X specification requires PCI-X devices to
support 64-bit addressing (DAC) for all transactions.  And at least
one platform (SGI SN2) requires 64-bit consistent allocations to
operate correctly when the IO bus is in PCI-X mode.
关于PCI设备,有特别注意的地方: PCI-X规范要求PCI-X设备支持64位地址(DAC)。当IO总
线是PCI-X设备时,至少一个平台(SGI SN2)要求64位兼容。

For correct operation, you must interrogate the kernel in your device
probe routine to see if the DMA controller on the machine can properly
support the DMA addressing limitation your device has.  It is good
style to do this even if your device holds the default setting,
because this shows that you did think about these issues wrt. your
device.
正确的操作是,在你的设备的probe函数中,你必须与内核协商,看内核是否支持你的设备
的地址空间的限制。即使你的设备没有地址限制,与内核协商也是一个很好的编程风格。因为
这显示了你确实考虑到了地址限制的问题。

The query is performed via a call to dma_set_mask_and_coherent():
协商是通过调用dma_set_mask_and_coherent函数完成。

 int dma_set_mask_and_coherent(struct device *dev, u64 mask);

which will query the mask for both streaming and coherent APIs together.
If you have some special requirements, then the following two separate
queries can be used instead:
函数dma_set_mask_and_coherent可以协商streaming和coherent的掩码。如果你有特殊的要求,下面的两个函数可以用。

 The query for streaming mappings is performed via a call to
 dma_set_mask():
streaming影射的协商通过函数dma_set_mask完成。

  int dma_set_mask(struct device *dev, u64 mask);

 The query for consistent allocations is performed via a call
 to dma_set_coherent_mask():
consistent分配的协商通过dma_set_coherent_mask完成。

  int dma_set_coherent_mask(struct device *dev, u64 mask);

Here, dev is a pointer to the device struct of your device, and mask
is a bit mask describing which bits of an address your device
supports.  It returns zero if your card can perform DMA properly on
the machine given the address mask you provided.  In general, the
device struct of your device is embedded in the bus-specific device
struct of your device.  For example, &pdev->dev is a pointer to the
device struct of a PCI device (pdev is a pointer to the PCI device
struct of your device).
dev是指向你设备的device struct的指针,mask是描述你设备支持多少地址位的位掩码。如果
你的设备的DMA与内核可以很好的工作,这个函数返回0。你设备的device struct通常嵌入在
与你设备相关的总线设备结构体中。例如,&pdev->dev是指向PCI设备的device struce的指
针(pdev是指向你设备的PCI设备结构体的指针)

If it returns non-zero, your device cannot perform DMA properly on
this platform, and attempting to do so will result in undefined
behavior.  You must either use a different mask, or not use DMA.
如果返回一个非零的数, 你的设备与这个平台不能正常使用DMA。如果你一定要用,会导致一
些意想不到的错误。你必须使用不同的掩码,或不使用DMA.

This means that in the failure case, you have three options:
对于地址空间限制,你有以下3个处理方法:

1) Use another DMA mask, if possible (see below).
使用另外的DMA掩码,见下面。
2) Use some non-DMA mode for data transfer, if possible.
使用非DMA的方式传送数据
3) Ignore this device and do not initialize it.
忽略这个设备,不再初始化它。

It is recommended that your driver print a kernel KERN_WARNING message
when you end up performing either #2 or #3.  In this manner, if a user
of your driver reports that performance is bad or that the device is not
even detected, you can ask them for the kernel messages to find out
exactly why.
推荐使用处理方法2和3。在这种处理方法下,你的驱动的用户抱怨性能差或者找不到设备,你
可以让他们看看内核的告警来查查原因。

The standard 32-bit addressing device would do something like this:
标准的32位地址设备将做下面的事情:

 if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
  dev_warn(dev, "mydev: No suitable DMA available\n");
  goto ignore_this_device;
 }

Another common scenario is a 64-bit capable device.  The approach here
is to try for 64-bit addressing, but back down to a 32-bit mask that
should not fail.  The kernel may fail the 64-bit mask not because the
platform is not capable of 64-bit addressing.  Rather, it may fail in
this case simply because 32-bit addressing is done more efficiently
than 64-bit addressing.  For example, Sparc64 PCI SAC addressing is
more efficient than DAC addressing.
另一个常见场景是64位的设备. 解决方法是先测试64位地址, 然后再使用32位掩码. 使用64位, 内
核可能会报错.这不是因为内核不支持64位, 而是32位的地址空间效率更高. 例如,
Sparc64的SAC地址空间比DAC地址空间更有效。

Here is how you would handle a 64-bit capable device which can drive
all 64-bits when accessing streaming DMA:
下面是一个如何操作64位的设备来访问streaming的DMA的例子。
 int using_dac;

 if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
  using_dac = 1;
 } else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
  using_dac = 0;
 } else {
  dev_warn(dev, "mydev: No suitable DMA available\n");
  goto ignore_this_device;
 }

If a card is capable of using 64-bit consistent allocations as well,
the case would look like this:
如果一个设备可以使用64位consistent分配,下面就是一个例子。

 int using_dac, consistent_using_dac;

 if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
  using_dac = 1;
  consistent_using_dac = 1;
 } else if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
  using_dac = 0;
  consistent_using_dac = 0;
 } else {
  dev_warn(dev, "mydev: No suitable DMA available\n");
  goto ignore_this_device;
 }

The coherent mask will always be able to set the same or a smaller mask as
the streaming mask. However for the rare case that a device driver only
uses consistent allocations, one would have to check the return value from
dma_set_coherent_mask().
coherent掩码可以比streaming掩码少,或者两者可以相同。对于很少见的只能使用consistent分配
的驱动,需要检查dma_set_coherent_mask函数的返回值。

Finally, if your device can only drive the low 24-bits of
address you might do something like:
最后,如果你的设备只能使用24位的地址,下面就是一个例子。

 if (dma_set_mask(dev, DMA_BIT_MASK(24))) {
  dev_warn(dev, "mydev: 24-bit DMA addressing not available\n");
  goto ignore_this_device;
 }

When dma_set_mask() or dma_set_mask_and_coherent() is successful, and
returns zero, the kernel saves away this mask you have provided.  The
kernel will use this information later when you make DMA mappings.
当函数dma_set_mask() 或 dma_set_mask_and_coherent()成功了, 返回值是零。内核会
保存这个掩码。当做DMA影射的时候,内核会使用这个掩码。

There is a case which we are aware of at this time, which is worth
mentioning in this documentation.  If your device supports multiple
functions (for example a sound card provides playback and record
functions) and the various different functions have _different_
DMA addressing limitations, you may wish to probe each mask and
only provide the functionality which the machine can handle.  It
is important that the last call to dma_set_mask() be for the
most specific mask.
有一个例子,必须要提一下。如果你的设备支持多个功能,例如一个声卡提供了播放和录音功
能。不同的功能有不同的DMA地址限制。你需要探测每个功能的掩码,并且将其提供给内核。
函数dma_set_mask非常重要。

Here is pseudo-code showing how this might be done:
下面是展示怎么使用的伪代码。

 #define PLAYBACK_ADDRESS_BITS DMA_BIT_MASK(32)
 #define RECORD_ADDRESS_BITS DMA_BIT_MASK(24)

 struct my_sound_card *card;
 struct device *dev;

 ...
 if (!dma_set_mask(dev, PLAYBACK_ADDRESS_BITS)) {
  card->playback_enabled = 1;
 } else {
  card->playback_enabled = 0;
  dev_warn(dev, "%s: Playback disabled due to DMA limitations\n",
         card->name);
 }
 if (!dma_set_mask(dev, RECORD_ADDRESS_BITS)) {
  card->record_enabled = 1;
 } else {
  card->record_enabled = 0;
  dev_warn(dev, "%s: Record disabled due to DMA limitations\n",
         card->name);
 }

A sound card was used as an example here because this genre of PCI
devices seems to be littered with ISA chips given a PCI front end,
and thus retaining the 16MB DMA addressing limitations of ISA.
这里使用声卡作例子,是因为PCI设备的类型被ISA芯片弄乱了。ISA芯片提供了一个PCI前段。
因此PCI保留了16M DMA地址空间的限制。这个限制是从ISA继承过来的。

   Types of DMA mappings DMA影射的类型

There are two types of DMA mappings:
有两种DMA映射:

- Consistent DMA mappings which are usually mapped at driver
  initialization, unmapped at the end and for which the hardware should
  guarantee that the device and the CPU can access the data
  in parallel and will see updates made by each other without any
  explicit software flushing.
一致DMA映射,这种映射在驱动初始化的时候建立,在驱动结束的时候删除。这种映射确保设
备和CPU可以并行访问数据,不需要任何软件干预,双方都能看到彼此作的更新。

  Think of "consistent" as "synchronous" or "coherent".
可以把一致看作,同步和连贯。

  The current default is to return consistent memory in the low 32
  bits of the DMA space.  However, for future compatibility you should
  set the consistent mask even if this default is fine for your
  driver.
当前默认的是返回DMA空间的低32位一致内存。为了兼容,你应该设置一致掩码,即使当前默认的掩码工作的非常好。

  Good examples of what to use consistent mappings for are:
下面是使用一致映射的例子:

 - Network card DMA ring descriptors. 网卡DMA环的descriptors
 - SCSI adapter mailbox command data structures. SCSI设备mailbox命令数据结构
 - Device firmware microcode executed out of
   main memory. 设备firmware微码在主内存以外执行

  The invariant these examples all require is that any CPU store
  to memory is immediately visible to the device, and vice
  versa.  Consistent mappings guarantee this.
上面的例子都要求CPU保存到DMA的信息,设备立刻就能看到。设备保存到DMA的信息,CPU立刻也能看到。

  IMPORTANT: Consistent DMA memory does not preclude the usage of
             proper memory barriers.  The CPU may reorder stores to
      consistent memory just as it may normal memory.  Example:
      if it is important for the device to see the first word
      of a descriptor updated before the second, you must do
      something like:
注意:一致型DMA内存不排除恰当的内存屏障的使用。CPU有时象对普通内存一样,会重排DMA内
存的数据。例如: 如果设备需要先看第一个数据,然后再看第二个数据。你需要这么做:
  desc->word0 = address;
  wmb();
  desc->word1 = DESC_VALID;

             in order to get correct behavior on all platforms.
这样做可以在所有的平台上获得正确的行为。
      Also, on some platforms your driver may need to flush CPU write
      buffers in much the same way as it needs to flush write buffers
      found in PCI bridges (such as by reading a register's value
      after writing it).
在一些平台上你的驱动需要确保CPU写入的数据已经写入到设备中,例如在写入寄存器
数据后,再读一下,可以确保数据写入寄存器。

- Streaming DMA mappings which are usually mapped for one DMA
  transfer, unmapped right after it (unless you use dma_sync_* below)
  and for which hardware can optimize for sequential accesses.
流式DMA映射,这种映射通常是一个DMA缓存,写完数据后,映射就被删除(如果你没有
使用dma_sync)。设备可以优化这些数据,供下下面的顺序访问。

  Think of "streaming" as "asynchronous" or "outside the coherency
  domain".
可以把流式看作异步或非同步域。

  Good examples of what to use streaming mappings for are:
下面是使用流式映射的例子:
 - Networking buffers transmitted/received by a device.网络设备接收和发送数据的缓存
 - Filesystem buffers written/read by a SCSI device.SCSI设备读写一个文件系统的缓存

  The interfaces for using this type of mapping were designed in
  such a way that an implementation can make whatever performance
  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
the underlying bus, although some devices may have such restrictions.
Also, systems with caches that aren't DMA-coherent will work better
when the underlying buffers don't share cache lines with other data.
尽管一些设备有对齐的限制,但是DMA映射本身没有这种限制。而且带高速缓存的系统当底
下的缓存不与其他数据共享cache线时,会工作得更好。

   Using Consistent DMA mappings.使用DMA一致映射

To allocate and map large (PAGE_SIZE or so) consistent DMA regions,
you should do:
为了分配和映射大的(页大小)连续的DMA区域,你需要做如下:
 dma_addr_t dma_handle;

 cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);

where device is a struct device *. This may be called in interrupt
context with the GFP_ATOMIC flag.
dev是指向struct device结构体的指针。这段代码可能在中断上下文中使用,因此
需要用GFP_ATOMIC标志

Size is the length of the region you want to allocate, in bytes.
Size是需要分配的区域的大小,以字节为单位。

This routine will allocate RAM for that region, so it acts similarly to
__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 dma_pool interface, described below.
这个函数为那个区域分配内存,因此这个函数类似于__get_free_pages(大小是以2为底的指数)。如
果驱动需要小于1页的内存,使用dma_poll函数更好。下面是这个函数的描述:

The consistent DMA mapping interfaces, for non-NULL dev, will by
default return a DMA address which is 32-bit addressable.  Even if the
device indicates (via DMA mask) that it may address the upper 32-bits,
consistent allocation will only return > 32-bit addresses for DMA if
the consistent DMA mask has been explicitly changed via
dma_set_coherent_mask().  This is true of the dma_pool interface as
well.
对非-NULL设备,一致DMA映射函数默认返回一个32位的DMA地址。即使设备说明(通过DMA掩码)他
的地址高于32位,一致分配将只返回大于32位的DMA地址,如果一致DMA掩码明确通过
dma_set_coherent_mask函数修改了。这对于dma_pool函数也是正确的。

dma_alloc_coherent() 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.
dma_alloc_coherent返回两个值: 从CPU访问的虚拟地址和传给设备的dma_handle.

The CPU virtual address and the DMA address are both
guaranteed to be aligned to the smallest PAGE_SIZE order which
is greater than or equal to the requested size.  This invariant
exists (for example) to guarantee that if you allocate a chunk
which is smaller than or equal to 64 kilobytes, the extent of the
buffer you receive will not cross a 64K boundary.
CPU虚拟地址和DMA地址都是按页对齐,这保证了分配的内存大于或等于要求的内存。这一要求保
证了,如果你要求分配小于或等于64K的内存,你获得的内存将不会跨越64K这个边界。

To unmap and free such a DMA region, you call:
使用下面的函数释放内存,删除映射:

 dma_free_coherent(dev, size, cpu_addr, dma_handle);

where dev, size are the same as in the above call and cpu_addr and
dma_handle are the values dma_alloc_coherent() returned to you.
This function may not be called in interrupt context.
dev,size与上面调用时使用的参数相同。cpu_addr和dma_handle是dma_alloc_coherent返
回的值。这个函数不能在中断处理函数中调用。

If your driver needs lots of smaller memory regions, you can write
custom code to subdivide pages returned by dma_alloc_coherent(),
or you can use the dma_pool API to do that.  A dma_pool is like
a kmem_cache, but it uses dma_alloc_coherent(), not __get_free_pages().
Also, it understands common hardware constraints for alignment,
like queue heads needing to be aligned on N byte boundaries.
如果驱动需要一些小的内存,你可以把dma_alloc_coherent返回的内存页进一步划分。或者
使用dma_pool函数来获得小内存。dma_pool函数类似于kmem_cache,但他使用dma_alloc_coherent,
不使用__get_free_pages函数。而且dma_pool很好地处理对齐等硬件限制,象队列头需要在N字节边界对齐。

Create a dma_pool like this:
下面创建dma_pool:

 struct dma_pool *pool;

 pool = dma_pool_create(name, dev, size, align, boundary);

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" (which is expressed in bytes, and must be a
power of two).  If your device has no boundary crossing restrictions,
pass 0 for boundary; passing 4096 says memory allocated from this pool
must not cross 4KByte boundaries (but at that time it may be better to
use dma_alloc_coherent() directly instead).
name是用来调试的(象kmem_cache的名字);dev和size与前面相同。设备硬件的对齐要求
是“align”(以字节为单位,必须是2的幂)。如果你的设备没有跨越边界的限制,给boundary赋值0。
赋值4096表示内存分配不能超过4K(这时使用dma_alloc_coherent更好).

Allocate memory from a DMA pool like this:
下面是分配内存的例子:

 cpu_addr = dma_pool_alloc(pool, flags, &dma_handle);

flags are GFP_KERNEL if blocking is permitted (not in_interrupt nor
holding SMP locks), GFP_ATOMIC otherwise.  Like dma_alloc_coherent(),
this returns two values, cpu_addr and dma_handle.
flags是FRP_KERNEL,表示可以睡眠(此时不能在中断中,也不能获得SMP锁),GFP_ATOMIC则
相反。与dma_alloc_coherent一样,返回值是cpu地址和dma_handle。

Free memory that was allocated from a dma_pool like this:
下面是释放内存的例子:

 dma_pool_free(pool, cpu_addr, dma_handle);

where pool is what you passed to dma_pool_alloc(), and cpu_addr and
dma_handle are the values dma_pool_alloc() returned. This function
may be called in interrupt context.
poll是传给dma_pool_alloc的变量,cpu_addr和dma_handle是dma_pool_alloc返回
的变量。这个函数可以在中断上下文中调用。

Destroy a dma_pool by calling:
通过下面的函数删除dma pool.

 dma_pool_destroy(pool);

Make sure you've called dma_pool_free() for all memory allocated
from a pool before you destroy the pool. This function may not
be called in interrupt context.
在删除pool之前,一定要调用dma_pool_free函数来释放从一个pool中分配的内存。这个函数可以在中断中调用。

   DMA Direction DMA方向

The interfaces described in subsequent portions of this document
take a DMA direction argument, which is an integer and takes on
one of the following values:
下面是DMA的方向参数,这是一个整数,代表下面的含义:

 DMA_BIDIRECTIONAL
 DMA_TO_DEVICE
 DMA_FROM_DEVICE
 DMA_NONE

You should provide the exact DMA direction if you know it.
应该提供DMA的方向。

DMA_TO_DEVICE means "from main memory to the device"
DMA_FROM_DEVICE means "from the device to main memory"
It is the direction in which the data moves during the DMA
transfer.
DMA_TO_DEVICE是从主内存到设备
DMA_FROM_DEVICE是从设备到主内存
他们是DMA传送数据的方向

You are _strongly_ encouraged to specify this as precisely
as you possibly can.
尽量准确地指定数据传送的方向.

If you absolutely cannot know the direction of the DMA transfer,
specify DMA_BIDIRECTIONAL.  It means that the DMA can go in
either direction.  The platform guarantees that you may legally
specify this, and that it will work, but this may be at the
cost of performance for example.
如果你完全不知道DMA传送的方向, 用DMA_BIDIRECTIONAL. 这让DMA在两个方向传送数据。平台
确保可以这么指定,而且是可以工作的。但是这是以性能为代价的。

The value DMA_NONE is to be used for debugging.  One can
hold this in a data structure before you come to know the
precise direction, and this will help catch cases where your
direction tracking logic has failed to set things up properly.
DMA_NONE用来调试,在你知道数据传送方向之前,你可以用这个值。这个值可以帮你找到DMA数据传送的方向。

Another advantage of specifying this value precisely (outside of
potential platform-specific optimizations of such) is for debugging.
Some platforms actually have a write permission boolean which DMA
mappings can be marked with, much like page protections in the user
program address space.  Such platforms can and do report errors in the
kernel logs when the DMA controller hardware detects violation of the
permission setting.
DMA_NONE可以用来调试(不考虑特定平台的优化)。一些平台可以给DMA映射写权限,象用户程序
的地址空间的页保护一样。特定平台可以在kerenl的日志中报错,当DMA控制器探测到DMA权限被违反时。

Only streaming mappings specify a direction, consistent mappings
implicitly have a direction attribute setting of
DMA_BIDIRECTIONAL.
以上的数据传送方向只对流式映射有效。consistent映射默认是DMA_BIDIRECTIONAL。

The SCSI subsystem tells you the direction to use in the
'sc_data_direction' member of the SCSI command your driver is
working on.
SCSI子系统通过SCSI命令的sc_data_direction成员来告知传输方向。

For Networking drivers, it's a rather simple affair.  For transmit
packets, map/unmap them with the DMA_TO_DEVICE direction
specifier.  For receive packets, just the opposite, map/unmap them
with the DMA_FROM_DEVICE direction specifier.
对网络驱动,这相当简单。 对发送数据,用DMA_TO_DEVICE。对接收数据,用DMA_FROM_DEVICE。

    Using Streaming DMA mappings使用流式DMA映射

The streaming DMA mapping routines can be called from interrupt
context.  There are two versions of each map/unmap, one which will
map/unmap a single memory region, and one which will map/unmap a
scatterlist.
流式映射可以在中断上下文中调用。有两种映射,一是映射一块内存区域,另外是映射一个内存链。

To map a single region, you do:
下面是映射一个内存区域:

 struct device *dev = &my_dev->dev;
 dma_addr_t dma_handle;
 void *addr = buffer->ptr;
 size_t size = buffer->len;

 dma_handle = dma_map_single(dev, addr, size, direction);
 if (dma_mapping_error(dev, dma_handle)) {
  /*
   * reduce current DMA mapping usage,
   * delay and try again later or
   * reset driver.
   */
  goto map_error_handling;
 }

and to unmap it:
取消映射:

 dma_unmap_single(dev, dma_handle, size, direction);

You should call dma_mapping_error() as dma_map_single() could fail and return
error. Not all DMA implementations support the dma_mapping_error() interface.
However, it is a good practice to call dma_mapping_error() interface, which
will invoke the generic mapping error check interface. Doing so will ensure
that the mapping code will work correctly on all DMA implementations without
any dependency on the specifics of the underlying implementation. Using the
returned address without checking for errors could result in failures ranging
from panics to silent data corruption. A couple of examples of incorrect ways
to check for errors that make assumptions about the underlying DMA
implementation are as follows and these are applicable to dma_map_page() as
well.
当dma_map_single失败,返回错误时,dma_mapping_error会被调用。不是所有的DMA实现都
支持dma_mapping_error接口。
然而,调用dma_mapping_error接口是一个好习惯,这个函数会调用通用的映射错误检查接口。
这么做会确保映射代码在所有的DMA实现上都能正常工作,不会依赖于平台的一些
特殊的东西。不检查错误,直接使用返回地址会导致panic或数据损坏。下面是一些错误方式
来检查返回值。这些例子在dma_map_page中也有。

错误例子1:
Incorrect example 1:
 dma_addr_t dma_handle;

 dma_handle = dma_map_single(dev, addr, size, direction);
 if ((dma_handle & 0xffff != 0) || (dma_handle >= 0x1000000)) {
  goto map_error;
 }

错误例子 2:
Incorrect example 2:
 dma_addr_t dma_handle;

 dma_handle = dma_map_single(dev, addr, size, direction);
 if (dma_handle == DMA_ERROR_CODE) {
  goto map_error;
 }

You should call dma_unmap_single() when the DMA activity is finished, e.g.,
from the interrupt which told you that the DMA transfer is done.
当DMA活动结束后,或者中断提示DMA传送结束时,dma_unmap_single函数应该被调用。

Using CPU pointers like this for single mappings has a disadvantage:
you cannot reference HIGHMEM memory in this way.  Thus, there is a
map/unmap interface pair akin to dma_{map,unmap}_single().  These
interfaces deal with page/offset pairs instead of CPU pointers.

对单个映射这么使用CPU指针有缺点:这种方式不能访问HIGHMEM内存。因此,类似于
dma_map/unmap_single函数,有另外一个映射函数对可以访问HIGHMEM内存。
这个函数接口对处理的是页/偏移,不是CPU指针。

Specifically:
例如:
 struct device *dev = &my_dev->dev;
 dma_addr_t dma_handle;
 struct page *page = buffer->page;
 unsigned long offset = buffer->offset;
 size_t size = buffer->len;

 dma_handle = dma_map_page(dev, page, offset, size, direction);
 if (dma_mapping_error(dev, dma_handle)) {
  /*
   * reduce current DMA mapping usage,
   * delay and try again later or
   * reset driver.
   */
  goto map_error_handling;
 }

 ...

 dma_unmap_page(dev, dma_handle, size, direction);

Here, "offset" means byte offset within the given page.
偏移是在给定页内偏移的字节数。

You should call dma_mapping_error() as dma_map_page() could fail and return
error as outlined under the dma_map_single() discussion.
象在dma_map_single中讨论的一样,当dma_map_page失败,返回错误时,dma_mapping_error函数被调用。

You should call dma_unmap_page() when the DMA activity is finished, e.g.,
from the interrupt which told you that the DMA transfer is done.
当DMA活动结束,或者中断提示DMA传送完成时,dma_unmap_page函数应该被调用。

With scatterlists, you map a region gathered from several regions by:
对于内存链表,几个内存区域被影射。

 int i, count = dma_map_sg(dev, sglist, nents, direction);
 struct scatterlist *sg;

 for_each_sg(sglist, sg, count, i) {
  hw_address[i] = sg_dma_address(sg);
  hw_len[i] = sg_dma_len(sg);
 }

where nents is the number of entries in the sglist.
nents是sglist中内存区域的入口。

The implementation is free to merge several consecutive sglist entries
into one (e.g. if DMA mapping is done with PAGE_SIZE granularity, any
consecutive sglist entries can be merged into one provided the first one
ends and the second one starts on a page boundary - in fact this is a huge
advantage for cards which either cannot do scatter-gather or have very
limited number of scatter-gather entries) and returns the actual number
of sg entries it mapped them to. On failure 0 is returned.
可以把几个连续的sglist块合并成一个(例如:如果DMA映射是以页大小为粒度的,在一个页内
的几个连续的sglist可以合并成一个,对于不能处理sglit的设备或只能处理有限的sglist的
设备来说,这是一个巨大的优势),合并完成后,返回映射的具体数目,0表示成功。

Then you should loop count times (note: this can be less than nents times)
and use sg_dma_address() and sg_dma_len() macros where you previously
accessed sg->address and sg->length as shown above.
然后,应该循环几次(小于nents次),使用sg_dma_address和sg_dma_len宏,以前是sg->address和sg->length。

To unmap a scatterlist, just call:
调用下面的函数可以取消内存链表:

 dma_unmap_sg(dev, sglist, nents, direction);

Again, make sure DMA activity has already finished.
再一次确认DMA活动结束。

PLEASE NOTE:  The 'nents' argument to the dma_unmap_sg call must be
              the _same_ one you passed into the dma_map_sg call,
       it should _NOT_ be the 'count' value _returned_ from the
              dma_map_sg call.
注意:传给dma_unmap_sg的参数nents必须与传送给dma_map_sg函数的相同。不应该是函数dma_map_sg的返回值。

Every dma_map_{single,sg}() call should have its dma_unmap_{single,sg}()
counterpart, because the DMA address space is a shared resource and
you could render the machine unusable by consuming all DMA addresses.
每个dma_map_single/sg函数应该有dma_unmap_single/sg与其配对。因为DMA地址空间是共享的资源,如果把DMA的地址都占用了,这会导致机器不能正常工作。

If you need to use the same streaming DMA region multiple times and touch
the data in between the DMA transfers, the buffer needs to be synced
properly in order for the CPU and device to see the most up-to-date and
correct copy of the DMA buffer.
如果需要多次使用同一个流式DMA区域来传送不同的数据,这个DMA区域需要同步,使得CPU和设备能正确的传送最新的数据。

So, firstly, just map it with dma_map_{single,sg}(), and after each DMA
transfer call either:

 dma_sync_single_for_cpu(dev, dma_handle, size, direction);

or:

 dma_sync_sg_for_cpu(dev, sglist, nents, direction);

as appropriate.
因此,首先使用dma_map_single/sg映射,然后在DMA传送完成后,
调用dma_sync_single_for_cpu(dev, dma_handle, size, direction);或dma_sync_sg_for_cpu(dev, sglist, nents, direction);进行同步。

Then, if you wish to let the device get at the DMA area again,
finish accessing the data with the CPU, and then before actually
giving the buffer to the hardware call either:

 dma_sync_single_for_device(dev, dma_handle, size, direction);

or:

 dma_sync_sg_for_device(dev, sglist, nents, direction);

as appropriate.
然后,如果希望让设备再一次访问DMA内存,在CPU访问完成数据后,在真正把DMA内存传送给设备之前,
调用dma_sync_single_for_device(dev, dma_handle, size, direction);或dma_sync_sg_for_device(dev, sglist, nents, direction);同步。

PLEASE NOTE:  The 'nents' argument to dma_sync_sg_for_cpu() and
       dma_sync_sg_for_device() must be the same passed to
       dma_map_sg(). It is _NOT_ the count returned by
       dma_map_sg().
注意:传送给dma_sync_sg_for_cpu和dma_sync_sg_for_device的nents必须与传送给dma_map_sg的参数相同。不应该是dma_map_sg的返回值。

After the last DMA transfer call one of the DMA unmap routines
dma_unmap_{single,sg}(). If you don't touch the data from the first
dma_map_*() call till dma_unmap_*(), then you don't have to call the
dma_sync_*() routines at all.
在上次dma_unmap_single/sg后,如果从第一次dma_map_single/sg到dma_unmap_single/sg期间,数据没有被访问,这样就根本没有必要调用dma_sync函数。

Here is pseudo code which shows a situation in which you would need
to use the dma_sync_*() interfaces.
下面是调用dma_sync的伪代码。

 my_card_setup_receive_buffer(struct my_card *cp, char *buffer, int len)
 {
  dma_addr_t mapping;

  mapping = dma_map_single(cp->dev, buffer, len, DMA_FROM_DEVICE);
  if (dma_mapping_error(cp->dev, mapping)) {
   /*
    * reduce current DMA mapping usage,
    * delay and try again later or
    * reset driver.
    */
   goto map_error_handling;
  }

  cp->rx_buf = buffer;
  cp->rx_len = len;
  cp->rx_dma = mapping;

  give_rx_buf_to_card(cp);
 }

 ...

 my_card_interrupt_handler(int irq, void *devid, struct pt_regs *regs)
 {
  struct my_card *cp = devid;

  ...
  if (read_card_status(cp) == RX_BUF_TRANSFERRED) {
   struct my_card_header *hp;

   /* Examine the header to see if we wish
    * to accept the data.  But synchronize
    * the DMA transfer with the CPU first
    * so that we see updated contents.
    */
   dma_sync_single_for_cpu(&cp->dev, cp->rx_dma,
      cp->rx_len,
      DMA_FROM_DEVICE);

   /* Now it is safe to examine the buffer. */
   hp = (struct my_card_header *) cp->rx_buf;
   if (header_is_ok(hp)) {
    dma_unmap_single(&cp->dev, cp->rx_dma, cp->rx_len,
       DMA_FROM_DEVICE);
    pass_to_upper_layers(cp->rx_buf);
    make_and_setup_new_rx_buf(cp);
   } else {
    /* CPU should not write to
     * DMA_FROM_DEVICE-mapped area,
     * so dma_sync_single_for_device() is
     * not needed here. It would be required
     * for DMA_BIDIRECTIONAL mapping if
     * the memory was modified.
     */
    give_rx_buf_to_card(cp);
   }
  }
 }

Drivers converted fully to this interface should not use virt_to_bus() any
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 dma_alloc_coherent(), dma_pool_alloc(), and dma_map_single()
calls (dma_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.
使用这个接口函数的驱动不要再使用virt_to_bus和bus_to_virt。一些驱动需要做一些修改,因为在DMA映射中没有bus_to_virt的替代函数。可以把
dma_alloc_coherent,dma_pool_alloc和dma_map_single返回的DMA地址保存在驱动之中。dma_map_sg把DMA地址保存在scatterlist之中。

All drivers should be using these interfaces with no exceptions.  It
is planned to completely remove virt_to_bus() and bus_to_virt() as
they are entirely deprecated.  Some ports already do not provide these
as it is impossible to correctly support them.
所有的驱动应该使用这些接口。virt_to_bus和bus_to_virt很快就被完全删掉,因为这些函数已经过时了。一些设备已经不支持这些函数了。


   Handling Errors错误处理

DMA address space is limited on some architectures and an allocation
failure can be determined by:
在一些架构上,DMA地址空间是有限制的。通过下面的方法可以确定分配错误:

- checking if dma_alloc_coherent() returns NULL or dma_map_sg returns 0
检查dma_alloc_coherent是否返回NULL,dma_map_sg是否返回0

- checking the dma_addr_t returned from dma_map_single() and dma_map_page()
  by using dma_mapping_error():
使用dma_mapping_error检查dma_map_single和dma_map_page返回的dma_addr_t:

 dma_addr_t dma_handle;

 dma_handle = dma_map_single(dev, addr, size, direction);
 if (dma_mapping_error(dev, dma_handle)) {
  /*
   * reduce current DMA mapping usage,
   * delay and try again later or
   * reset driver.
   */
  goto map_error_handling;
 }

- unmap pages that are already mapped, when mapping error occurs in the middle
  of a multiple page mapping attempt. These example are applicable to
  dma_map_page() as well.
当映射多个页时,在中间出现映射错误时,已经映射的页必须取消映射。下面的例子也适用于dma_map_page函数。

Example 1:
例 1:
 dma_addr_t dma_handle1;
 dma_addr_t dma_handle2;

 dma_handle1 = dma_map_single(dev, addr, size, direction);
 if (dma_mapping_error(dev, dma_handle1)) {
  /*
   * reduce current DMA mapping usage,
   * delay and try again later or
   * reset driver.
   */
  goto map_error_handling1;
 }
 dma_handle2 = dma_map_single(dev, addr, size, direction);
 if (dma_mapping_error(dev, dma_handle2)) {
  /*
   * reduce current DMA mapping usage,
   * delay and try again later or
   * reset driver.
   */
  goto map_error_handling2;
 }

 ...

 map_error_handling2:
  dma_unmap_single(dma_handle1);
 map_error_handling1:

Example 2: (if buffers are allocated in a loop, unmap all mapped buffers when
     mapping error is detected in the middle)
例2:在循环映射时,出现错误,已经映射的缓存,必须取消映射。

 dma_addr_t dma_addr;
 dma_addr_t array[DMA_BUFFERS];
 int save_index = 0;

 for (i = 0; i < DMA_BUFFERS; i++) {

  ...

  dma_addr = dma_map_single(dev, addr, size, direction);
  if (dma_mapping_error(dev, dma_addr)) {
   /*
    * reduce current DMA mapping usage,
    * delay and try again later or
    * reset driver.
    */
   goto map_error_handling;
  }
  array[i].dma_addr = dma_addr;
  save_index++;
 }

 ...

 map_error_handling:

 for (i = 0; i < save_index; i++) {

  ...

  dma_unmap_single(array[i].dma_addr);
 }

Networking drivers must call dev_kfree_skb() to free the socket buffer
and return NETDEV_TX_OK if the DMA mapping fails on the transmit hook
(ndo_start_xmit). This means that the socket buffer is just dropped in
the failure case.
在ndo_start_xmit中,DMA映射失败时,网络驱动必须调用dev_kfree_skb释放缓存,并返回NETDEV_TX_OK。
这表示缓存已经释放了。

SCSI drivers must return SCSI_MLQUEUE_HOST_BUSY if the DMA mapping
fails in the queuecommand hook. This means that the SCSI subsystem
passes the command to the driver again later.
如果SCSI驱动在queuecommand中DMA映射失败,驱动必须返回SCSI_MLQUEUE_HOST_BUSY。这表示驱动稍后会再把命令传下来。

  Optimizing Unmap State Space Consumption unmap的优化

On many platforms, dma_unmap_{single,page}() is simply a nop.
Therefore, keeping track of the mapping address and length is a waste
of space.  Instead of filling your drivers up with ifdefs and the like
to "work around" this (which would defeat the whole purpose of a
portable API) the following facilities are provided.
在许多平台上,dma_unmap_single/page非常简单。因此保留映射地址和长度浪费空间。下面的方法可以简化:

Actually, instead of describing the macros one by one, we'll
transform some example code.

1) Use DEFINE_DMA_UNMAP_{ADDR,LEN} in state saving structures. 在结构体中使用DEFINE_DMA_UNMAP_{ADDR,LEN}
   Example, before:例如,使用之前

 struct ring_state {
  struct sk_buff *skb;
  dma_addr_t mapping;
  __u32 len;
 };

   after:使用之后

 struct ring_state {
  struct sk_buff *skb;
  DEFINE_DMA_UNMAP_ADDR(mapping);
  DEFINE_DMA_UNMAP_LEN(len);
 };

2) Use dma_unmap_{addr,len}_set() to set these values.使用dma_unmap_{addr,len}_set()设置这些值。
   Example, before:例,使用之前

 ringp->mapping = FOO;
 ringp->len = BAR;

   after:使用之后

 dma_unmap_addr_set(ringp, mapping, FOO);
 dma_unmap_len_set(ringp, len, BAR);

3) Use dma_unmap_{addr,len}() to access these values.使用dma_unmap_{addr,len}()访问这些值
   Example, before:例,使用之前

 dma_unmap_single(dev, ringp->mapping, ringp->len,
    DMA_FROM_DEVICE);

   after:使用之后

 dma_unmap_single(dev,
    dma_unmap_addr(ringp, mapping),
    dma_unmap_len(ringp, len),
    DMA_FROM_DEVICE);

It really should be self-explanatory.  We treat the ADDR and LEN
separately, because it is possible for an implementation to only
need the address in order to perform the unmap operation.
ADDR和LEN被分别处理,因为有可能只需要地址来进行取消映射。

   Platform Issues平台问题

If you are just writing drivers for Linux and do not maintain
an architecture port for the kernel, you can safely skip down
to "Closing".
如果只是写linux驱动,并不维护一个linux内核架构,下面这些可以忽略。

1) Struct scatterlist requirements.
Struct scatterlist要求

   You need to enable CONFIG_NEED_SG_DMA_LENGTH if the architecture
   supports IOMMUs (including software IOMMU).
如果架构支持IOMMUs,内核选项CONFIG_NEED_SG_DMA_LENGTH应该打开(包括IOMMU软件)。

2) ARCH_DMA_MINALIGN

   Architectures must ensure that kmalloc'ed buffer is
   DMA-safe. Drivers and subsystems depend on it. If an architecture
   isn't fully DMA-coherent (i.e. hardware doesn't ensure that data in
   the CPU cache is identical to data in main memory),
   ARCH_DMA_MINALIGN must be set so that the memory allocator
   makes sure that kmalloc'ed buffer doesn't share a cache line with
   the others. See arch/arm/include/asm/cache.h as an example.
架构必须确保kmalloc分配的内存是DMA安全的。驱动和子系统依赖于这个。如果一个架构不是完全DMA兼容的(例如,设备不能保证CPU的缓存中的数据与主内存中
的数据完全一样),ARCH_DMA_MINALIGN内核选项必须被选中,保证kmalloc分配的内存不共享缓存线。参加arch/arm/include/asm/cache.h

   Note that ARCH_DMA_MINALIGN is about DMA memory alignment
   constraints. You don't need to worry about the architecture data
   alignment constraints (e.g. the alignment constraints about 64-bit
   objects).
注意:ARCH_DMA_MINALIGN是关于DMA内存对齐的限制。不用担心架构数据对齐的限制(例如,64位对象在对齐上的限制)

      Closing 结束语

This document, and the API itself, would not be in its current
form without the feedback and suggestions from numerous individuals.
We would like to specifically mention, in no particular order, the
following people:
没有众人的贡献,本文档和API就不会面世。我们特别感谢下面的人(没有主次之分):

 Russell King <rmk@arm.linux.org.uk>
 Leo Dagum <dagum@barrel.engr.sgi.com>
 Ralf Baechle <ralf@oss.sgi.com>
 Grant Grundler <grundler@cup.hp.com>
 Jay Estabrook <Jay.Estabrook@compaq.com>
 Thomas Sailer <sailer@ife.ee.ethz.ch>
 Andrea Arcangeli <andrea@suse.de>
 Jens Axboe <jens.axboe@oracle.com>
 David Mosberger-Tang <davidm@hpl.hp.com>


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值