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. 关于MySQL5.6配置文件my-default.ini不生效问题

    一.问题描述 首先,由于工作要求,需使用MySQL5.6版本(绿色版),从解压到修改root密码,一切都很顺利,但是在我要修改mysql的最大连接数的时候,出现问题了,配置不生效.完蛋.还好有万能的百 ...

  2. 光流法draw_flow()函数报错

    光流法draw_flow()函数报错 import cv2 from scipy import * def draw_flow(im, flow, step=16): ""&quo ...

  3. ios--->self.view.window在逻辑判断中的作用

    - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that ...

  4. linux--->阿里云centos6.9环境配置安装lnmp

    阿里云centos6.9环境配置安装lnmp mysql安装 本人博客:http://www.cnblogs.com/frankltf/p/8615418.html PHP安装 1.安装依赖关系 yu ...

  5. mybatis入门案例自定义实现

    mybatis入门案例自定义实现 一.需要实现的类和接口 public static void main(String[] args) throws Exception{ //1.读取配置文件 Inp ...

  6. oracle问题之数据库恢复(三)

    可能很多人在做数据库恢复时,都遇到过如下错误: SQL> recover database; ORA: recovery session canceled due to errors ORA: ...

  7. mod3 如何用硬件实现

    今天接到Qualcom 的电话面试,表现很一般.Qualcom 不愧是一流的IC 设计公司,问得问题非常基础,但是非常深入! 其中问了一个如何实现模3 的问题.没有回答上来. 后来想了一下,其实非常简 ...

  8. python书籍推荐以及杂七杂八

    黄哥推荐学习Python 10本好书 Python3网络爬虫开发实战 github daily-reading 想对大家说的话 POJ 算法练习 http://openjudge.cn/ http:/ ...

  9. Codeforces_334_C

    http://codeforces.com/problemset/problem/334/C 求不能凑整n,和最小,数量最多的数量. #include<iostream> #include ...

  10. Java并发读书笔记:如何实现线程间正确通信

    目录 一.synchronized 与 volatile 二.等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 三.等待通知典型 生产者消费者模型 ...