PCIe概述

PCI-Express(peripheral component interconnect express)是一种高速串行计算机扩展总线标准,由PCI发展过来,其中的“express”是“快”的意思。

目前PCIe已经发展到PCIe4.0阶段,速度越来越快。PCIe采用点到点的通信方式,每个设备独享通道带宽,速度和效率都比PCI好。

PCIe各代的双向带宽如下表所示,双向带宽即读写带宽,单论读或写该值减半。

链接速度(双向带宽) ×1 ×2 ×4 ×8 ×12 ×16 ×32
Gen1带宽(GB/s) 0.5 1 2 4 6 8 16
Gen2带宽(GB/s) 1 2 4 8 12 16 32
Gen3带宽(GB/s) 2 4 8 16 24 32 64
Gen4带宽(GB/s) 4 8 16 32 48 64 128

PCIe1.0和PCIe2.0均采用8/10编码格式,即传输8bit的数据,实际上物理线路需要传输10bit,多余2bit数据用来校验,这样就浪费了20%的资源。而PCIe3.0和PCIe4.0采用128/130格式编码,有效数据带宽大大增加。

PCIe使用串口传输,而不是PCI的并行传输。

PCIe结构

拓扑结构

计算机网络主要拓扑结构有总线型拓扑、环形拓扑、树形拓扑、星形拓扑、混合型拓扑和网状拓扑。

PCIe采用的是树形结构(PCI采用的是总线型拓扑结构),如图所示:

PCIe拓扑结构

其中最核心的是Root Complex(根复合体),它为CPU代言,并与计算机其他设备通信。它内部一般是一条PCIe总线,以及若干个PCI bridge,并拓展出若干个PCIe Port。

Root Complex连接了内存、Switch、PCIe终端设备(endpoint),以及作为桥完成PCIe总线与PCI或PCI-X总线的转换。

Switch的作用是用以连接更多的PCIe设备,就像USB扩展坞一样或是插线板一样,虽然Root Complex也能直接连接endpoint,但是毕竟接口有限,而Switch可以连接更多的Switch,从而连接更多的设备。

Switch为挂在其上的endpoint和switch提供路由和转发服务。靠近RC的端口叫做上游端口,分出来的其他端口则叫做下游端口。

Switch连接图

分层结构

PCIe定义了下三层:事务层(Transaction Layer)、数据链路层(Data Link Layer)和物理层(Physical Layer)。

分层架构

事务层的主要职责是创建(发送)或者解析(接收)TLP (事务层数据包,Transaction Layer packet),流量控制,QoS,事务排序等。

数据链路层的主要职责是创建(发送)或者解析(接收)DLLP(Data Link Layer packet),Ack/Nak协议(链路层检错和纠错),流控,电源管理等。

物理层的主要职责是处理所有的Packet数据物理传输,发送端数据分发到各个Lane传输(stripe),接收端把各个Lane上的数据汇总起来(De-stripe),每个Lane上加扰(Scramble,目的是让0和1分布均匀,去除信道的电磁干扰EMI)、去扰(De-scramble),以及8/10或者128/130编码解码,等等。

细节如图:

TLP传输流程

发送方和接收方对于TLP的处理是打包和解包的过程。

打包过程:数据从上到下,一层一层打包,上层打包完的数据,作为下层的原始数据,再打包。

打包

红色的是TLP的格式,Header和Data是事务层上层给的信息,事务层给它尾巴上加个CRC校验,就构成了一个TLP;这个TLP下传到数据链路层,又被数据链路层头上加了个包序列号,尾巴再加个CRC校验,构成一个DLLP;然后DLLP下传到物理层,头上加个Start,尾巴加个End符号,把这些数据分派到各个Lane上,然后每个Lane上加扰码,经8/10或128/130编码,最后通过物理传输介质传输给接收方。

解包过程则是:

解包

接收方物理层是最先接收到这些数据的,然后执行逆操作;在数据链路层,校验序列号和LCRC,如果没错,剥掉序列号和LCRC,往事务层走;如果校验出差,通知对方重传;在事务层,校验ECRC,有错,数据抛弃,没错,去掉ECRC,获得数据。

另外,虽说Switch的主要功能是转发数据,但也还需要实现事务层。因为数据的目的地信息是在TLP中的,如果不实现这一层,就无法知道目的地址,也就无法实现数据寻址路由。

事务层 TLP

设备之间的数据传输都是以Packet的形式进行传输。事务层根据上层(软件层或应用层)请求的类型,目的地址和其他属性进行打包产生**TLP (事务层数据包,Transaction Layer packet)**,然后传输至目标设备。

TLP类型

事务层会产生四种不同空间的TLP请求:

  • Memory
  • IO
  • Configuration
  • Message

PCIe线上主流传输的是Memory相关的TLP。

这四种请求又有两种属性:

  • 需要对方响应的称为Non-Posted TLP
  • 不需要对方响应的称为Posted TLP

TLP的请求类型如下表所示。

请求类型 Non-Posted TLP/Posted TLP
Memory Read Non-Posted TLP
Memory Write Posted TLP
Memory Read Lock Non-Posted TLP
IO Read Non-Posted TLP
IO Write Non-Posted TLP
Configuation Read (0/1) Non-Posted TLP
Configuation Write (0/1) Non-Posted TLP
Message Posted TLP

只有Memory Write和Message两种TLP是Posted的,其他的都是Non-Posted。

对于Non-Posted的请求,对方响应时需要返回一个Completion TLP:

  • 对于Read Request,响应者通过Completion TLP返回请求的数据,包含有效数据。
  • 对于Write Request,响应者通过Completion TLP返回执行状态,不包含有效数据。

因此,PCIe里面所有的TLP = Request TLP + Completion TLP。

TLP结构

TLP主要由三部分组成:Header,Data和CRC。TLP都是生于发送端的事务层(Transaction Layer),终于接收端的事务层。

每个TLP都有一个Header,跟动物一样,没有头就活不了,所以TLP可以没手没脚,但不能没有头。事务层根据上层请求内容,生成TLP Header。Header内容包括发送者的相关信息、目标地址(该TLP要发给谁)、TLP类型(如Memory read,Memory Write之类的)、数据长度(如果有的话)等等。

Data Payload域,用以放有效载荷数据。该域不是必须的,因为并不是每个TLP都必须携带数据的,比如Memory Read TLP,它只是一个请求,数据是由目标设备通过Completion TLP返回的。后面我们会整理哪些TLP需要携带数据,哪些TLP不带数据的。一个TLP最大载重是4KB,数据长度大于4KB的话,就需要分几个TLP传输。

ECRC(End to End CRC)域,它对之前的Header和Data(如果有的话)生成一个CRC,在接收端然后根据收到的TLP,重新生成Header和Data(如果有的话)的CRC,和收到的CRC比较,一样则说明数据在传输过程中没有出错,否则就有错。它也是可选的,可以设置不加CRC。

TLP路由

PCIe共有三种路由方式:

  • 基于地址路由
  • 基于设备ID路由
  • 隐式路由

不同类型TLP的寻址方式不同,下表总结了每种TLP的路由方式。

TLP类型 路由方式
Memory Read/Write TLP 地址路由
Configuration Read/Write TLP ID路由
Completion TLP ID路由
Message TLP 三种皆可(主要是隐式路由)

地址路由是指,当一个Memory Read或Memory Write TLP时,它会把TLP Header中的地址跟configure中所有的Bar寄存器(Bar寄存器用以存放Switch内部空间在主机内存空间映射基址)比较,如果地址落在这些Bar的地址空间,则寻址成功,否则忽略。

ID路由是指,在一个PCIe拓扑结构中,某个设备的某个功能ID可由ID = Bus Number + Device Number + Function Number(BDF)唯一指定,这种通过ID来寻址的方式叫做ID路由。

隐式路由是Message TLP才支持的路由,在PCIe总线中,有些Message是与RC直接通信的,因此不必清楚地指定地址或ID,这种方式称为隐式路由。

数据链路层 DLLP

数据链路层是PCIe协议的中间一层。

发送端起的作用是:接受事务层传来的TLP,加上序列号和LCRC(链路检测错误),然后转交给物理层。

接收端起的作用是:接受物理层传来的TLP,检测序列号和CRC,有问题就拒绝接收并通知重传;没有问题就交给事务层,并通知发送端TLP正确接收。

数据链路层除了保证TLP数据正确传输,还包括TLP流量控制电源管理,它通过DLLP(Data Link Layer Packet,数据链路层数据包)来完成这些功能。

DLLP源于发送端的DLL,终于接收端的DLL,不会到达两端的事务层,它仅限于两端的Port。

DLLP分类

数据链路层主要有四大类型DLLP:

  • ACK/NAK;
  • 流控相关的DLLP
  • 电源管理相关的DLLP
  • 厂家自定义DLLP;

DLLP大小为6B(在物理层传输时加上头尾共8B),不同类型的DLLP格式一样,内容不一样。格式如下:

DLLP格式.png

ACK/NAK协议

发送方会对每一个TLP在Replay Buffer中做备份,直到其接收到来自接收方的Ack DLLP,确认该DLP已经成功的被接受,才会删除这个备份。

如果接收方发现TLP存在错误,则会向发送方发送NAK DLLP,然后发送方会从Replay Buffer中取出数据,重新发送该TLP。

TLP流量控制

接收端在接收TLP时要考虑自身的空间大小,空间不足时会让TLP一直Hold在那里,知道有足够空间才会接收,但是这一定程度会影响通信效率。

PCIe通过流控DLLP来告知发送端,接收端到底有多少接受空间,这个过程是时不时的。具体的过程留待以后研究。

物理层

物理层由电气模块和逻辑模块组成

PCIe采用串行总线传输数据,使用差分信号,即用两根信号线上的电平表示0或1。这叫做“串行总线,差分信号”

链路性能损耗

  1. Encode和Decode(编解码损耗)
  2. TLP Packet Overhead(数据包的额外开销)
  3. Traffic Overhead(为了补偿时钟偏差而做的Skip带来的损耗)
  4. Link Protocol Overhead(即ACK/NAK带来的开销)
  5. Flow control(流量控制带来的开销)
  6. System Parameters(系统数据包通信时为了满足必要的格式带来的损耗)

参考文章

《深入浅出SSD:固态存储核心技术、原理与实战》–SSDFans