Java NIO-09-零拷贝之 DMA
Posted lijianming180
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java NIO-09-零拷贝之 DMA相关的知识,希望对你有一定的参考价值。
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实现内存中数据传递
https://www.xuebuyuan.com/3235513.html
https://www.cnblogs.com/lihuidashen/p/4470678.html
以上是关于Java NIO-09-零拷贝之 DMA的主要内容,如果未能解决你的问题,请参考以下文章