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跨核共享 方案

  1. 在内核模块中获取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 管逻辑

  2. 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 对绑定。

  3. 将iova发送给R核
    方案一:在内核驱动获取iova后,直接调用erpc接口发给R核,等待R核使用完毕通知A核驱动进行释放。
    方案二:在内核驱动获取iova后,返还给用户层,由用户层调用erpc接口发给R核。

单个buffer使用方法如此,若是需要队列进行buffer轮转,还需要添加一些逻辑。

posted @ 2025-11-11 14:43  moonのsun  阅读(7)  评论(0)    收藏  举报