本节讲述PCIe总线定义的各类TLP,并详细介绍这些TLP的格式。在这些TLP中,有些格式对于初学者来说较难理解。读者需要建立PCIe总线中与TLP相关的一些基本概念,特别是存储器读写相关的报文格式。在PCIe总线中,存储器读写,I/O读写和配置读写请求TLP由以下几类报文组成。
(1) 存储器读请求TLP和读完成TLP
当PCIe主设备,RC或者EP,访问目标设备的存储器空间时,使用Non-Posted总线事务向目标设备发出存储器读请求TLP,目标设备收到这个存储器读请求TLP后,使用存储器读完成TLP,主动向主设备传递数据。当主设备收到目标设备的存储器读完成TLP后,将完成一次存储器读操作。
(2) 存储器写请求TLP
在PCIe总线中,存储器写使用Posted总线事务。PCIe主设备仅使用存储器写请求TLP即可完成存储器写操作,主设备不需要目标设备的回应报文。
(3) 原子操作请求和完成报文
原子操作由PCIe V2.1总线规范引入,一个完整的原子操作包括原子操作请求和原子操作完成报文组成。原子操作的使用方法与其他Non-Posted总线事务类似,首先PCIe主设备向目标设备发送原子操作请求,之后目标设备向主设备发送原子操作完成报文,结束一次原子操作。有关原子操作的详细说明见第5.3.5节。
(4) I/O读写请求TLP和读写完成TLP
在PCIe总线中,I/O读写操作使用Non-Posted总线事务,I/O读写TLP都需要完成报文做为回应。只是在I/O写请求的完成报文中不需要“带数据”,而仅含有I/O写请求是否成功的状态信息。
(5) 配置读写请求TLP和配置读写完成TLP
从总线事务的角度上看,配置读写请求操作的过程与I/O读写操作的过程类似。配置读写请求TLP都需要配置读写完成作为应答,从而完成一个完成的配置读写操作。
(6) 消息报文
与PCI总线相比,PCIe总线增加了消息请求事务。PCIe总线使用基于报文的数据传送模式,所有总线事务都是通过报文实现的,PCIe总线取消了一些在PCI总线中存在的边带信号。在PCIe总线中,一些由PCI总线的边带信号完成的工作,如中断请求和电源管理等,在PCIe总线中由消息请求报文实现。
5.3.1 存储器读写请求TLP
存储器读写请求TLP的格式如图5?8所示。
在PCIe总线中,存储器写请求TLP使用Posted数据传送方式。而其他与存储器和I/O相关的报文都使用Split方式进行数据传送,这些请求报文需要完成报文,通知发送端之前的数据请求报文已经被处理完毕,有关完成报文的详细说明见第5.3.2节。
存储器读写请求TLP使用地址路由方式进行数据传递,在这类TLP头中包含Address字段,Address字段具有两种地址格式,分别是32位和64位地址。在存储器读写和I/O读写请求的第3和第4个双字中,存放TLP的32或者64位地址。存储器、I/O和原子操作读写请求使用的TLP头较为类似。本节仅介绍存储器、I/O读写使用的TLP头,而在第5.3.5节详细介绍原子操作。
1 Length字段
在存储器读请求TLP中并不包含Data Payload,在该报文中,Length字段表示需要从目标设备数据区域读取的数据长度;而在存储器写TLP中,Length字段表示当前报文的Data Payload长度。
Length字段的最小单位为DW。当该字段为n时,表示需要获得的数据长度或者当前报文的数据长度为n个DW,其中0?n?0x3FF。值得注意的是,当n等于0时,表示数据长度为1024个DW。
2 DW BE字段
PCIe总线以字节为基本单位进行数据传递,但是Length字段以DW为最小单位。为此TLP使用Last DW BE和First DW BE这两个字段进行字节使能,使得在一个TLP中,有效数据以字节为单位。
这两个DW BE字段各由4位组成,其中Last DW BE字段的每一位对应数据Payload最后一个双字的字节使能位;而First DW BE字段的每一位对应数据Payload第一个双字的字节使能位。其对应关系如表5?5所示。
表5?5 First和Last DW BE字段
Last DW BE |
第3位 |
为1表示数据Payload的最后一个双字的字节3有效 |
第2位 |
为1表示数据Payload的最后一个双字的字节2有效 |
|
第1位 |
为1表示数据Payload的最后一个双字的字节1有效 |
|
第0位 |
为1表示数据Payload的最后一个双字的字节0有效 |
|
First DW BE |
第3位 |
为1表示数据Payload的第一个双字的字节3有效 |
第2位 |
为1表示数据Payload的第一个双字的字节2有效 |
|
第1位 |
为1表示数据Payload的第一个双字的字节1有效 |
|
第0位 |
为1表示数据Payload的第一个双字的字节0有效 |
Last DW BE和First DW BE这两个字段的使用规则如下。
- 如果传送的数据长度在一个对界的双字(DW)之内,则Last DW BE字段为0b0000,而First DW BE的对应位置1;如果数据长度超过1DW,Last DW BE字段一定不能为0b0000。PCIe总线使用Last DW BE字段为0b0000表示所传送的数据在一个对界的DW之内。
- 如果传送的数据长度超过1DW,则First DW BE字段至少有一个位使能。不能出现First DW BE为0b0000的情况。
- 如果传送的数据长度大于等于3DW,则在First DW BE和Last DW BE字段中不能出现不连续的置1位。
- 如果传送的数据长度在1DW之内时,在First DW BE字段中允许有不连续的置1位。此时PCIe总线允许在TLP中传送1个DW的第1,3字节或者第0,2字节。
- 如果传送的数据长度为2DW之内时,则First DW BE字段和Last DW BE字段允许有不连续的置1位。
值得注意的是,PCIe总线支持一种特殊的读操作,即“Zero-Length”读请求。此时Length字段的长度为1DW,而First DW BE字段和Last DW BE字段都为0b0000,即所有字节都不使能。此时与这个存储器读请求TLP对应的读完成TLP中不包含有效数据。再次提醒读者注意“Zero-Length”读请求使用的Length字段为1,而不是为0,为0表示需要获得的数据长度为1024个DW。
“Zero-Length”读请求的引入是为了实现“读刷新”操作,该操作的主要目的是为了确保之前使用Posted方式所传送的数据,到达最终的目的地,与“Zero-Length”读对应的读完成报文中不含有负载,从而提高了PCIe链路的利用率。
在PCIe总线中,使用Posted方式进行存储器写时,目标设备不需要向主设备发送回应报文,因此主设备并不知道这个存储器写是否已经达到目的地。而主设备可以使用“读刷新”操作,向目标设备进行读操作来保证存储器写最终到达目的地。
在PCIe总线中,标准的存储器读请求也可以完成同样的刷新操作。但是“Zero-Length”读请求与这种读请求相比,其完成报文不需要“Data Payload”,因此在一定程度上提高了PCIe总线的效率。如果一个存储器读请求TLP报文的TH位为1时,DW BE字段将被重新定义为ST[7:0]字段,有关ST字段的详细说明见第5.3.6节。
3 Requester ID字段
Requester ID字段包含“生成这个TLP报文”的PCIe设备的总线号(Bus Number)、设备号(Device Number)和功能号(Function Number),其格式如图5?9所示。对于存储器写请求TLP,Requester ID字段并不是必须的,因为目标设备收到存储器写请求TLP后,不需要完成报文作为应答,因此Requester ID字段对于存储器写请求TLP并没有实际意义。
但是PCIe总线规范并没有明确说明存储器写请求TLP究竟需不需要Requester ID字段,为此IC设计者依然需要将存储器写TLP的Requester ID字段置为有效。值得注意的是,如果一个存储器写请求TLP报文的TH位为1时,Tag字段将被重新定义为ST[7:0]字段,有关ST字段的详细说明见第5.3.6节。
对于Non-Posted数据请求,目标设备需要使用完成报文做为回应。在这个完成报文中,需要使用源设备的Requester ID字段。因此在Non-Posted数据请求TLP中,如存储器读请求、I/O和配置读写请求TLP,必须使用Requester ID字段。
存储器,I/O读请求TLP中含有Requester ID和Tag字段。在PCIe总线中Requester ID和Tag字段合称为Transaction ID,Transaction ID字段的格式如图5?9所示。存储器读,I/O和配置读写请求TLP使用Transaction字段的主要目的是使接收端通过分析报文的Transaction ID,确认完成报文的目的地。
在PCIe总线中,所有Non-Posted数据请求都需要完成报文作为应答,才能结束一次完整的数据传递。一个源设备在发送Non-Posted数据请求之后,如果并没有收到目标设备回送的完成报文,TLP报文的发送端需要保存这个Non-Posted数据请求,此时该设备使用的Transaction ID(Tag字段)不能被再次使用,直到一次数据传送结束,即数据发送端收齐与该TLP对应的所有完成报文。
PCIe设备发出的每一个Non-Posted数据请求TLP,在同一个时刻段内Transaction ID必须是唯一的。即在同一时间段内,在当前PCI总线域中不能存在两个或者两个以上的存储器读请求TLP,其Transaction ID完全相同。
源设备发送Non-Posted数据请求后,在没有获得全部完成报文之前,不能释放这个Transaction ID占用的资源。在同一个PCIe设备发送的TLP中,其Requester ID字段是相同的,因此PCIe设备的设计者所能管理的资源是Tag字段。PCIe设备的设计者需要合理地管理Tag资源,以保证数据传送的正确性。
PCIe设备在发送Non-Posted数据请求时,需要暂存这些Non-Posted数据请求。其中Tag字段的长度决定了发送端能够暂存多少个同类型的TLP,如果Tag字段长度为5,发送端能够暂存32个报文;如果PCIe设备使能了Extended Tag位,Tag字段可以由8位组成,此时发送端能够暂存256个报文。
通过Tag字段的长度,可以发现每个PCIe设备最多可以暂存256个同类型的Non-Posted报文。但是在多数情况下,一个PCIe设备可能只包含1个Function。因此PCIe设备还可以使用Function号扩展Tag字段,从而扩展“暂存TLP报文”的数目。
PCIe设备在PCI Express Capability结构的Device Control寄存器中,设置了一个Phantom Functions Enable位,。当一个PCIe设备仅支持一个Function时,Phantom Functions Enable位可以被设置为1,此时PCIe设备可以使用Requester ID的Function Number字段对Tag字段进一步扩展,此时一个PCIe设备最多可以支持2048个同类型的数据请求。
由以上分析可以发现,一个PCIe设备最多可以支持2048个存储器读数据请求,基本上可以满足绝大多数需要。但是在某些特殊应用场合,PCIe设备即使可以暂存2048个存储器读请求,也并不足够。
与PCI总线相比,PCIe总线的数据传送延时较长,而为了弥补这个传送延时,PCIe设备通常使用流水线技术。此时PCIe设备必须能够连续发送多个存储器读请求报文,随后RC也将连续回送多个存储器读完成报文,在PCIe设备的实现中,需要保证能够源源不断地从RC接收这些报文,以充分利用报文接收流水线,。
PCIe V2.1总线规范还提出了另一种Requester ID格式,即ARI (Alternative Routing-ID Interpretation)格式,除了Requester ID外,在完成报文中使用的Completer ID也可以使用这种格式。ARI格式将ID号分为两个字段,分别为Bus号和Function号,而不使用Device号,ARI格式如图5?10所示。
PCIe总线引入ARI格式的依据是在一个PCIe链路上仅可能存在一个PCIe设备,因而其Device号一定为0。在多数PCIe设备中,Requester ID和Completion ID包含的Device号是没有意义的。使用ARI格式时,一个PCIe设备最多可以支持256个Function,而传统的PCIe设备最多只能支持8个Function。
4 I/O读写请求TLP的规则
I/O读写请求与存储器读写请求TLP的格式基本类似,只是I/O读写请求TLP只能使用32位地址模式和基于地址的路由方式,而且I/O读写请求TLP只能使用Non-Posted方式进行传递。PCIe总线并不建议PCIe设备支持I/O地址空间,但是Switch和RC需要具备接收和发送I/O请求报文的能力,因为许多老的PCI设备依然使用I/O地址空间,这些PCI设备可以通过PCIe桥连接到PCIe总线中。因此虽然支持I/O读写请求的PCIe设备极少,但是在PCIe体系结构中,依然需要支持PCI总线域的I/O地址空间。
与存储器读写请求TLP不同,I/O读写请求TLP的某些字段必须为以下值。
- TC[2:0]必须为0,I/O请求报文使用的TC标签只能为0。
- TH和Attr2位保留,而Attr[1:0]必须为“0b00”,这表示I/O请求报文必须使用PCI总线的强序数据传送模式,而且在传送过程中,硬件保证其传送的数据与Cache保持一致,实际上I/O地址空间都是不可Cache的。
- AT[1:0]必须为“0b00”,表示不支持地址转换,因此在虚拟化技术中,并不处理PCI总线域中的I/O空间。
- Length[9:0]为“0b00 0000 0001”,表示I/O读写请求TLP最大的数据Payload为1DW,该类TLP不支持突发传送。
- Last DW[3:0]为“0b0000”。
5.3.2 完成报文
PCIe总线支持Split传送方式,目标设备使用完成报文向源设备主动发送数据。完成报文使用ID路由方式,由TLP Predix、报文头和Data Payload组成,但是在某些完成报文可以不含有Data Payload,如I/O或者配置写完成和Zero-Length读完成报文。在PCIe总线中,有一下几类数据请求需要收到完成报文之后,才能完成整个数据传送过程,完成报文格式如图5?11所示。
- 所有的数据读请求,包括存储器、I/O读请求、配置读请求和原子操作请求。当一个PCIe设备发出这些数据请求报文后,必须收到目标设备的完成报文后,才能结束一次数据传送。这一类完成报文必须包含Data Payload。
- 所有的Non-Posted数据写请求,包括I/O和配置写请求。当一个PCIe设备发出这些数据请求报文后,必须收到目标设备的完成报文后,才能结束数据传送。但是这一类完成报文不包含数据,仅包含应答信息。
- 与ATS机制相关的一些报文。
完成报文“Byte 0”中的大部分字段与“存储器,I/O、配置请求报文”的对应字段的含义相同。完成报文一次最多能够传送的报文大小不能超过Max_Payload_Size参数。在多数处理器中,完成报文中包含的数据在一个Cache行之内,完成报文使用RCB参数来处理数据对界,RCB参数的大小与处理器系统的Cache行长度和DDR-SDRAM的一次突发传送长度相关,这些参数的详细描述见第5.4.3节。在x86和PowerPC处理器中,一个存储器读完成报文一般不超过RCB参数。
1 Requester ID和Tag字段
完成报文使用ID路由方式,ID路由方式详见第5.2.2节。完成报文头的长度为3DW,完成报文头中包含Transaction ID信息,由Requester ID和Tag字段组成,这个ID必须与源设备发送的数据请求报文的Transaction ID对应,完成报文使用Transaction ID进行ID路由,并将数据发送给源设备。
当PCIe设备收到存储器读、I/O读写或者配置读写请求TLP时,需要首先保存这些报文的Transaction ID,之后当该设备准备好完成报文后,将完成报文的Requester ID和Tag字段赋值为之前保存的Transaction ID字段。
2 Completer ID字段
Completer ID字段的含义与Requester ID字段较为相似,只是该字段存放“发送完成报文”的PCIe设备的ID号。PCIe设备进行数据请求时需要在TLP字段中包含Requester ID字段;而使用完成报文结束数据请求时,需要提供Completer ID字段。
3 Status字段
Status字段保存当前完成报文的完成状态,表示当前TLP是正确地将数据传递给数据请求端;还是在数据传递过程中出现错误;或者要求数据请求方进行重试。PCIe总线规定了几类完成状态,如表5?6所示。
表5?6 Status字段
Status[2:0] |
描述 |
0b000 |
SC(Sucessful Completion),正常结束 |
0b001 |
UR(Unsupported Request),不支持的数据请求 |
0b010 |
CRS(Configuration Request Retry Status),要求数据请求方进行重试。当RC对一个PCIe目标设备发起配置请求时,如果该目标设备没有准备好,可以向RC发出CRS完成报文,当RC收到这类报文时,不能结束本次配置请求,必须择时重新发送配置请求 |
0b100 |
CA(Completion Abort),数据夭折。表示目标设备无法完成本次数据请求 |
其他 |
保留 |
4 BCM位与Byte Count字段
BCM(Byte Count Modified)字段由PCI-X设备设置。PCI-X设备也支持Split Transaction传送方式,当PCI-X设备进行存储器读请求时,目标设备不一定一次就能将所有数据传递给源设备。此时目标设备在进行第一次数据传送时,需要设置Byte Count字段和BCM位。
BCM位表示Byte Count字段是否被更改,该位仅对PCI-X设备有效,而PCIe设备不能操纵BCM位,只有PCI-X设备或者PCIe-to-PCI-X桥可以改变该位。本节对此位不做进一步介绍,对此位感兴趣的读者可以参考PCI-X Addendum to the PCI Local Bus Specification, Revision 2.0。
Byte Count字段记录源设备还需要从目标设备中,获得多少字节的数据就能完成全部数据传递,当前TLP中的有效负载也被Byte Count字段统计在内。该字段由12位组成。该字段为0b0000-0000-0001表示还剩一个字节,为0b1111-1111-1111表示还剩4095个字节,而为0b0000-0000-0000表示还剩4096个字节。除了存储器读请求的完成报文外,大多数完成报文的Byte Count字段为4。
如一个源设备向目标设备发送一个“读取128B的存储器读请求TLP”,而目标设备收到这个读请求TLP后,可能使用两个存储器读完成TLP传递数据。其中第1个存储器读完成TLP的有效数据为64B,而Byte Count字段为128;第2个存储器读完成TLP中的有效数据为64B,而Byte Count字段也为64。当数据请求端接收完毕第1个存储器读完成TLP后,发现还有64B的数据没有接收完毕,此时必须等待下一个存储器读完成TLP。等到数据请求端收齐所有数据后,才能结束整个存储器读请求。
目标设备发出的第2个读完成TLP中的有效数据为64B,而Byte Count字段为64,当数据请求端接收完毕这个读完成TLP后,将完成一个完整的存储器读过程,从而可以释放这个存储器读过程使用的Tag资源。存储器读请求的完成报文的拆分方式较为复杂,Byte Count字段的设置也相对较为复杂。
5 Lower Address字段
如果当前完成报文为存储器读完成TLP,该字段存放在存储器读完成TLP中第一个数据所对应地址的最低位。值得注意的是,在完成报文中,并不存在First DW BE和Last DW BE字段,因此接收端必须使用存储器读完成TLP的Low Address字段,识别一个TLP中包含数据的起始地址。
5.3.3 配置读写请求TLP
配置读写请求TLP由RC发起,用来访问PCIe设备的配置空间。配置请求报文使用基于ID的路由方式。PCIe总线也支持两种配置请求报文,分别为Type 00h和Type 01h配置请求。配置请求TLP的格式如图5?12所示。
配置请求TLP的第4~7字节与存储器请求TLP类似。而第8~11字节的Bus、Device和Function Number中存放该TLP访问的目标设备的相应的号码,而Ext Register和Reigister Number存放寄存器号。配置请求报文的其他字段必须为以下值。
- TC[2:0]必须为0,I/O请求报文的传送类型(TC)只能为0。
- TH位为保留位;Attr2位为保留,而Attr[1:0]必须为“00b”,这表示I/O请求报文使用PCI总线的强序数据传送模式;AT[1:0]必须为“0b00”,表示不进行地址转换。
- Length[9:0]为“0b00 0000 0001”,表示配置读写请求最大Payload为1DW。
- Last DW BE字段为“0b0000”。而First DW BE字段根据配置读写请求的大小设置。
5.3.4 消息请求报文
在PCIe总线中,多数消息报文使用隐式路由方式,其格式如图5?13所示。其中Byte 0字段为通用TLP头,而Byte 4的第3字节中存放Message Code字段。
PCIe总线规定了以下几类消息报文。
- INTx中断消息报文(INTx Interrupt Signaling)。
- 电源管理消息报文(Power Management)。
- 错误消息报文(Error Signaling)。
- 锁定事务消息报文(Locked Transaction Support)。
- 插槽电源限制消息报文(Slot Power Limit Support)。
- Vendor-Defined Messages。