Linux 内核中的 DMA 映射和 DMA 引擎是什么?
内核通常使用虚拟地址。功能类似于kmalloc()
, vmalloc()
通常返回虚拟地址。它可以存储在void*
。虚拟内存系统将这些地址转换为物理地址。这些物理地址实际上对驱动程序没有用处。驾驶员必须使用ioremap()
映射空间并产生虚拟地址。
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
| | | |
| | | |
+-------+ +------+
如果设备支持 DMA ,驱动程序使用以下命令设置缓冲区kmalloc
或返回虚拟地址(X)的类似接口。虚拟的
内存系统将 X 映射到系统 RAM 中的物理地址 (Y)。司机
可以使用虚拟地址X来访问缓冲区,但是设备本身
不能,因为 DMA 不经过 CPU 虚拟内存系统。在某些系统中,只有设备可以直接对物理地址进行DMA。
在某些系统中,IOMMU硬件用于将DMA地址转换为物理地址。看上图,它将Z转换为Y。
DMA映射API何时可以在Linux设备中使用
司机?
使用 DMA 映射 API 的原因是驱动程序可以将虚拟地址 X 返回到接口,例如dma_map_single()
,它设置任何所需的 IOMMU
映射并返回 DMA 地址 Z。然后驱动程序告诉设备
对Z进行DMA,IOMMU将其映射到系统中地址Y处的缓冲区
内存。
参考资料取自这个链接 https://www.kernel.org/doc/Documentation/DMA-API-HOWTO.txt.
任何真正的 Linux 设备驱动程序示例作为参考都会很棒。
一个简单的 PCI DMA 示例 http://www.xml.com/ldd/chapter/book/ch13.html
你可以查看linux内核内部驱动程序/DMA http://lxr.free-electrons.com/source/drivers/dma/对于各种真实的司机。