arm archtecture上的dma_map_single内部

时间:2016-08-22 05:22:15

标签: memory-management linux-kernel arm linux-device-driver dma

我试图理解ARM体系结构的DMA内部,引用内核文档:http://lxr.free-electrons.com/source/Documentation/DMA-API-HOWTO.txt

我的理解是我们在内核空间中分配内存(使用DMA约束)并将其传递给dma_map_single()函数,此函数将根据DMA需要更改内存的映射属性(写入组合或非缓存) )。然后,如果平台支持IOMMU,它将返回设备总线的虚拟地址,否则它将返回可以直接从设备访问的物理地址。

理解是否正确?

目前,我无法映射它的源代码,任何带有代码片段的指针都会非常有用。

1 个答案:

答案 0 :(得分:6)

不完全。

对于流式DMA API(即dma_map_*() / dma_unmap_*()),实际上没有重新映射。只有来自内核线性映射的地址(即普通kmalloc()内存)对流式DMA有效,因此由于CPU映射是可缓存的,因此非连贯设备的dma_map_*()操作将清除/使缓存无效适用于缓冲区的范围,并依赖CPU在相应的dma_unmap_*()之前不访问它。然后(如果适当的话)在同时进行任何推测性提取的情况下,在CPU可以读取由设备写入存储器的任何数据之前,再次使高速缓存无效。对于缓存一致的设备,这些都不需要,所以它被跳过了。

由于缓冲区位于线性映射中,因此DMA地址是virt_to_phys()偏移量的简单情况,减去在某些时髦硬件情况下在物理内存和总线地址之间进行转换的任何特定于设备的偏移量(例如Raspberry Pi 2/3或TI Keystone 2) - 参见例如the ARM implementation of dma_map_page()(其中dma_map_single() is merely a special case)。在涉及IOMMU的情况下,还有一个额外步骤:为该物理地址创建IOVA映射,并返回该IOVA而不是底层总线地址。

请注意,对于一致 DMA API(即dma_alloc_coherent()),当设备本身不是缓存一致时,我们创建一个单独的非vmalloc区域中已分配页面的可缓存映射,然后对该缓冲区的所有CPU访问使用该非可缓存别名(在初始缓存维护之后清理线性映射别名),因为与流式DMA不同,CPU和设备都是如此允许随时访问连贯的缓冲区。