DMA机制-2
IOVA
IOVA指的是IO的virtual address。
IO指的是DMA硬件,比如ARM的IOMMU(又称为SMMU)。
对于CPU来说:vaddr -> MMU -> paddr,对于DMA来说:iova -> IOMMU -> paddr。
关系图:
+------------------+ +------------------+
| CPU (内核) | | 设备 (GPU/FPGA) |
| | | |
| vaddr (虚拟地址) | | iova (IO虚拟地址) |
| | | | | |
| v | | v |
| [MMU 映射] | | [IOMMU 映射] |
| | | | | |
| +-------->+-------+--------+ |
| 物理地址 paddr |
| (如 0x4a000000) |
+--------------------------------------------+
IOVA和物理地址通常需要按页对齐。
IOMMU
CPU 分配的大块内存(如 1MB)在物理上可能是 不连续的(由多个 4KB 页组成);
但很多设备要求 物理连续的 DMA 缓冲区,IOMMU 允许你:
- 分配多个不连续物理页
- 通过 IOVA 将它们 映射成设备视角下连续的地址空间
IOMMU可以解决物理内存分配的碎片化。
基于IOMMU硬件的DMA buffer跨核共享 模型
+--------------------------------------------------+
| A 核 (Linux) |
| - Kernel |
| - IOMMU (SMMU) driver |
| - Device Tree: |
| isp@56000000 { |
| compatible = "vendor,isp"; |
| reg = <0x56000000 0x10000>; |
| iommus = <&smmu 0x42>; ←←← StreamID = 0x42
| }; |
+--------------------------------------------------+
↑
AXI Interconnect
↑
+--------------------------------------------------+
| ISP 硬件单元 (固定功能 IP) |
| - 内置 DMA 引擎 |
| - 发起内存读写时携带 StreamID = 0x42 |
+--------------------------------------------------+
↑
SMMU (IOMMU)
↑
DRAM
基于IOMMU硬件的DMA buffer跨核共享 方案
-
在内核模块中获取ISP设备
isp设备运行在R核,为什么要在A核Linux下创建设备?
✅ Linux 需要这个 isp_dev 并不是因为“控制 ISP 的运行”,而是为了“代表 ISP 硬件”向 IOMMU 申请 DMA 映射。
即使 ISP 的固件跑在 RTOS 上,其硬件单元(DMA 引擎、寄存器等)仍然是 SoC 的一部分,由 Linux 设备树描述,并受 Linux IOMMU 子系统管理。
只要 ISP 硬件在芯片内部有唯一的 StreamID / device ID,Linux 就必须在设备树中为其声明一个 device node,以便:
① 分配 StreamID;
② 建立 IOMMU 映射上下文(Context Bank);
③ 管理其 DMA 地址空间。
可以参考上面的“基于IOMMU硬件的DMA buffer跨核共享 模型”
struct device 在 Linux 中不仅是“驱动绑定点”,更是“IOMMU、DMA、电源、时钟等子系统的资源锚点”。
核心思想是:Linux 管资源,RTOS 管逻辑。 -
dma_alloc_attrs() 申请DMA buffer,获取iova(dma_handle)
dma_alloc_attrs() 是 Linux 内核中用于分配具有特定属性(attributes)的 DMA(Direct Memory Access)内存的函数。
它是在较新版本的内核(大约从 4.12 开始)引入的,用来替代旧的 dma_alloc_coherent() 和 dma_alloc_writecombine() 等接口,提供更灵活的内存分配控制。
void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
gfp_t flag, unsigned long attrs);
参数说明:
dev:指向设备结构体 struct device 的指针。该设备将使用这块 DMA 内存。
size:要分配的内存大小(以字节为单位)。
dma_handle:输出参数,用于返回分配内存的总线地址(DMA 地址),供设备使用。
flag:内存分配标志(如 GFP_KERNEL、GFP_ATOMIC 等)。
attrs:DMA 属性掩码,用于指定内存的特殊属性(例如是否缓存、一致性等)。
至此:
iova 是 ISP DMA 引擎应使用的地址;
IOMMU 已建立 iova → physical page 映射;
内存生命周期由 vaddr/iova 对绑定。 -
将iova发送给R核
方案一:在内核驱动获取iova后,直接调用erpc接口发给R核,等待R核使用完毕通知A核驱动进行释放。
方案二:在内核驱动获取iova后,返还给用户层,由用户层调用erpc接口发给R核。
单个buffer使用方法如此,若是需要队列进行buffer轮转,还需要添加一些逻辑。
本文来自博客园,作者:moonのsun,转载请注明原文链接:https://www.cnblogs.com/moon-sun-blog/p/19210285

浙公网安备 33010602011771号