DMA实现架构浅析

时间:2022-05-28 18:30:32

无论是我们平时台式机使用的网卡还是在存储系统中高速读写的磁盘,都离不开一个feature的支持那就是DMA。但是很多同学都只是听说过这个名词或对这名词理解仅停留在大学课本的8237 DMA芯片上,所以今天特地来写写DMA,和大家一起来探讨究竟什么是DMA,这个东西究竟包含了哪些东西,以及DMA的具体实现上有哪些不同。

What is DMA

Direct memory access (DMA) is a feature of computer systems that allows certain hardware subsystems to access main system memory (RAM) independently of the central processing unit (CPU).

从以上定义中我们看出DMA就是要使得一个硬件子系统来直接访问系统内存,并且不占用CPU的运算能力把CPU解放出来。
DMA本质上是一种功能,不是一种具体实现。所以如果要研究DMA的框架就必须从不同DMA的实现当中去寻找答案。
要弄清DMA的实现我们先要把系统中的单元抽离出来,把这些基本单元识别清楚再去分析。

  1. device:如一块网卡,一个硬盘,一个USB鼠标
  2. host controller: 控制设备,和设备直接打交道的单元,如PCIe的root complex,USB controller, SATA contoller,这种单元一般都是固化在主机的主板上或是SOC,CPU内部。
  3. system memory:主机的内存,一般就指DRAM。
  4. bus:分为device and HC之间的总线和HC and system memory之间的总线

但是非要从以上四个主要部件来说究竟是哪一部分实现了DMA,我觉得还要具体case具体分析,一概而论都是片面且不准确的,就像网络的可靠传输,可以通过HDLC之类的协议在L2实现也可以通过TCP在L4实现更可以通过L7来实现。
所以今天DMA架构的剖析就通过四个cases来说说不同的device subsytem中究竟是哪部分实现了DMA

case 1:8237 DMA controller
DMA实现架构浅析

从这个图中其实会看到专门有个DMAC的DMA 8237 controller来实现DMA的feature,之所以在前面的四大components中没说它是因为现在的系统中一般都不会单独出现它的身影,所以在case1 的原始架构中,我们看到其实device是可以不感知DMA但是host必须要感知和配置DMAC。这边我们所说的DMAC和实现DMA的engine必须要有直接访问物理device资源的能力和能产生访问system memory的请求。host通过IO去配置DMAC,使得DMAC根据配置去把device上的数据搬移到指定的system memory。有了这最基本的DMA controller or DMA engine的实现分析后,我们来看看现有的设备究竟把这个DMAC藏在了哪里。

case 2:把DMAC放到设备内部 PCIe的NIC
我们常用的PCIe的NIC就属于有一个DMAC在NIC内部。
1.访问system memory的请求
NIC里的DMAC 通过读指定物理地址里的descriptor根据指定格式去解析里面的内容就能访问到host想要NIC访问的物理内存
2.访问device的资源
NIC的DMAC会通过NIC内部的ASIC去读写NIC内部的frame buffer,此buffer直接和收发报文相关联或存储收发报文。
3.访问system memory时使用的bus
NIC的DMAC会通过发起PCIe的memory read和 memory write到PCIe的controller(root complex)去请求对应的system memory,此处认为root complex又是挂在cpu的内部总线上的,所以发给root complex的请求通过其转化又能通过内部总线请求到system memory。不过此处的PCIe bus和internal bus都只是提供了一个物理通路去完成请求,DMAC更侧重产生这个请求

case 3:把DMAC放到host controller内部 SATA
我们常用的SATA的controller就属于一个自带DMAC的controller
1.访问system memory的请求
此类请求由SATA的controller产生
2.访问device的资源
controller会通过SATA的FIS(frame information structure)去访问SATA硬盘的资源,但是这边要说一点,这边虽然DMAC不在device里面,但是device是有和DMA匹配的相关操作的也就是说device需要感知DMA操作。这边的感知是指SATA device和SATA controller之间的bus会有一种属于DMA的特殊的bus访问协议
原因如下
SATA和PATA中分为PIO和 DMA两种device访问方式。
当使用PIO时,CPU会去一个byte一个byte去一个叫data register的寄存器里面去读取数据,读取一个就自动往data register里面更新一个数据。
而DMA模式下是去读另外个叫data port的register并且整个操作流程如检查一些标志位上也是有区别的(我估计在DMA模式下device controller和device之间的传送速度会更快)。SATA controller和sata device之间的DMA模式是有标准化的但是DMAC怎么被host去配置然后把SATA的DMA协议中取到的数据转移到system memory里面这部分没标准话。所以不同的SOC或SATA控制器在描述这部分system memory相关的操作时的寄存器或是描述符是没有标准的这使得整体driver很能通用化。
3.访问system memory时使用的bus
一般此类controller会是一个PCIe的controller,所以bus的使用情况参照case2

case 4:把DMAC放到host controller内部 USB
这边和SATA的区别在于usb controller以OHCI为例,所有的controller要访问什么system memory都是标准里面通过ED(endpoint descriptor)和TD(tranfer descriptor)来定义的。这个就不用担心不同controller和driver不兼容了。
如果是sata driver不同的soc一般情况下操作都不一样,但是usb 的controller即使厂家不同只要follow spec的话是可以做到driver通用的 :)

分析了以上一些具体实现就是要让大家明白,DMA是一个数据搬移的feature这个feature需要实现两大功能支持,产生请求和读写device的资源,但是根据不同的设备和总线,这两大功能可以分布在不同的单元中,并且具体的操作方式也包含标准化的和非标准化的两种,如果以后要设计新DMA架构时就可以从标准化和DMAC不同的放置位置两方面来考虑你的设计。