外设数据到昇腾310推理卡 之一
目录
问题提出
内核路径及文件说明
videobuf2-dma-contig.c
mmap方式分配
vb2_dc_alloc
attrs
总结
问题提出
假设310做pcie ep,视频流接口也做EP,如下图所示,那么数据如何流转到310呢?
首先了解内核对视频处理的流程,前述我们整理过总体流程,本文着重介绍底层内存分配接口,而后介绍这些接口的应用。进而在上述问题中的应用。
内核路径及文件说明
drivers\media\common\videobuf2 此目录下,主要有三个内存分配的文件,介绍如下
文件 | 内存类型 | 分配方式 | 主要用途 |
---|---|---|---|
videobuf2-dma-contig.c | 物理连续内存 | dma_alloc_coherent | 硬件要求连续内存(如 ISP、编码器) |
videobuf2-dma-sg.c | 非连续内存(SG 列表) | vmalloc /用户缓冲区 | 通用 DMA 硬件(如 USB 摄像头) |
videobuf2-cma-sg.c | CMA 内存 + SG 抽象 | CMA 分配 | 兼容旧硬件或特定需求 |
选择建议
-
优先使用
dma-contig
:若硬件明确需要连续内存(如 MIPI CSI 摄像头或 VPU 加速)。 -
默认使用
dma-sg
:若硬件支持 SG 且无连续内存要求(如大多数 USB 设备)。 -
cma-sg
仅在特定旧平台或驱动中有需求。
这些模块通过 videobuf2
核心框架为视频驱动提供统一的缓冲区管理接口,屏蔽底层内存分配细节。
videobuf2-dma-contig.c
根据我们的问题及三个文件的分析说明,我们着重分析videobuf2-dma-contig.c 文件。
该文件实现了使用连续 DMA 内存的视频缓冲区管理,适用于需要物理连续内存的视频硬件设备(如摄像头、视频编解码器等)。它提供了多种内存操作方式,包括 MMAP、USERPTR 和 DMABUF
对外统一的接口,后续我们在内存使用时,会看到对这部分接口的回调,此处先行记录。
const struct vb2_mem_ops vb2_dma_contig_memops = {.alloc = vb2_dc_alloc, //mmap 方式的分配接口 分配连续 DMA 内存缓冲区.put = vb2_dc_put, //释放 DMA 连续内存缓冲区.get_dmabuf = vb2_dc_get_dmabuf,.cookie = vb2_dc_cookie,.vaddr = vb2_dc_vaddr,.mmap = vb2_dc_mmap, //将 DMA 缓冲区映射到用户空间.get_userptr = vb2_dc_get_userptr,.put_userptr = vb2_dc_put_userptr,.prepare = vb2_dc_prepare, //DMA 传输前后的同步操作.finish = vb2_dc_finish, //DMA 传输前后的同步操作.map_dmabuf = vb2_dc_map_dmabuf, .unmap_dmabuf = vb2_dc_unmap_dmabuf,.attach_dmabuf = vb2_dc_attach_dmabuf,.detach_dmabuf = vb2_dc_detach_dmabuf,.num_users = vb2_dc_num_users,
};
mmap方式分配
上述接口注释中,alloc put和mmap用于mmap方式的底层接口。
prepare和finish则是三种方式通用的接口。
类似的应用场景如下:即
1)用户分配多块连续的物理内存,形成一个物理内存的链表,每个节点单独存储一帧数据。
2)外设将数据写入到这些节点。
3) 用户从这些节点中读取数据。
vb2_dc_alloc
核心调用
buf->attrs = attrs;buf->cookie = dma_alloc_attrs(dev, size, &buf->dma_addr,GFP_KERNEL | gfp_flags, buf->attrs);
主要参数: 第二个及最后一个,由调用者传入。
1) attrs
2) gfp_flags
attrs
定义在,\kernel\include\linux\dma-mapping.h,形如DMA_ATTR_SYS_CACHE_ONLY等,具体的请参考源码,此处汇总应用场景等
属性名称 | 作用 | 典型应用场景 | 硬件要求 | 同步要求 | 性能影响 | 限制与风险 |
---|---|---|---|---|---|---|
DMA_ATTR_SYS_CACHE_ONLY | 允许缓冲区使用系统/末级缓存(LLC),需手动维护与非一致性设备的一致性 | 非一致性但支持缓存的设备(如DSP、NPU) | 设备需容忍缓存存在 | 必须显式调用 dma_sync_* | 减少访问延迟(缓存命中时) | 设备不支持缓存时会导致数据不一致 |
DMA_ATTR_SYS_CACHE_ONLY_NWA | 同上,但禁用写分配(No Write-Allocate) | 写入密集型设备(如视频编码输出) | 同上 | 同上 | 减少缓存污染,写入性能更优 | 读取频繁场景可能降低缓存命中率 |
DMA_ATTR_WEAK_ORDERING | 允许内存访问弱序执行(读写可乱序) | 网络设备、DMA引擎(不依赖严格顺序) | 设备逻辑不依赖内存顺序 | 无需额外同步 | 减少内存屏障开销 | 顺序敏感设备会出错 |
DMA_ATTR_WRITE_COMBINE | 合并写入操作(类似WC内存) | 帧缓冲区(GPU/V4L2)、高频写入设备 | 无特殊要求 | 需手动flush 写入 | 提升写入带宽 | 写入延迟可见,需主动同步 |
DMA_ATTR_NO_KERNEL_MAPPING | 避免创建内核虚拟地址映射 | 安全敏感设备、协处理私有内存 | 无 | 无 | 节省内核虚拟地址空间 | 内核无法直接访问缓冲区 |
DMA_ATTR_SKIP_CPU_SYNC | 跳过CPU缓存同步(假设设备已更新数据) | 设备独占写入(加密引擎)、零拷贝接收 | 设备必须保证数据完整性 | 无 | 减少冗余同步开销 | 设备未完整写入时会导致脏数据 |
DMA_ATTR_FORCE_CONTIGUOUS | 强制分配物理连续内存(即使IOMMU存在) | 旧硬件(摄像头控制器)、需物理连续的DMA引擎 | 依赖CMA或大页内存 | 无 | 避免SG-DMA分散开销 | 大内存可能分配失败 |
DMA_ATTR_ALLOC_SINGLE_PAGES | 优先分配单页内存(非大页) | 小缓冲区高频分配(USB批量传输) | 无 | 无 | 减少TLB压力 | 大块内存效率低 |
DMA_ATTR_PRIVILEGED | 限制缓冲区仅高特权级访问(如EL2/TEE) | 安全加密引擎、TrustZone环境 | 依赖MMU权限配置 | 无 | 增强安全性 | 需硬件支持特权级隔离 |
DMA_ATTR_OVERWRITE | 提示设备将完全覆写缓冲区(无需保留旧数据) | 零拷贝网络接收、DMA_FROM_DEVICE传输 | 设备必须覆写全部数据 | 无 | 跳过预读优化传输性能 | 设备未覆写全部数据时会导致残留数据 |
默认(无属性) | 无缓存(Non-Cacheable),严格一致性 | 传统非一致性DMA设备(如旧网卡) | 无 | 无需同步 | 安全性高,性能较低 | 访问延迟高 |
1) 对于强制分配连续物理内存情形,依赖于cma,而商用操作系统,例如麒麟,cma大小被限制。例如预留1G可以,预留2G则失败。这种情况,对于我们的应用就有限制了。
dmesg |grep -i cma
[ 0.000000] cma: Reserved 1024 MiB at 0x00000000b1800000
[ 0.000000] Kernel command line: BOOT_IMAGE=/vmlinuz-5.4.18-52-generic root=UUID=7291d504-6ba9-4b1c-b513-1af62bae982e ro mem=11520M cma=1024M quiet splash resume=UUID=e52cb080-ef37-40c7-beda-3a435f5a6564 audit=0 security=kysec
[ 0.000000] Memory: 10377592K/11796480K available (11772K kernel code, 1448K rwdata, 6764K rodata, 960K init, 3169K bss, 370312K reserved, 1048576K cma-reserved)
2) 问题: 哪些设备 会设置skip cache,哪些设置cache only,
将上述宏进行分类汇总如下:
分类 | 属性名称 | 核心功能 | 硬件要求 | 是否需要同步 | 典型应用场景 |
---|---|---|---|---|---|
物理布局控制 | DMA_ATTR_FORCE_CONTIGUOUS | 强制分配物理连续内存(即使IOMMU存在) | 依赖CMA或大页内存 | 否 | 旧硬件(摄像头控制器)、需物理连续的DMA引擎 |
DMA_ATTR_ALLOC_SINGLE_PAGES | 优先分配单页内存(非大页) | 无 | 否 | 小缓冲区高频分配(USB批量传输) | |
缓存与一致性 | DMA_ATTR_SYS_CACHE_ONLY | 允许使用系统缓存(需手动同步与非一致性设备) | 设备需容忍缓存存在 | 是(dma_sync_* ) | 非一致性但支持缓存的设备(DSP/NPU) |
DMA_ATTR_SYS_CACHE_ONLY_NWA | 同上,但禁用写分配(减少缓存污染) | 同上 | 是 | 高频写入设备(视频编码输出) | |
DMA_ATTR_WRITE_COMBINE | 合并写入操作(类似WC内存) | 无特殊要求 | 是(需手动flush ) | 帧缓冲区(GPU/V4L2)、高频写入设备 | |
内存访问顺序 | DMA_ATTR_WEAK_ORDERING | 允许内存访问弱序执行(读写可乱序) | 设备不依赖严格内存顺序 | 否 | 网络设备、DMA引擎 |
安全与隔离 | DMA_ATTR_PRIVILEGED | 限制缓冲区仅高特权级访问(如TEE) | 依赖MMU权限配置 | 否 | 安全加密引擎、TrustZone环境 |
DMA_ATTR_NO_KERNEL_MAPPING | 避免创建内核虚拟地址映射 | 无 | 否 | 协处理私有内存、安全敏感设备 | |
性能优化 | DMA_ATTR_SKIP_CPU_SYNC | 跳过CPU缓存同步(假设设备已更新数据) | 设备必须保证数据完整性 | 否 | 设备独占写入(加密引擎)、零拷贝接收 |
DMA_ATTR_OVERWRITE | 提示设备将完全覆写缓冲区(无需保留旧数据) | 设备必须覆写全部数据 | 否 | 零拷贝网络接收、DMA_FROM_DEVICE传输 | |
调试与容错 | DMA_ATTR_NO_WARN | 抑制内存分配失败警告 | 无 | 否 | 低内存环境、预期可能失败的分配 |
总结
对于我们的场景, 采用何种参数进行内存布局、缓存控制呢?