当前位置: 首页 > news >正文

外设数据到昇腾310推理卡 之二dma_alloc_attrs

目录

内核源码及路径

CONFIG_DMA_DECLARE_COHERENT

DTS示例配置

dma_direct_alloc

特殊属性快速路径 (DMA_ATTR_NO_KERNEL_MAPPING)

主体流程

1. 内存分配核心

2. 地址转换

3. 缓存一致性处理

 映射

attrs不同属性的cache处理

 cache的标示(ARM64)

dma_alloc_attrs

总结


   前述文章中,我们介绍了分配内存的几种方式以及着重介绍mmap方式的一个参数,本文介绍分配内存的过程。

内核源码及路径

路径函数及宏  功能
kernel\dma\mapping.cdma_alloc_attrs
kernel\kernel\dma\coherent.c

dma_declare_coherent_memory

dma_alloc_from_dev_coherent  DMA设备一致性内存分配

\kernel\kernel\dma\direct.cdma_direct_alloc  DMA CMA内存分配
\kernel\include\linux\dma-mapping.hdma_alloc_coherent
  arch\arm64\mm   
 
arch_dma_prep_coherent 分配内存页后,将内存页转换虚拟地址并调用__dma_flush_area
\kernel\arch\arm64\mm\cache.S__dma_flush_area 功能clean & invalidate D / U line
I:\rk3588\kernel\arch\arm64\include\asm\pgtable.hpgprot_syscached 功能Mark the prot value as outer cacheable and inner non-cacheable

  

CONFIG_DMA_DECLARE_COHERENT

声明设备默认支持硬件一致性DMA(Hardware-Coherent DMA),使得内核在分配DMA缓冲区时,自动假设设备与CPU缓存保持一致,无需软件维护同步。

场景启用 CONFIG_DMA_DECLARE_COHERENT不启用
内存分配dma_alloc_coherent() 返回硬件一致性内存默认返回非一致性内存(需手动同步)
同步操作无需调用 dma_sync_*必须显式同步缓存
设备树/ACPI配置需设备节点包含 dma-coherent 属性无特殊要求
性能更高(无同步开销)较低(依赖软件同步

如何验证硬件是否真正支持一致性?

  • 检查设备手册是否声明支持(如ARM的ACP或PCIe的ATS)。在驱动中故意省略dma_sync_*,测试数据传输是否正常。

DTS示例配置

reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;my_coherent_pool: coherent_pool@0x10000000 {compatible = "shared-dma-pool";reg = <0x10000000 0x400000>; // 4MB区域no-map;};
};my_device: my_device@0 {compatible = "vendor,coherent-device";memory-region = <&my_coherent_pool>; // 关联内存区域dma-coherent;
};

基于上述的DTS与内核配置,在分配一致性内存时,从上述DTS中的区域分配,而非从cma分配。例如我们可以将高地址内存预留出来,通过上述方式给我们的视频接口使用。

此外可以在驱动中调用接口 dma_declare_coherent_memory将保留的物理内存与设备关联。进而绕开cma

dma_direct_alloc

特殊属性快速路径 (DMA_ATTR_NO_KERNEL_MAPPING)

if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) && !force_dma_unencrypted(dev)) {page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO);*dma_handle = phys_to_dma_direct(dev, page_to_phys(page));return page; // 返回 page 结构而非虚拟地址
}

应用场景:当内核不需要访问该内存时(如纯设备间DMA)

主体流程

 

1. 内存分配核心

page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO);

  • 使用 CMA 或 buddy 分配器获取物理连续页

  • 明确排除 __GFP_ZERO 以优化性能(后续手动清零)

2. 地址转换

*dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
  • 将物理地址转换为设备可识别的 DMA 地址

  • 处理可能的地址偏移(如 SMMU 前向窗口)

3. 缓存一致性处理

arch_dma_prep_coherent(page, size);
  • 确保 CPU 缓存与内存一致。这里是在分配内存后,被使用前,进行的一致性处理。架构特定实现(如 ARM 的 cache 刷写)

 映射

主要属性控制,如上一篇所述

attrs不同属性的cache处理

/** Return the page attributes used for mapping dma_alloc_* memory, either in* kernel space if remapping is needed, or to userspace through dma_mmap_*.*/
pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs)
{if (force_dma_unencrypted(dev))prot = pgprot_decrypted(prot);if (dev_is_dma_coherent(dev))return prot;
#ifdef CONFIG_ARCH_HAS_DMA_WRITE_COMBINEif (attrs & DMA_ATTR_WRITE_COMBINE)return pgprot_writecombine(prot);
#endifif (attrs & DMA_ATTR_SYS_CACHE_ONLY ||attrs & DMA_ATTR_SYS_CACHE_ONLY_NWA)return pgprot_syscached(prot);return pgprot_dmacoherent(prot);
}#define pgprot_dmacoherent(prot)	pgprot_noncached(prot)  //关闭cache

 

 cache的标示(ARM64)

/*
 * Mark the prot value as outer cacheable and inner non-cacheable. Non-coherent
 * devices on a system with support for a system or last level cache use these
 * attributes to cache allocations in the system cache.
 */


#define pgprot_syscached(prot) \__pgprot_modify(prot, PTE_ATTRINDX_MASK, \PTE_ATTRINDX(MT_NORMAL_iNC_oWB) | PTE_PXN | PTE_UXN)

 

dma_alloc_attrs

     内核分配并映射内存的流程分为三个主体,本篇介绍了左边两个。至于smmu iommu的映射目前不涉及。 

     顺便提一句 dma_alloc_coherent,因为很多教程里面都提这个接口,这个接口内部实际封装了attrs这个接口,而仅仅把attrs属性设置了0,根据上述的分析,即映射到内核时,其页面被设置了no cache的属性,即关闭了cache。

static inline void *dma_alloc_coherent(struct device *dev, size_t size,dma_addr_t *dma_handle, gfp_t gfp)
{return dma_alloc_attrs(dev, size, dma_handle, gfp,(gfp & __GFP_NOWARN) ? DMA_ATTR_NO_WARN : 0);
}

总结

    分析了dma 分配的流程,分为三种情况。

    1) dma 设备支持一致性,从设备占用的DDR中分配内存,不走cma的接口。

     2) 直接进行物理地址的映射。

     3) iommu的情况。  dma_map_ops的实现

    通过上述流程可知,dma分配的接口可以分配cache的和no cached,具体哪些驱动采用了cached呢?

     另外既然如此,流式映射的接口,诸如dma_map_single为什么不用dma_alloc_attrs 封装呢?

因为dma_map_single为单纯建立映射,并不分配内存;而dma_alloc_attrs先分配了页啊。

http://www.xdnf.cn/news/1110493.html

相关文章:

  • Linux系统编程——目录 IO
  • 理解小数的计算机表达
  • PyTorch神经网络实战:从零构建图像分类模型
  • 脉冲神经网络膜电位泄漏系数学习:开启时空动态特征提取的新篇章
  • 复现永恒之蓝
  • Linux - 安全排查 3
  • 飞算JavaAI:重新定义Java开发效率的智能引擎
  • python-for循环
  • 【TA/Unity】Shader基础结构
  • 强化学习、PPO和GRPO的通俗讲解
  • 创客匠人:解析创始人 IP 打造对知识变现的深层赋能
  • os.machine()详解
  • vue3 el-table动态表头
  • 菜鸟的C#学习(二)
  • TDengine 使用最佳实践(1)
  • hot100链表(1)
  • 工业软件出海的ERP-PLM-MES一体化解决方案
  • 自动化运维工具jenkins问题
  • AI 时代的分布式多模态数据处理实践:我的 ODPS 实践之旅、思考与展望
  • 单细胞分析教程 | (二)标准化、特征选择、降为、聚类及可视化
  • 牛客网50题
  • 第14次课 认识图 A
  • docker镜像原理与镜像制作优化
  • Classifier guidance与Classifier-free guidance的原理和公式推导
  • 【STM32实践篇】:最小系统组成
  • 深入详解:决策树在医学影像领域心脏疾病诊断的应用及实现细节
  • Pytest 跳过测试技巧:灵活控制哪些测试该跑、哪些该跳过
  • 图像扭曲增强处理流程
  • 物联网设备数据驱动3D模型的智能分析与预测系统
  • frp内网穿透教程及相关配置