dma_map_single arm 架构的内部结构

dma_map_single internals on arm archtecture

我正在尝试了解 ARM 架构上的 DMA 内部结构,参考内核文档:http://lxr.free-electrons.com/source/Documentation/DMA-API-HOWTO.txt

我的理解是我们在内核中分配内存space(有DMA约束)并传递给dma_map_single()函数,这个函数会根据DMA需要改变内存的映射属性(写入组合或非缓存)。如果平台支持 IOMMU,它将 return 设备总线的虚拟地址,或者它将 return 可以直接从设备访问的物理地址。

理解正确吗?

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

不完全是。

对于流式 DMA API(即 dma_map_*()/dma_unmap_*()),实际上没有重新映射。只有来自内核线性映射(即正常 kmalloc() 内存)的地址对流式 DMA 有效,因此由于 CPU 映射是可缓存的,非一致性设备的 dma_map_*() 操作将 clean/invalidate 根据缓冲区的范围适当缓存,并依赖于 CPU 在相应的 dma_unmap_*() 之前不访问它。然后(如果适用)再次使缓存无效,以防在此期间发生任何推测性提取,然后 CPU 可以读取设备写入内存的任何数据。对于缓存一致的设备,需要 none,因此跳过。

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

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