1. 几种地址类型

虚拟地址

  Linux内核使用的地址是虚拟地址,数据类型为void *。例如,kmalloc()和vmalloc()函数返回值就是虚拟地址。

物理地址

  处理器真实地址总线上的地址,数据类型为phys_addr_t。

  对I/O设备寄存器和内存统一编址的处理器,如ARM/PowerPC,参考手册一般会给出memory map,也就是各种I/O设备的寄存器在物理地址空间的分布。对I/O设备寄存器独立编址的处理器。如X86,访问I/O设备寄存器或内存时,向地址总线发送地址,并通过控制信号来实现对I/O设备寄存器和内存的不同寻址。这些I/O设备寄存器的地址可以在/proc/iomem中查看,必须使用ioremap()映射到虚拟地址空间才可以使用。

总线地址

  从I/O设备的角度看,I/O设备使用的地址是总线地址。DMA使用地址也是总线地址,数据类型为dma_addr_t。对一些简单的系统,设备通过DMA可以直接访问物理地址,但大多数系统都有IOMMU将总线地址转换为物理地址。

2. DMA寻址能力

  默认情况下Linux认为设备DMA可以进行32位寻址。必须对DMA mask进行设置,将设备的DMA寻址能力通知内核。

int dma_set_mask_and_coherent(struct device *dev, u64 mask)

  该函数也可以分为如下两个函数,如果有需要,可以分别对流式映射设置DMA mask,对一致性分配设置DMA mask。

int dma_set_mask(struct device *dev, u64 mask);
int dma_set_coherent_mask(struct device *dev, u64 mask);

3. DMA映射的类型

3.1 一致性DMA映射

  一致性DMA映射通常在驱动初始化阶段分配buffer,并且保持cache的一致性。分配和释放一致性DMA buffer通常使用下面方法。

dma_addr_t dma_handle;
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp); dma_free_coherent(dev, size, cpu_addr, dma_handle)

  当分配的buffer较小,小于一个页的时候,通常使用dma_pool的APIs。

struct dma_pool *pool;
pool = dma_pool_create(name, dev, size, align, boundary);
cpu_addr = dma_pool_alloc(pool, flags, &dma_handle); dma_pool_free(pool, cpu_addr, dma_handle);
dma_pool_destroy(pool)

3.2 流式DMA映射

  流式DMA映射必须声明DMA数据流的方向。

  • DMA_BIDIRECTIONAL
  • DMA_TO_DEVICE
  • DMA_FROM_DEVICE
  • DMA_NONE

  对单个内存区域的映射和取消映射使用如下方法。

struct device *dev = &my_dev->dev;
dma_addr_t dma_handle;
void *addr = buffer->ptr;
size_t size = buffer->len; dma_handle = dma_map_single(dev, addr, size, direction); dma_unmap_single(dev, dma_handle, size, direction);

  该方法直接使用虚拟地址addr的缺点就是不能对HIGHMEM内存进行映射。下面的函数提供对page映射和取消映射的方法。

struct device *dev = &my_dev->dev;
dma_addr_t dma_handle;
struct page *page = buffer->page;
unsigned long offset = buffer->offset;
size_t size = buffer->len; dma_handle = dma_map_page(dev, page, offset, size, direction); dma_unmap_page(dev, dma_handle, size, direction);

  对散列表的映射和取消映射如下,nents是sglist中entry的数目。通过散列表,将多个不连续的内存区域进行映射。返回的count的数值可能比nents小,因为有些scatterlist在内存区域连续可能进行了合并。

int i, count = dma_map_sg(dev, sglist, nents, direction);
struct scatterlist *sg; for_each_sg(sglist, sg, count, i) {
hw_address[i] = sg_dma_address(sg);
hw_len[i] = sg_dma_len(sg);
} dma_unmap_sg(dev, sglist, nents, direction)

  在流式DMA映射取消映射之前,CPU不应该访问DMA buffer,如果需要访问,则必须在DMA传输后相应地调用如下函数。

dma_sync_single_for_cpu(dev, dma_handle, size, direction);

dma_sync_sg_for_cpu(dev, sglist, nents, direction);

  CPU访问结束后,将buffer还给设备DMA使用时,需要相应调用如下函数。

dma_sync_single_for_device(dev, dma_handle, size, direction);

dma_sync_sg_for_device(dev, sglist, nents, direction);

参考

https://elixir.bootlin.com/linux/v5.4/source/Documentation/DMA-API-HOWTO.txt

Linux动态DMA映射的更多相关文章

  1. linux kernel内存映射实例分析

    作者:JHJ(jianghuijun211@gmail.com)日期:2012/08/24 欢迎转载,请注明出处 引子 现在android智能手机市场异常火热,硬件升级非常迅猛,arm cortex ...

  2. 使用 firewalld 构建 Linux 动态防火墙

    firewalld 是新一 Linux 代防火墙工具,它提供了支持网络 / 防火墙区域 (zone) 定义网络链接以及接口安全等级的动态防火墙管理工具.它也支持允许服务或者应用程序直接添加防火墙规则的 ...

  3. linux动态库默认搜索路径设置的三种方法

    众所周知, Linux 动态库的默认搜索路径是 /lib 和 /usr/lib .动态库被创建后,一般都复制到这两个目录中.当程序执行时需要某动态库, 并且该动态库还未加载到内存中,则系统会自动到这两 ...

  4. 再探Linux动态链接 -- 关于动态库的基础知识

      在近一段时间里,由于多次参与相关专业软件Linux运行环境建设,深感有必要将这些知识理一理,供往后参考. 编译时和运行时 纵观程序编译整个过程,细分可分为编译(Compiling,指的是语言到平台 ...

  5. 技巧:Linux 动态库与静态库制作及使用详解

    技巧:Linux 动态库与静态库制作及使用详解 标准库的三种连接方式及静态库制作与使用方法 Linux 应用开发通常要考虑三个问题,即:1)在 Linux 应用程序开发过程中遇到过标准库链接在不同 L ...

  6. linux动态库加载RPATH, RUNPATH

    摘自http://gotowqj.iteye.com/blog/1926771 linux动态库加载RPATH, RUNPATH 链接动态库 如何程序在连接时使用了共享库,就必须在运行的时候能够找到共 ...

  7. Linux 动态库剖析

    进程与 API 动态链接的共享库是 GNU/Linux® 的一个重要方面.该种库允许可执行文件在运行时动态访问外部函数,从而(通过在需要时才会引入函数的方式)减少它们对内存的总体占用.本文研究了创建和 ...

  8. linux动态库编译和使用

    linux动态库编译和使用详细剖析 引言 重点讲述linux上使用gcc编译动态库的一些操作.并且对其深入的案例分析.最后介绍一下动态库插件技术, 让代码向后兼容.关于linux上使用gcc基础编译, ...

  9. Android NDK开发及调用标准linux动态库.so文件

    源:Android NDK开发及调用标准linux动态库.so文件 预备知识及环境搭建 1.NDK(native development Kit)原生开发工具包,用来快速开发C.C++动态库,并能自动 ...

随机推荐

  1. Ubuntu下配置Apache以及搭载CGI

    在Windows下自己下载应用过Apache,在Linux下也用到了服务器,就选择了Apache.Apache的安装在Ubuntu下异常简单. 1. 上网下载自动包安装 sudo apt-get in ...

  2. Eclipse CDT 插件修改自动补全

    eclipse CDT 2019-06代码补全插件 本自动补全文件已在2019-06至2019-09平台上做过测试,均已完美通过功能检测 在原来Eclipse工具补全的基础上新增26个英文字符和&qu ...

  3. STM8 ADC1连续模式切换通道干扰问题的解决

    初始化ADC1: void Init_ADC(void){ GPIO_Init(GPIOD, (GPIO_Pin_TypeDef)(GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_5|G ...

  4. IntelliJ IDEA的这个接口调试工具真是太好用了!

    你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it well enough ...

  5. 死磕java(3)

    流程控制 if else // do while// switch case// while do// break// continue// 相关查询百度

  6. mysql随机查询若干条数据

    条不重复的数据,使用以下: 秒以上 搜索Google,网上基本上都是查询max(id) * rand()来随机获取数据. SELECT *  FROM `table` AS t1 JOIN (SELE ...

  7. Educational Codeforces Round 39 Editorial B(Euclid算法,连续-=与%=的效率)

    You have two variables a and b. Consider the following sequence of actions performed with these vari ...

  8. error C2338: No Q_OBJECT in the class with the signal (NodeCreator.cpp)

    在Qt中,当派生类需要用到信号与槽机制时,有两个要求. 1.该类派生自QObject类. 2.类中有Q_OBJECT宏. 本次报错的原因就是因为没有在类中添加Q_OBJECT宏. 而我的出错原因更傻逼 ...

  9. SpringBoot2.x操作缓存的新姿势

    一.介绍 spring cache 是spring3版本之后引入的一项技术,可以简化对于缓存层的操作,spring cache与springcloud stream类似,都是基于抽象层,可以任意切换其 ...

  10. python学习(1)python的基本概念

    1.python是世界上最流行的程序语言之一,用途广泛. 2.python是解释型语言,与C++编译类语言相比,python扩展性强,简单易上手.但是缺点也很明显,执行速度慢. 3.python定义中 ...