基于PCI+Express2.0的高速网卡中DMA的设计

2018-03-29 04:34郑凯
软件 2017年8期
关键词:网卡

摘要:PCffi总线已经成为高带宽网卡与计算机通信的主流总线。而DMA控制器是实现PCIE总线高带宽应用的关键因素。本文详细阐述了基于PCIE接口的网卡中DMA引擎的接收和发送数据过程,介绍了描述符机制。本文提出了基于PCIE接口的网卡DMA的设计方案,并详细说明了其中的实现难点和各子模块的功能。本文还提出了影响DMA性能的主要因素和改进方向。

关键词:网卡;DMA机制;PCIExpress

中图分类号:TP334.7文献标识码:ADOI:10.3969/j.issn.1003-6970.2017.08.041

本文著录格式:郑凯.基于PCI+ExpressZO的高速网卡中DMA的设计[J].软件,2017,38(8):204-209

引言

高性能高可靠性的网络接口卡是大型数据中心服务器直连高速网络的关键部件。PCI Express2.0提供的最高单位通道速率已可达5.0Gb/s。使用该总线的网卡能适应更高速度、更高带宽网络的需要。高速网卡通过直接内存访问机制(即DMA机制)来进行主机和网络直接的数据交互。在DMA机制中,数据传输无需CPU的介入,大大降低主机的工作负担。在主流的以PCIE为总线接口的网卡中,如何利用DMA机制来充分利用PC正总线的高带宽特性,实现网卡和主机间的高速数据传输是目前的一个研究热点。

DMA控制器是随着DMA机制在网卡中的应用而出现的,DMA控制器的主要功能是通过硬件数据通路完成主机和网卡之间的数据交互。设计一个高效合理的DMA控制器首先需要理解DMA机制下的工作原理和传输数据的关键机制。并且需要了解软件驱动程序和硬件网卡高效传输数据的交互过程。能否实现软硬件协同高效工作,也是DMA设计好坏的一个指标。为了更好的应用PCIE总线的特性,要充分了解PCIE总线协议和数据传输的形式。本文正是由以上思路来展开对论文的阐述。

1DMA的关键机制和工作流程在网卡采用的DMA方式下,网卡在发送和读写前必须知道其读写的内存地址,DMA控制器中接收和发送描述符的设计便是为DMA提供读写主存的地址和其他控制信息。

1.1 接收和发送描述符队列

DMA控制器包含了两个描述符队列即接收和发送描述符队列。描述符队列的设计正是为了提高系统的性能和总线带宽利用率。在主机的主存中也存在着同样的两个队列的映射。

1.2 接收和发送描述符队列

DMA控制器包含了两个描述符队列即接收和发送描述符队列。描述符队列的设计正是为了提高系统的性能和总线带宽利用率。在主机的主存中也存在着同样的两个队列的映射。

如图1为主存中发送描述符队列示意图,队列中每个描述符中的地址信息被配置为一个待发送数据缓存的基地址。其中Base为这个描述符队列存放在主存中的基地址,Size为队列长度,Head指针指向此队列中配好的第一个可用描述符,Tail指针指向此队列中CPU配好的最后一个可用描述符。

发送描述符的组成结构如图2所示。其中,Datalength域为待发送数据的长度,由CRJ来配置;RdAddr域为主存中待发送数据缓存的基地址。Own位由CPU置为0,表明为此描述可被DMA控制器使用;被硬件置为1,表明此描述符已经被DMA控制器用掉,需要被CPU重新配置。

1.3 高速网卡中DMA数据发送流程

(1)CPU在主存中创建了一个发送描述符队列,并且把该队列在主存中的起始位置,队列长度和头尾指针(初值都为0)写到网卡中的相关寄存器中去。

(2)CPU被协议栈请求发包,它把包存放在一个缓存区或多个缓存区中。

(3)CPU初始化描述符队列中的描述符,将其指向待发送的数据缓存区。

(4)主机准备好了可用的描述符,并及时更新网卡中的队列尾指针寄存器。

(5)网卡中的DMA通过查看头尾指针寄存器的值,知道主存中有可用描述符,进而通过PCIE接口发起一次为获取描述符的存储器读请求。

(6)描述符以PCffi读完成报文的形式被网卡接收并且存放到网卡中的专门位置。

(7)DMA读出描述符中存放的读主存地址和长度等信息,通过PCIE总线发起一次为获取主存中待发送数据的存储器读请求。如果读取长度大于PCIE总线的最大读请求长度,还会分割为几次读请求发出。

(8)主存中的数据包被以PCIE完成报文的形式传送到网卡中。

(9)当整个数据包存放到本地网卡后,DMA会通过PCIE总线向主存发起一次存储器写请求,来回写主存中被网卡刚用过的描述符。

(10)DMA会发起一次中断,通知主机驱动,数据包已经被读到网卡中,驱动可以释放刚才的数据缓存。

1.3 高速网卡中DMA数据接收流程

(1)CPU在主存中创建了一个接收描述符队列,并且把该队列在主存中的起始位置,队列长度和头尾指针(初值都为0)写到网卡中的相关寄存器中去。

(2)主机将队列中的描述符指针指向空的缓存,并且更新了网卡中尾指针寄存器的值。

(3)接收DMA通過查看尾指针寄存器,获知主存中有可用接收描述符,通过PCIE总线发出存储器读请求来获取主存中的接收描述符。

(4)接收描述符通过PC正总线以读完成报文形式返回并被存放在网卡中的适当位置。

(5)网络的数据包进入接收MAC,并通过过滤模块后进入接收FIFO中。

(6)当网卡接收到一个完整包时,会发起数据传输请求。DMA读取描述符中的写主存地址并且根据数据包长度来进行切割请求,发起若干个存储器与请求。

(7)等一个完整的数据包都写到主存,DMA可以回写本地描述符中的数据包长度,并将own位置为1,表示此描述符已经用完。

(8)DMA通过PCIE接口,将回写后的本地描述符组装成存储器写请求,来回写刚用掉的对应主存中的描述符。

(9)网卡产生一个中断通知主机一个新的数据包已经被接收到主存,等待處理。

(10)主机读取这个数据包并把它送到TCP/IP协议栈进行进一步处理。

(11)主机释放掉相关的缓存,并通过查看主存中描述符的状态位确定哪些描述符已经被用,并重新分配描述符。

2 基于PCIE接口的DMA设计

PCIExpress总线采用了一种类似网络报文的形式来进行传输。在PCIExpress协议中,隐藏了地址线、数据线,以及中断信号等边缘信号。所有信息以传输层报文TLP(Transaction Layer Packet)进行传输。TLP与TCP/IP很相似,在报文中同样也具有报文头和载荷:报文头是由代表不同传输信息的字段组成,如报文长度、报文传输地址等;而载荷则由传输的数据构成。

PCIE的DMA读/写操作实现的主要方法是将TLP包头中的各个字段正确填充,并将数据按照64bit或者32bit并行放在TLP包头后,按照64bit或者32bit并行传输给PCffi核,由PCE核以PCIE协议串行传输给主机。

2.1 系统设计架构和模块划分

结合高速网卡高效的数据收发流程,以及对PCIE总线协议的了解,本文提出了DMA控制器的设计方案。如图3为基于PCIE总线的高速网卡中,DMA控制器的设计架构图。其中PCIE接口采用了赛林思的PCIE核。

在DMA接收方向上大概的数据路径依次是:网络中的数据包通过RxMAC模块进入网卡,被包过滤模块过滤后,存放到接收缓存控制模块的DataFIFO中,通过接收引擎送入PCIE接口,并最终写入主存中去。

在DMA发送方向上大概的数据路径依次是:主存中的数据通过PCIE接口传入网卡,在发送引擎中被解析后送到发送缓存控制模块,并通过数据成帧模块形成网络报文,最终通过TXMAC模块送到网络中去。

在数据接收和传送过程中,都要用到描述符,它们被存放在各自的FIFO中。

DMA的主要模块包括接收引擎和发送引擎,以及描述符和寄存器读写模块。

2.2 接收引擎功能详述

接收引擎需要向PCIE核发送存储器写/读请求和完成包,本设计支持以上三种包类型的产生。其中存储器写请求是用来向主存写入网卡接收到的网络报文。

存储器读请求主要上有两种用途:一是用来读取主存中待发送的数据;二是用来读取主存中准备好的描述符,包括接收和发送描述符。

完成报文主要是为了回应主机对网卡中某些寄存器的读操作。

为了产生这三种报文,接收引擎内部设计了专门的产生三种报文的模块:即存储器写请求(MWr)组包模块,存储器读请求(MRd)组包模块,完成报文(Comp)组包模块。

2.2.1 存储器写请求(MWr)切片和组包模块

PCIE总线协议规定最大存储器写请求的数据载荷长度是4K字节。但是在大部分实际系统中,最大存储器写请求长度为128字节或者256字节。因此传送长度较长的网络报文需要分割为几次存储器写请求。

存储器写请求(MWr)切片模块就是根据接收到的报文长度进行切割。当已经接收到一个完整的报文,并且接收描述FIFO不空时,切片模块读入描述符FIFO中的写主存地址,并读取CtrlFIFO中的报文长度,随后进行写请求的分割。分割的原则是一次读请求不能跨越主存地址的4k边界,并且一次请求的长度不超过最大请求长度。

存储器写请求切片模块将每次切割的写请求长度和写主存地址送入存储器写请求包头组装模块,进行包头的组装。组装后的存储器写请求包头会被存放到存储器写请求包头FIFO中去。

2.2.2 存储器读请求(MRd)切片和组包模块

存储器读请求切片模块和存储器写请求切片模块大体相似,但是它需要完成更多的任务。上文中提到存储器读请求要完成对主存中描述符的读取。这需要通过查看网卡中的发送/接收描述符尾指针寄存器。

当网卡中的尾指针寄存器有变化时,网卡需要计算两次变化的差值并结合发送/接收描述符队列基地址等信息,组成一次存储器读请求。如果这次读取的描述符的数目很多,使读取长度大于最大读请求长度,就会分割为多次存储器读请求。每次切割后,将相关信息送入存储器读请求组包模块中,生成多个存储器读请求并被存放到读取发送/接收描述符请求FIFO中去。

同样,为了完成对主存中待发送数据的读取,还需要查看发送描述符FIFO。如果发送描述FIFO不空,就会将描述符FIFO中的读主存地址和数据长度读入存储器读请求切片模块进行切割。

如果CPU刚刚更新了网卡中发送描述符的尾指针寄存器,并且这时发送描述符FIFO也不空,就需要对两种切割任务的仲裁。当发送描述符FIFO中的描述符数目不小于一个最少值时,我们优先发起获取主存待发送数据的读请求。当发送描述符FIFO中的描述符小于一个最小值时,我们要首先发起获取新的发送描述符的读请求丁作。

在存储器读请求组包模块中,我们通过存储器读请求中的标签号(Tag号)来区分三种不同的读请求,以便在接收它们对应的完成报文时能分类存放和管理。因此Tag号的管理是一个非常重要的问题。

2.2.3 完成报文(Comp)组包模块

如果主机想了解网卡中寄存器的相关信息,会发出存储器读请求,这时网卡就要回复一个完成报文。其中完成报文的切片操作是由发送引擎中解析到存储器读请求来触发的。其中,完成报文包头中的完成标号(completeId)等信息需要从PCIE核的配置接口来获知。

2.2.4 仲裁模块

当各种请求的包头FIFO都不空时,我们需要进行对事务层报文(TLP)的接收进行仲裁。在本设计中,我们采用加权轮询分时的方法对三种TLP报文请求进行调度。加权轮询(Weighted Round Robin)是為了解决不同任务间的调度平衡问题,而通过为各个任务设置不同权重值,以权重值来组织各个任务的执行时间,从而达到调度的合理性。

当传输开始时,在传输模块中分别有两个计数器负责对读写请求计数,当请求次数达到权重值,则将该请求计数器清零,跳入另一请求周期,如此反复直到传输完毕。采用这种分时方式的好处是,用户可根据传输的输出吞吐的特点对传输进行配置。

2.2.5 接收状态机

这个状态机负责通过接收传输接口把TLP报文送给PCIE核。当要发起传输时,它要从存放各种TLP报文包头FIFO中读出包头信息先存到寄存器中,然后在状态机的控制下发送出去。

这个状态机模块负责产生一次完整的DMA传输结束信号,回写描述符FIFO中相应的信息,并将回写后的本地描述符组装成存储器写请求送人到PCIE核。

中断逻辑也是在这个模块产生的。接收状态机负责产生中断通知CPU刷新已使用的主存中相应描述符。

这个状态机主要部分是传输状态的产生逻辑和每种传输状态下要分类传送数据的逻辑。当包头组装模块中某种存储包头的fifo不空时,状态机状态开始调转,进入传送某种TLP包的状态。

2.3 发送引擎功能详述

2.3.1 发送状态机

发送状态机用来解析主机发送到网卡的TLP报文类型,把收到的不同类型的数据送到各自对应的FIFO缓存。当有存储器读请求时,要向接收引擎传送发起完成包的请求。

2.3.2 发送检测模块

发送检测模块的功能主要有:

(1)检测一次读请求发起的完成包的结束,以释放Tag资源。

(2)检测完整的一次DMA读请求是否完成。

(3)检测收到的完成包是否正确。

(4)产生中断,通知CPU刷新已使用的主存中相应描述符,并通知接收引擎发起回写主存描述符的存储器写请求。

2.3.3 数据缓存状态机

PCIE协议规定一次读请求的完成包是按序收来的,但是后一次的读请求对应的完成可能比一次读请求对应的完成来的早。因此接收到的完成包的顺序不一定是对应发出的读请求的顺序,所以当存到SRAM里时要有一个存放排序的问题,根据完成包的tag标签来分配存放地址。

数据缓存状态机就是要计算每个完成包要存放的起始地址和存放顺序。

2.4接收和发送描述符FIFO和寄存器模块从主存中获取的发送和接收描述符被分别存放在网卡中的发送和接收描述符FIFO。描述符的获取和正确存放是实现DMA高效工作的必要条件。CPU通过PCIE总线将一些DMA相关寄存器信息写到本地网卡中的DMA寄存器模块。

3 实现难点和性能改进方向

3.1 DMA读写对界问题

PCIE接口的TLP报文的数据载荷长度是以双字为单位因此需要要求PCIE存储器读写请求的地址都以双字对齐。而网络报文的长度不一定能被双字整除,因此在报文的包头填写时需要做细致的处理,以实现数据对界的要求。

为此我们采用了向前X字节对界和向后X字节对界的方法操作来处理对界问题。

3.2 对存储器读完成TLP的乱序处理

在PQE总线中,一个存储器读请求可以对应几个完成报文。设备发出的存储器读请求可以超越之前发出的存储器读请求。而且当存储器完成报文使用的Transaction ID不同时,存储器读完成TLP也可能超越之前的存储器读完成TLP,这将造成存储器读完成TLP乱序到达网卡。

但是我们要充分利用存储器读请求和其对应的完成报文的Tag号相同的特点,以及同一个存储器读请求对应的完成报文是按地址顺序依次到达的。

为了实现对乱序存储器读完成报文的接收,我们在DMA中采用了一块SRAM对完成报文进行存储。并且用一个小的RAM来对完成报文的存放顺序做管理。我们以Tag号对这块RAM进行编址,每个Tag号对应的entry中填入这个读请求对应完成报文存到SRAM的起始存放地址。这个起始地址是以每个Tag号对应的发送读请求的先后顺序来安排的。

当这个读请求对应的一个完成报文到达后,要及时根据这个完成报文的长度,对这个RAM对应的entry进行更新,递增其目的存放地址,以便接收此存储器读请求对应的下一个完成报文。当确认这个存储器读请求对应的完成报文都已接收完成后,这个存储器读请求的Tag号对应的Entry会被标记。并且这个Tag号会被其他存储器读请求再次使用,否则其它存储器读请求不能使用这个Tag号。

当SRAM中的一个数据报文发送到网络中后,已发送报文的存储起始地址和报文长度会送到报文管理模块,以便让下一次存储器读请求返回的完成报文来使用。

3.2 DMA性能改进的方向

本文中的DMA是每当往主存写好一个完整包后,就会向主机发出一次中断。当网络上的小报文集中大量涌入网卡时,会使网卡产生的接收中断过于频繁,导致CPU在没有完成一次接收中断处理的时候又有需要处理的接收中断,CPU就会疲于处理接收中断而没有时间对接收数据做进一步处理。

这需要我们可以不再以接收一个包来发出中断。而是等一定量的数据块(例如1K字节的包)写到主存后,再发出中断。但是这会大大增加DMA控制器硬件的复杂度。因为需要很多逻辑去解析这次接收的定量数据块中含有数据报文的数目。因为CPU是以一个数据报文为单位来进行处理。

另外描述符的设计上,多队列描述符会比单队列描述更能提高DMA控制器的性能。目前,市场上大多数采取描述符机制的网卡使用的是传统的单队列接收描述符。虽然服务器[11-12]的内存可以配置到1GB以上,但对于越来越复杂的应用程序来说服务器内存仍然是紧缺资源。所以在描述符机制中分配给接收描述符的接收数据的缓冲区空间总量不会太大,而为了提高高速网卡的性能,接收描述符的数量当然是越多越好。这就需要在固定容量的缓冲区空间条件下开发更多个数的接收描述符。多对列描述符机制在同样缓冲空间大小下能够获得更多的接收描述符,从而提高了网卡的性能。

猜你喜欢
网卡
在DDS 中间件上实现双冗余网卡切换的方法
部署Linux虚拟机出现的网络故障
Server 2016网卡组合模式
验证链路聚合
双网卡叠加 提高网络性能
读编往来
无线网卡种类有什么区别?
RHEL7 Network Teaming(网卡绑定)配置与测试
USB故障又一原因
如何屏蔽集成声卡显卡和网卡