DMA 的好处

在介绍DMA之前我想问大家:我们为什么要引入DMA,DMA对我们有什么好处那?

计算机系统中各种常用的数据输入/输出方法有查询方式(包括无条件及条件传送方式)和中断方式,这些方式适用于CPU与慢速及中速外设之间的数据交换。

但当高速外设要与系统内存或者要在系统内存的不同区域之间进行大量数据的快速传送时,就在一定程度上限制了数据传送的速率。

直接存储器存取(DMA)就是为解决这个问题提出的,采用DMA方式,在一定时间段内,由DMA控制器取代CPU,获得总线控制权,来实现内存与外设或者内存的不同区域之间大量数据的快速传送。

同时很重要的一点是当DMA传输数据时,并不占用CPU资源,在这个时候CPU可以空出手来做其他的事情。

这样我们既可以做大量数据的高速传输又可以让CPU有时间和资源去做其他的事情。

DMA 芯片的实现

上面介绍了什么是DMA,也介绍了DMA的重要性。那么我们就要看看我们芯片中的DMA了。

在S3C2440A中,我们集成了DMA模块,可以用来传递高速传输数据。既然是数据传输那么我又要问了,我们知道数据传输三要素:源,目的,长度。这是我们数据传输时要知道的。那么在S3C2440A中,源,目的,长度是怎么表示的那?

ps: 硬件知识,暂时不做研究。

DMA映射

基本原理

DMA映射主要为在设备与主存之间建立DMA数据传输通道时,在主存中为该DMA通道分配内存空间的行为,该内存空间也称为DMA缓冲区。

这个任务原本可以很简单,但是由于现代处理器cache的存在,使得事情变得复杂。

RAM与cache内容的一致性问题

出现问题原因

现代处理器为了提升系统性能,在CPU与RAM之间加入了高速缓存cache,所以当在RAM中为一个DMA通道建立一段缓冲区时,必须仔细考虑RAM与cache内容的一致性问题。

具体分析

如果RAM与Device之间的一次数据交换改变了RAM中DMA缓冲区的内容,而cache中缓存了DMA缓冲区对应的RAM中一段内存块。

如果没有机制保护cache中的内容被新的DMA缓冲区数据更新(或者无效),那么cache和他对应的RAM中的一段内存块在内容上出现了不一致,此时如果CPU去读取device传到RAM的DMA缓冲区中的数据,它将直接从cache获得数据,这些数据显然不是它所期望的,因为cache对应的RAM中的数据已经更新了。

解决问题

就cache一致性问题,不同的体系架构有不同的策略,有些是在硬件层面予以保证(x86平台)有些没有硬件支持而需要软件的参与(ARM品台)。

Linux内核中的通用DMA尽力为设备驱动程序提供统一的接口来处理cache缓存一致性的问题,

而将大量品台相关的代码对设备驱动程序隐藏起来。

DMA 的映射方式

1. 一致性DMA映射

linux内核DMA层为一致性DMA映射提供的接口函数为dma_alloc_coherent()

一致性所获得的DMA缓冲区的大小都是页面的整数倍,如果驱动程序需要更小的DMA一致性的DMA缓冲区,则应该使用内核提供的DMA池(pool)机制

对于一致性DMA映射,在分配DMA缓冲区时各平台相关代码已经从根本上解决了cache一致性问题.

但是,一致性映射也会遇到无法克服的困难,主要是指驱动程序中使用的DMA缓冲区并非由驱动程序分配,

大专栏  Java NIO-09-零拷贝之 DMA是来自其他模块(如网络设备驱动程序中用于数据包传输的skb->data所指向的缓冲区),此时需要流式DMA映射。

2. 流式DMA映射

流式DMA映射的特点是DMA传输通道使用的缓冲区不是由当前驱动程序自身分配的,而且往往对每次DMA传输都会重新建立一个流式映射的缓冲区,所以使用流式DMA映射时,
设备驱动程序必须小心负责处理可能出现的cache一致性。

linux内核DMA层为设备驱动提供的建立流式DMA映射的函数—dma_map_single

3. 分散/聚集DMA映射

分散/聚集DMA映射通过将虚拟地址上分散的DMA缓冲区通过一个struct scatterlist的数组或链表组织起来,然后通过一次的DMA传输操作在主存RAM与设备之间传输数据。

分散/聚集DMA映射本质上是通过一次DMA操作把内存中分散的数据块在主存与设备之间进行传输,对于其中的每个数据块内核都会建立对应的一个流式DMA映射。

需要设备的支持。

回弹缓冲区

如果CPU侧虚拟地址对应的物理地址不适合设备的DMA操作,那么需要建立回弹缓冲区,相当于一个 中转站,把数据往设备传输时,驱动程序需要把CPU给的数据拷贝到回弹缓冲区,然后再启动DMA操作。

DMA池

由于DMA映射所建立的缓冲区是单个页面的整数倍,如果驱动程序需要更小的一致性映射的DMA缓冲区,可以使用内核提供的DMA池机制(非常类似于Linux内存管理中的slab机制).

个人收获

参考资料

嵌入式Linux——DMA:在内核中简单使用DMA实现内存中数据传递

Linux内核中DMA分析

Linux DMA驱动构架分析

https://www.xuebuyuan.com/3235513.html

https://www.cnblogs.com/lihuidashen/p/4470678.html

Java NIO-09-零拷贝之 DMA的更多相关文章

  1. NIO 与 零拷贝

    零拷贝介绍 零拷贝是网络编程的关键, 很多性能优化都需要零拷贝. 在 Java程序中, 常用的零拷贝方式有m(memory)map[内存映射] 和 sendFile.它们在OS中又是怎样的设计? NI ...

  2. 【Java】Java中的零拷贝

    物理内存 计算机物理内存条的容量,比如我们买电脑会关注内存大小有多少G,这个容量就是计算机的物理内存. 虚拟内存 操作系统为每个进程分配了独立的虚拟地址空间,也就是虚拟内存,虚拟地址空间又分为用户空间 ...

  3. Linux、JDK、Netty中的NIO与零拷贝

    一.先理解内核空间与用户空间 Linux 按照特权等级,把进程的运行空间分为内核空间和用户空间,分别对应着下图中, CPU 特权等级分为4个,Linux 使用 Ring 0 和 Ring 3. 内核空 ...

  4. Java IO和Java NIO在文件拷贝上的性能差异分析

    1.  在JAVA传统的IO系统中,读取磁盘文件数据的过程如下: 以FileInputStream类为例,该类有一个read(byte b[])方法,byte b[]是我们要存储读取到用户空间的缓冲区 ...

  5. 框架篇:Linux零拷贝机制和FileChannel

    前言 大白话解释,零拷贝就是没有把数据从一个存储区域拷贝到另一个存储区域.但是没有数据的复制,怎么可能实现数据的传输呢?其实我们在java NIO.netty.kafka遇到的零拷贝,并不是不复制数据 ...

  6. 零拷贝详解 Java NIO学习笔记四(零拷贝详解)

    转 https://blog.csdn.net/u013096088/article/details/79122671 Java NIO学习笔记四(零拷贝详解) 2018年01月21日 20:20:5 ...

  7. 零拷贝的原理及Java实现

    在谈论Kafka高性能时不得不提到零拷贝.Kafka通过采用零拷贝大大提供了应用性能,减少了内核和用户模式之间的上下文切换次数.那么什么是零拷贝,如何实现零拷贝呢? 什么是零拷贝 WIKI中对其有如下 ...

  8. NIO零拷贝的深入分析

    深入分析通过Socket进行数据文件传递中的传统IO的弊端以及NIO的零拷贝实现原理,及用户空间和内核空间的切换方式 传统的IO流程 在这个过程中: 数据从磁盘拷贝进内核空间缓冲区 从内核空间缓冲区拷 ...

  9. 转载一篇关于kafka零拷贝(zero-copy)通俗易懂的好文

    原文地址 https://www.cnblogs.com/yizhou35/p/12026263.html 零拷贝就是一种避免CPU 将数据从一块存储拷贝到另外一块存储的技术. DMA技术是Direc ...

  10. kafka零拷贝

    Kafka之所以那么快的另外一个原因就是零拷贝(zero-copy)技术.本文我们就来了解Kafka中使用的零拷贝技术为什么那么快. 传统的文件拷贝 传统的文件拷贝通常需要从用户态去转到核心态,经过r ...

随机推荐

  1. HTML5中的data-*属性

    data-* 属性包括两部分: 属性名不应该包含任何大写字母,并且在前缀 "data-" 之后必须有至少一个字符: 属性值可以是任意字符串: 注释:用户代理会完全忽略前缀为 &qu ...

  2. windows安装theano和keras

    系统: Windows 2008 python版本: Anaconda3 1. theano 安装 pip install theano 2. 安装g++ 下载安装mingw, 推荐版本tdm64-g ...

  3. vi几个常用的命令

    1.同时打开多个文件:vi 1.txt 2.txt 3.txt 在多个文件中来回切换,命令行模式输入“:next"表示下一个,输入":previous"代表进入上一个,” ...

  4. Matlab高级教程_第三篇:Matlab转码C/C++方式(混编)_第二部分

    这一部分通过一些实例来进行转码和调试的讲解: 1. 输入变量.输出变量和过程内变量的内存预分配 函数代码:函数名test function [A,B] = test( mark,num,array ) ...

  5. python版本不同,修改cmd下的默认版本

    原文出处 https://blog.csdn.net/zyx_ly/article/details/93137014  感谢博主分享 即修改系统环境变量的位置,把想设置成为默认的上移即可

  6. win10//ubuntu安装tensorflow-gpu与kears,并用minist测试

    WIn10 安装cuda 先安装VS,然后根据自己的版本安装CUDA. 安装完后,打开cmd命令行输入nvcc -V,检测是否安装成功 安装cuDDN 安装对应版本,解压后覆盖到CUDA的地址,默认为 ...

  7. 允许外部访问Windows本机的指定端口

    背景:目前公司有一台公网Windows服务器,有公网IP和内网IP,防火墙已开启 需求:9999端口需要对外开放 方案:在防火墙的入站规则里添加一条规则,使外部能够访问9999端口 问题:添加好规则后 ...

  8. BigDecimal不整除的一个异常java.lang.ArithmeticException

    转载地址:http://blog.csdn.net/jobjava/article/details/6764623 金额的数据类型是BigDecimal 通过BigDecimal的divide方法进行 ...

  9. 84)PHP,SQL注入基础讲解

     怎么预防: 填写防止SQL注入的代码:

  10. spring boot 配置文件properties和YAML详解

    spring boot 配置文件properties和YAML详解 properties中配置信息并获取值. 1:在application.properties配置文件中添加: 根据提示创建直接创建. ...