C/C++教程

017 PCIe总线的事务层(一)

本文主要是介绍017 PCIe总线的事务层(一),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、PCIe总线的事务层

事务层是PCIe总线层次结构的最高层,该层次将接收PCIe设备核心层的数据请求,并将其转换为PCIe总线事务,PCIe总线使用的这些总线事务在TLP头中定义。PCIe总线继承了PCI/PCI-X总线的大多数总线事务,如存储器读写、I/O读写、配置读写总线事务,并增加了Message总线事务和原子操作等总线事务。

本节重点介绍与数据传送密切相关的总线事务,如存储器、I/O、配置读写总线事务。在PCIe总线中,Non-Posted总线事务分两部分进行,首先是发送端向接收端提交总线读写请求,之后接收端再向发送端发送完成(Completion)报文。PCIe总线使用Split传送方式处理所有Non-Posted总线事务,存储器读、I/O读写和配置读写这些Non-Posted总线事务都使用Split传送方式。PCIe的事务层还支持流量控制和虚通路管理等一系列特性,而PCI总线并不支持这些新的特性。

在PCIe总线中,不同的总线事务采用的路由方式不相同。PCIe总线继承了PCI总线的地址路由和ID路由方式,并添加了“隐式路由”方式。

PCIe总线使用的数据报文首先在事务层中形成,这个数据报文也被称之为事务层数据报文,即TLP,TLP在经过数据链路层时被加上Sequence Number前缀和CRC后缀,然后发向物理层。

数据链路层还可以产生DLLP(Data Link Layer Packet)。DLLP和TLP没有直接关系,DLLP是产生于数据链路层,终止于数据链路层,并不会传递到事务层。DLLP不是TLP加上前缀和后缀形成的。数据链路层的报文DLLP通过物理层时,需要经过8/10b编码,然后再进行发送。数据的接收过程是发送过程的逆过程,但是在具体实现上,接收过程与发送过程并不完全相同。


1、TLP的格式


当处理器或者其他PCIe设备访问PCIe设备时,所传送的数据报文首先通过事务层被封装为一个或者多个TLP,之后才能通过PCIe总线的各个层次发送出去。TLP的基本格式如图5 1所示。

 

 

一个完整的TLP由1个或者多个TLP Prefix、TLP头、Data Payload(数据有效负载)和TLP Digest组成。TLP头是TLP最重要的标志,不同的TLP其头的定义并不相同。TLP头包含了当前TLP的总线事务类型、路由信息等一系列信息。在一个TLP中,Data Payload的长度可变,最小为0,最大为1024DW。

TLP Digest是一个可选项, 一个TLP是否需要TLP Digest由TLP头决定。Data Payload也是一个可选项,有些TLP并不需要Data Payload,如存储器读请求、配置和I/O写完成TLP并不需要Data Payload。

TLP Prefix由PCIe V2.1总线规范引入,分为Local TLP Prefix和EP-EP TLP Prefix两类。其中Local TLP Prefix的主要作用是在PCIe链路的两端传递消息,而EP-EP TLP Prefix的主要作用是在发送设备和接收设备之间传递消息。设置TLP Prefix的主要目的是为了扩展TLP头,并以此支持PCIe V2.1规范的一些新的功能。

TLP头由3个或者4个双字(DW)组成。其中第一个双字中保存通用TLP头,其他字段与通用TLP头的Type字段相关。一个通用TLP头由Fmt、Type、TC、Length等字段组成,如图5 2所示。

 

 

如果存储器读写TLP支持64位地址模式时,TLP头的长度为4DW,否则为3DW。而完成报文的TLP头不含有地址信息,使用的TLP头长度为3DW。其中Byte 4~Byte 15的格式与TLP相关,下文将结合具体的TLP介绍这些字段。

1.1、通用TLP头的Fmt字段和Type字段

Fmt和Type字段确认当前TLP使用的总线事务,TLP头的大小是由3个双字还是4个双字组成,当前TLP是否包含有效负载。其具体含义如表5 1所示。

表5 1 Fmt[1:0]字段

Fmt[2:0]TLP的格式
0b000 TLP大小为3个双字,不带数据。
0b001 TLP大小为4个双字,不带数据。
0b010 TLP大小为3个双字,带数据。
0b011 TLP大小为4个双字,带数据。
0b100 TLP Prefix
其他 PCIe总线保留

其中所有读请求TLP都不带数据,而写请求TLP带数据,而其他TLP可能带数据也可能不带数据,如完成报文可能含有数据,也可能仅含有完成标志而并不携带数据。在TLP的Type字段中存放TLP的类型,即PCIe总线支持的总线事务。该字段共由5位组成,其含义如表5 2所示。

表5 2 Type[4:0]字段

TLP类型Fmt[2:0]Type[4:0]描述
MRd 0b000、0b001 0b0 0000 存储器读请求;TLP头大小为3个或者4个双字,不带数据。
MRdLk 0b000、0b001 0b0 0001 带锁的存储器读请求;TLP头大小为3个或者4个双字,不带数据。
MWr 0b010、0b011 0b0 0000 存储器写请求;TLP头大小为3个或者4个双字,带数据。
IORd 0b000 0b0 0010 IO读请求;TLP头大小为3个双字,不带数据。
IOWr 0b010 0b0 0010 IO写请求;TLP头大小为3个双字,带数据。
CfgRd0 0b000 0b0 0100 配置0读请求;TLP头大小为3个双字,不带数据。
CfgWr0 0b010 0b0 0100 配置0写请求;TLP头大小为3个双字,带数据。
CfgRd1 0b000 0b0 0101 配置1读请求;不带数据。
CfgWr1 0b010 0b0 0101 配置1写请求;带数据。
TCfgRd 0b010 0b1 1011 本书对这两种总线事务不做介绍。
TCfgWr 0b001 0b1 1011  
Msg 0b001 0b1 0r2r1r0 消息请求;TLP头大小为4个双字,不带数据。“rrr”字段是消息请求报文的Route字段,下文将详细介绍该字段。
MsgD 0b011 0b1 0r2r1r0 消息请求;TLP头大小为4个双字,带数据。
Cpl 0b000 0b0 1010 完成报文;TLP头大小为3个双字,不带数据。包括存储器、配置和I/O写完成。
CplD 0b010 0b0 1010 带数据的完成报文,TLP头大小为3个双字,包括存储器读、I/O读、配置读和原子操作读完成。
CplLk 0b000 0b0 1011 锁定的完成报文,TLP头大小为3个双字,不带数据。
CplDLk 0b010 0b0 1011 带数据的锁定完成报文,TLP头大小为3个双字,带数据。
FetchAdd 0b010、0b011 0b0 1100 Fetch and Add原子操作。
Swap 0b010、0b011 0b0 1101 Swap原子操作。
CAS 0b010、0b011 0b0 1110 CAS原子操作。
LPrfx 0b100 0b0 L3L2L1L0 Local TLP Prefix
EPrfx 0b100 0b1 E3E2E1E0 End-End TLP Prefix

由上表所示,存储器读和写请求,IO读和写请求,及配置读和写请求的type字段相同,如存储器读和写请求的Type字段都为0b0 0000。此时PCIe总线规范使用Fmt字段区分读写请求,当Fmt字段是“带数据”的报文,一定是“写报文”;当Fmt字段是“不带数据”的报文,一定是“读报文”。

PCIe总线的数据报文传送方式与PCI总线数据传送有类似之处。其中存储器写TLP使用Posted方式进行传送,而其他总线事务使用Non-Posted方式。

PCIe总线规定所有Non-Posted存储器请求使用Split总线方式进行数据传递。当PCIe设备进行存储器读、I/O读写或者配置读写请求时,首先向目标设备发送数据读写请求TLP,当目标设备收到这些读写请求TLP后,将数据和完成信息通过完成报文(Cpl或者CplD)发送给源设备。

其中存储器读、I/O读和配置读需要使用CplD报文,因为目标设备需要将数据传递给源设备;而I/O写和配置写需要使用Cpl报文,因为目标设备不需要将任何数据传递给源设备,但是需要通知源设备,写操作已经完成,数据已经成功地传递给目标设备。

在PCIe总线中,进行存储器或者I/O写操作时,数据与数据包头一起传递;而进行存储器或者I/O读操作时,源设备首先向目标设备发送读请求TLP,而目标设备在准备好数据后,向源设备发出完成报文。

PCIe总线规范还定义了MRdLk报文,该报文的主要作用是与PCI总线的锁操作相兼容,但是PCIe总线规范并不建议用户使用这种功能,因为使用这种功能将极大影响PCIe总线的数据传送效率。

与PCI总线并不相同,PCIe总线规范定义了Msg报文,即消息报文。分别为Msg和MsgD,这两种报文的区别在于一个报文可以传递数据,一个不能传递数据。

PCIe V2.1总线规范还补充了一些总线事务,如FetchAdd、Swap、CAS、LPrfx和EPrfx。其中LPrfx和EPrfx总线事务分别与Local TLP Prefix和EP-EP TLP Prefix对应。在PCIe总线规范V2.0中,TLP头的大小为1DW,而使用LPrfx和EPrfx总线事务可以对TLP头进行扩展,本节不对这些TLP Prefix做进一步介绍。PCIe设备可以使用FetchAdd、Swap和CAS总线事务进行原子操作。

2、TC字段

TC字段表示当前TLP的传送类型,PCIe总线规定了8种传输类型,分别为TC0~TC7,缺省值为TC0,该字段与PCIe的QoS相关。PCIe设备使用TC区分不同类型的数据传递,而多数EP中只含有一个VC,因此这些EP在发送TLP时,也仅仅使用TC0,但是有些对实时性要求较高的EP中,含有可以设置TC字段的寄存器。

在Intel的高精度声卡控制器(High Definition Audio Controller)的扩展配置空间中含有一个TCSEL寄存器。系统软件可以设置该寄存器,使声卡控制器发出的TLP使用合适的TC。声卡控制器可以使用TC7传送一些对实时性要求较强的控制信息,而使用TC0传送一般的数据信息。在具体实现中,一个EP也可以将控制TC字段的寄存器放入到设备的BAR空间中,而不必和Intel的高精度声卡控制器相同,存放在PCI配置空间中。

目前许多处理器系统的RC仅支持一个VC通路,此时EP使用不同的TC进行传递数据的意义不大。x86处理器的MCH中一般支持两个VC通路,而多数PowerPC处理器仅支持一个VC通路。PLX公司的多数Switch也仅支持两个VC通路。

有些RC,如MPC8572处理器,也能决定其发出TLP使用的TC。在该处理器的PCIe Outbound窗口寄存器(PEXOWARn)中,含有一个TC字段,通过设置该字段可以确定RC发出的TLP使用的TC字段。不同的TC可以使用PCIe链路中的不同VC,而不同的VC的仲裁级别并不相同。EP或者RC通过调整其发出TLP的TC字段,可以调整TLP使用的VC,从而调整TLP的优先级。

3、Attr字段

Attr字段由3位组成,其中第2位表示该TLP是否支持PCIe总线的ID-based Ordering;第1位表示是否支持Relaxed Ordering;而第0位表示该TLP在经过RC到达存储器时,是否需要进行Cache共享一致性处理。Attr字段如图5 3所示。

 

 

一个TLP可以同时支持ID-based Ordering和Relaxed Ordering两种位序。Relaxed Ordering最早在PCI-X总线规范中提出,用来提高PCI-X总线的数据传送效率;而ID-based Ordering由PCIe V2.1总线规范提出。TLP支持的序如表5 3所示。

表5 3 TLP支持的序

Attr[2]Attr[1]类型
0 0 缺省序,即强序模型
0 1 PCI-X Relaxed Ordering模型
1 0 ID-Based Ordering(IDO)模型
1 1 同时支持Relaxed Ordering和IDO模型

当使用标准的强序模型时,在数据的整个传送路径中,PCIe设备在处理相同类型的TLP时,如PCIe设备发送两个存储器写TLP时,后面的存储器写TLP必须等待前一个存储器写TLP完成后才能被处理,即便当前报文在传送过程中被阻塞,后一个报文也必须等待。如果使用Relaxed Ordering模型,后一个存储器写TLP可以穿越前一个存储器写TLP,提前执行,从而提高了PCIe总线的利用率。有时一个PCIe设备发出的TLP,其目的地址并不相同,可能先进入发送队列的TLP,在某种情况下无法发送,但这并不影响后续TLP的发送,因为这两个TLP的目的地址并不相同,发送条件也并不相同。值得注意的是,在使用PCI总线强序模型时,不同种类的TLP间也可以乱序通过同一条PCIe链路,比如存储器写TLP可以超越存储器读请求TLP提前进行。而PCIe总线支持Relaxed Ordering模型之后,在TLP的传递过程中出现乱序种类更多,但是这些乱序仍然是有条件限制的。在PCIe总线规范中为了避免死锁,还规定了不同报文的传送数据规则,即Ordering Rules。

PCIe V2.1总线规范引入了一种新的“序”模型,即IDO(ID-Based Ordering)模型,IDO模型与数据传送的数据流相关,是PCIe V2.1规范引入的序模型。

Attr字段的第0位是“No Snoop Attribute”位。当该位为0时表示当前TLP所传送的数据在通过FSB时,需要与Cache保持一致,这种一致性由FSB通过总线监听自动完成而不需要软件干预;如果为1,表示FSB并不会将TLP中的数据与Cache进行一致,在这种情况下,进行数据传送时,必须使用软件保证Cache的一致性。

在PCI总线中没有与这个“No Snoop Attribute”位对应的概念,因此一个PCI设备对存储器进行DMA操作时会进行Cache一致性操作(1) ,这种“自动的”Cache一致性行为在某些特殊情况下并不能带来更高的效率。

当一个PCIe设备对存储器进行DMA读操作时,如果传送的数据非常大,比如512MB,Cache的一致性操作不但不会提高DMA写的效率,反而会降低。因为这个DMA读访问的数据在绝大多数情况下,并不会在Cache中命中,但是FSB依然需要使用Snoop Phase进行总线监听。而处理器在进行Cache一致性操作时仍然需要占用一定的时钟周期,即在Snoop Phase中占用的时钟周期,Snoop Phase是FSB总线事务的一个阶段,如图3 6所示。

对于这类情况,一个较好的做法是,首先使用软件指令保证Cache与主存储器的一致性,并置“No Snoop Attribute”位为1(2),然后再进行DMA读操作。同理使用这种方法对一段较大的数据区域进行DMA写时,也可以提高效率。

除此之外,当PCIe设备访问的存储器,不是“可Cache空间”时,也可以通过设置“No Snoop Attribute”位,避免FSB的Cache共享一致性操作,从而提高FSB的效率。“No Snoop Attribute”位是PCIe总线针对PCI总线的不足,所作出的重要改动。

4、通用TLP头中的其他字段

除了Fmt和Type字段外,通用TLP头还含有以下字段。

4.1、TH位、TD位和EP位

TH位为1表示当前TLP中含有TPH(TLP Processing Hint)信息,TPH是PCIe V2.1总线规范引入的一个重要功能。TLP的发送端可以使用TPH信息,通知接收端即将访问数据的特性,以便接收端合理地预读和管理数据。

TD位表示TLP中的TLP Digest是否有效,为1表示有效,为0表示无效。而EP位表示当前TLP中的数据是否有效,为1表示无效,为0表示有效。

4.2、 AT字段

AT字段与PCIe总线的地址转换相关。在一些PCIe设备中设置了ATC(Address Translation Cache)部件,这个部件的主要功能是进行地址转换。只有在支持IOMMU技术的处理器系统中,PCIe设备才能使用该字段。

AT字段可以用作存储器域与PCI总线域之间的地址转换,但是设置这个字段的主要目的是为了方便多个虚拟主机共享同一个PCIe设备。对这个字段有兴趣的读者可以参考Address Translation Sevices规范,这个规范是PCI的IO Virtualization规范的重要组成部分。对虚拟化技术有兴趣的读者可以参考清华大学出版社的《系统虚拟化——原理与实现》,以获得基本的关于虚拟化的入门知识。

4.3、Length字段

Length字段用来描述TLP的有效负载(Data Payload)大小(3).PCIe总线规范规定一个TLP的Data Payload的大小在1B~4096B之间。PCIe总线设置Length字段的目的是提高总线的传送效率。

当PCI设备在进行数据传送时,其目标设备并不知道实际的数据传送大小,这在一定程度上影响了PCI总线的数据传送效率。而在PCIe总线中,目标设备可以通过Length字段提前获知源设备需要发送或者请求的数据长度,从而合理地管理接收缓冲,并根据实际情况进行Cache一致性操作。

当PCI设备进行DMA写操作,将PCI设备中4KB大小的数据传送到主存储器时,这个PCI设备的DMA控制器将存放传送的目的地址和传送大小,然后启动DMA写操作,将数据写入到主存储器。由于PCI总线是一条共享总线,因此传送4KB大小的数据,可能会使用若干个PCI总线写事务才能完成(4),而每一个PCI总线写事务都不知道DMA控制器何时才能将数据传送完毕。

如果这些总线写事务还通过一系列PCI桥才能到达存储器,在这个路径上的每一个PCI桥也无法预知,何时这个DMA操作才能结束。这种“不可预知”将导致PCI总线的带宽不能被充分利用,而且极易造成PCI桥数据缓冲的浪费。

而PCIe总线通过TLP的Length字段,可以有效避免PCIe链路带宽的浪费。值得注意的是,Length字段以DW为单位,其最小单位为1个DW。如果PCIe主设备传送的单位小于1个DW或者传送的数据并不以DW对界时,需要使用字节使能字段,即“DW BE”字段。


(1)PowerPC处理器通过设置Inbound寄存器,也可以避免这个Cache一致性操作。(2)FSB收到这类TLP后,不进行Cache一致性操作。(3)存储器读请求TLP没有DataPayload字段,此时该TLP使用Length字段表示需要读取多少数据。(4)当多个PCI设备共享一条PCI总线时,一个设备不会长时间占用PCI总线,这个设备在使用这条PCI总线一定的时间后,将让出PCI总线的使用权。

这篇关于017 PCIe总线的事务层(一)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!