Linux DMA Engine framework(1)_概述

本文介绍了Linux DMA Engine框架的基本概念和术语,包括DMA channels、DMA request lines、传输参数及scatter-gather技术,为后续深入解析DMA Engine的Provider和Consumer角度的实现细节奠定基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创文章,转发请注明出处。蜗窝科技www.wowotech.net

Linux DMA Engine framework(1)_概述

作者:wowo 发布于:2017-3-30 22:01 分类:Linux内核分析

1. 前言

前面文章介绍“Linux MMC framework”的时候,涉及到了MMC数据传输,进而不可避免地遭遇了DMA(Direct Memory Access)。因而,择日不如撞日,就开几篇文章介绍Linux的DMA Engine framework吧。

本文是DMA Engine framework分析文章的第一篇,主要介绍DMA controller的概念、术语(从硬件的角度,大部分翻译自kernel的document[1])。之后,会分别从Provider(DMA controller驱动)和Consumer(其它驱动怎么使用DMA传输数据)两个角度,介绍Linux DMA engine有关的技术细节。

2. DMA Engine硬件介绍

DMA是Direct Memory Access的缩写,顾名思义,就是绕开CPU直接访问memory的意思。在计算机中,相比CPU,memory和外设的速度是非常慢的,因而在memory和memory(或者memory和设备)之间搬运数据,非常浪费CPU的时间,造成CPU无法及时处理一些实时事件。因此,工程师们就设计出来一种专门用来搬运数据的器件----DMA控制器,协助CPU进行数据搬运,如下图所示:

dma

图片1 DMA示意图

思路很简单,因而大多数的DMA controller都有类似的设计原则,归纳如下[1]。

注1:得益于类似的设计原则,Linux kernel才有机会使用一套framework去抽象DMA engine有关的功能。

2.1 DMA channels

一个DMA controller可以“同时”进行的DMA传输的个数是有限的,这称作DMA channels。当然,这里的channel,只是一个逻辑概念,因为:

鉴于总线访问的冲突,以及内存一致性的考量,从物理的角度看,不大可能会同时进行两个(及以上)的DMA传输。因而DMA channel不太可能是物理上独立的通道;

很多时候,DMA channels是DMA controller为了方便,抽象出来的概念,让consumer以为独占了一个channel,实际上所有channel的DMA传输请求都会在DMA controller中进行仲裁,进而串行传输;

因此,软件也可以基于controller提供的channel(我们称为“物理”channel),自行抽象更多的“逻辑”channel,软件会管理这些逻辑channel上的传输请求。实际上很多平台都这样做了,在DMA Engine framework中,不会区分这两种channel(本质上没区别)。

2.2 DMA request lines

由图片1的介绍可知,DMA传输是由CPU发起的:CPU会告诉DMA控制器,帮忙将xxx地方的数据搬到xxx地方。CPU发完指令之后,就当甩手掌柜了。而DMA控制器,除了负责怎么搬之外,还要决定一件非常重要的事情(特别是有外部设备参与的数据传输):

何时可以开始数据搬运?

因为,CPU发起DMA传输的时候,并不知道当前是否具备传输条件,例如source设备是否有数据、dest设备的FIFO是否空闲等等。那谁知道是否可以传输呢?设备!因此,需要DMA传输的设备和DMA控制器之间,会有几条物理的连接线(称作DMA request,DRQ),用于通知DMA控制器可以开始传输了。

这就是DMA request lines的由来,通常来说,每一个数据收发的节点(称作endpoint),和DMA controller之间,就有一条DMA request line(memory设备除外)。

最后总结:

DMA channel是Provider(提供传输服务),DMA request line是Consumer(消费传输服务)。在一个系统中DMA request line的数量通常比DMA channel的数量多,因为并不是每个request line在每一时刻都需要传输。

2.3 传输参数

在最简单的DMA传输中,只需为DMA controller提供一个参数----transfer size,它就可以欢快的工作了:

在每一个时钟周期,DMA controller将1byte的数据从一个buffer搬到另一个buffer,直到搬完“transfer size”个bytes即可停止。

不过这在现实世界中往往不能满足需求,因为有些设备可能需要在一个时钟周期中,传输指定bit的数据,例如:

memory之间传输数据的时候,希望能以总线的最大宽度为单位(32-bit、64-bit等),以提升数据传输的效率; 
而在音频设备中,需要每次写入精确的16-bit或者24-bit的数据; 
等等。

因此,为了满足这些多样的需求,我们需要为DMA controller提供一个额外的参数----transfer width。

另外,当传输的源或者目的地是memory的时候,为了提高效率,DMA controller不愿意每一次传输都访问memory,而是在内部开一个buffer,将数据缓存在自己buffer中:

memory是源的时候,一次从memory读出一批数据,保存在自己的buffer中,然后再一点点(以时钟为节拍),传输到目的地; 
memory是目的地的时候,先将源的数据传输到自己的buffer中,当累计一定量的数据之后,再一次性的写入memory。

这种场景下,DMA控制器内部可缓存的数据量的大小,称作burst size----另一个参数。

2.4 scatter-gather

我们在“Linux MMC framework(2)_host controller driver”中已经提过scatter的概念,DMA传输时也有类似概念:

一般情况下,DMA传输一般只能处理在物理上连续的buffer。但在有些场景下,我们需要将一些非连续的buffer拷贝到一个连续buffer中(这样的操作称作scatter gather,挺形象的)。

对于这种非连续的传输,大多时候都是通过软件,将传输分成多个连续的小块(chunk)。但为了提高传输效率(特别是在图像、视频等场景中),有些DMA controller从硬件上支持了这种操作。 
注2:具体怎么支持,和硬件实现有关,这里不再多说(只需要知道有这个事情即可,编写DMA controller驱动的时候,自然会知道怎么做)。

3. 总结

本文简单的介绍了DMA传输有关的概念、术语,接下来将会通过下面两篇文章,介绍Linux DMA engine有关的实现细节:

Linux DMA Engine framework(2)_provider

Linux DMA Engine framework(3)_consumer

4. 参考文档

[1] Documentation/dmaengine/provider.txt

<think>好的,用户问的是dmaengine_prep_slave_sg和dmaengine_prep_slave_single的区别,需要详细解释。首先,我需要回忆一下Linux内核中DMA引擎的相关API。这两个函数都是用来准备DMA传输请求的,但适用的场景不同。 首先,dmaengine_prep_slave_sg。SG可能代表的是scatter-gather,也就是分散-收集。这种传输方式适用于数据在物理内存中不连续的情况。例如,当应用程序有一个分散在多个缓冲区中的数据块时,使用scatter-gather可以通过一次DMA传输来处理多个分散的缓冲区,而不需要每个缓冲区都单独配置DMA传输。这样能提高效率,减少CPU的干预。 然后是dmaengine_prep_slave_single。这里的single可能指的是单个连续的物理内存区域。也就是说,当要传输的数据块在物理地址上是连续的,可以使用这个函数。它适用于数据已经存放在一个连续的内存块中的情况,比如使用kmalloc分配的内存,或者通过dma_alloc_coherent分配的内存。 接下来需要确认两者的参数区别。dmaengine_prep_slave_sg的参数应该包括一个scatterlist的数组,以及数组的长度,而dmaengine_prep_slave_single可能需要传入一个内存地址和传输长度。这涉及到struct scatterlist的使用,scatterlist用于描述分散的内存块。 另外,还需要考虑DMA传输的方向,比如是从设备到内存还是内存到设备,这两个函数应该都会处理方向参数。不过用户的问题主要是区别,所以重点在于内存是否连续。 可能还需要提到,使用scatter-gather需要硬件DMA控制器的支持。不是所有的DMA控制器都支持scatter-gather传输,因此在使用dmaengine_prep_slave_sg之前,需要确认硬件能力。而dmaengine_prep_slave_single则更基础,可能大多数DMA控制器都支持单次传输。 应用场景的例子可能会有帮助。比如,网络数据包通常由多个碎片缓冲区组成,这时使用scatter-gather传输更高效。而如果处理的是单个大块数据,比如图像缓冲区,可能更适合用single传输。 同时,性能方面,scatter-gather可以减少中断次数和上下文切换,提高吞吐量,尤其是在处理大量小数据块时。而single传输每次只能处理一个连续块,如果有多个不连续块,就需要多次调用,增加开销。 还需要检查函数的具体参数和返回值类型,确保描述的准确性。比如,两者可能都返回一个struct dma_async_tx_descriptor指针,或者可能有错误处理的不同。 最后,总结两者的主要区别在于处理的数据是否物理连续,以及对应的硬件支持情况。确保解释清晰,让用户能根据实际场景选择合适的函数。</think>在Linux内核的DMA引擎框架中,`dmaengine_prep_slave_sg`和`dmaengine_prep_slave_single`是用于准备DMA传输请求的两个关键函数,它们的核心区别在于数据传输场景的适配性。 ### 1. **`dmaengine_prep_slave_single`** - **用途** 适用于**物理内存连续**的单一数据块传输。例如,当数据通过`kmalloc`或`dma_alloc_coherent`分配时,若物理地址连续,适合使用此函数。 - **参数特点** 需要明确指定: - 内存起始地址(物理地址) - 传输长度 - DMA传输方向(如`DMA_MEM_TO_DEV`或`DMA_DEV_TO_MEM`) - **代码示例** ```c struct dma_async_tx_descriptor *tx; tx = dmaengine_prep_slave_single(chan, dma_addr, size, direction, flags); ``` - **适用场景** 传输单个连续内存块,如音频缓冲区、图像帧等。 --- ### 2. **`dmaengine_prep_slave_sg`** - **用途** 处理**物理内存非连续**的分散数据(Scatter-Gather)。通过`scatterlist`描述多个分散的物理内存块,实现单次DMA传输多个缓冲区。 - **参数特点** 需传入: - `scatterlist`数组(描述内存分布) - 数组长度 - DMA传输方向 - **代码示例** ```c struct scatterlist sg[2]; struct dma_async_tx_descriptor *tx; tx = dmaengine_prep_slave_sg(chan, sg, nents, direction, flags); ``` - **硬件依赖** 需要DMA控制器支持Scatter-Gather模式,否则需通过软件模拟(可能降低性能)。 - **适用场景** 网络数据包(多缓冲区组成)、文件I/O的分散读/写等。 --- ### 3. **关键区别总结** | 特性 | `dmaengine_prep_slave_single` | `dmaengine_prep_slave_sg` | |-----------------------|--------------------------------------|--------------------------------------| | **内存连续性** | 必须连续 | 允许非连续(通过`scatterlist`描述) | | **硬件支持** | 基础功能,普遍支持 | 需DMA控制器支持Scatter-Gather | | **性能** | 简单场景高效 | 减少多次传输开销,适合复杂数据流 | | **参数类型** | 单地址+长度 | `scatterlist`数组 | --- ### 4. **选择建议** - 若数据物理连续 → **`dmaengine_prep_slave_single`** - 若数据分散或需批量传输 → **`dmaengine_prep_slave_sg`** - 优先验证硬件支持性(通过`dma_get_slave_caps`检查`SG`能力)。 通过合理选择两者,可优化DMA传输效率并减少CPU干预。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值