高级FPGA开发之基础协议之PCIe(二)
一、TLP报文类型
在PCIe总线中,存储器读写、I/O读写和配置读写请求TLP主要由以下几类报文组成:
1.1 存储器读请求TLP和读完成TLP
当PCIe主设备(RC或者EP)访问目标设备的存储器空间时,使用non-posted总线事务向目标设备发出存储器读请求TLP,目标设备收到这个存储器读请求tlp后,使用存储器读完成tlp,主动向主设备传递数据。当主设备收到目标设备的存储器读完成tlp后,将完成一次存储器读请求。
1.2 存储器写请求tlp
在PCIe总线中,存储器写使用posted总线事务。PCIe主设备仅使用存储器写请求tlp即可完成存储器写操作,主设备不需要目标设备的回应报文。
1.3 原子操作请求和完成报文
原子操作由PCIe V2.1总线规范引入,一个完整的原子操作包括原子操作请求和原子操作完成报文组成。
原子操作的使用方法与其他non-posted总线事务类似。
首先PCIe主设备向目标发送原子操作请求,之后目标设备向主设备发送原子操作完成报文,结束一次原子操作。
1.4 IO读写请求TLP和读写完成TLP
在PCIe总线中,IO读写操作使用non-posted,IO读写TLP读需要完成报文作为回应。只是在IO写请求的完成报文中不需要"带数据",而仅含有IO写请求是否成功的状态信息。
1.5 配置读写TLP和配置读写完成TLP
从总线事务的角度来看,配置读写请求的操作工程和IO读写操作的过程类似。
配置读写请求 TLP 都需要配置读写完成作为应答,从而完成一个完成的配置读写操作。
1.6 消息报文
和PCI总线相比,PCIe总线增加了消息请求事务。PCIe总线使用基于报文的数据传送模式,所有总线都是通过报文实现的,PCIe总线取消了一些在PCI总线中存在的边带信号。
在PCIe总线中,一些由PCI总线的边带信号完成的工作,比如中断请求和电源管理等,在PCIe总线中由消息请求报文实现。
二、TLP报文详解
2.1 存储器读写请求TLP
存储器读写请求TLP的格式如下图:
在PCIe总线上,存储器写请求TLP使用posted数据传送方式。而其他与存储器和IO相关的报文都使用split方式进行数据传送,这些请求报文需要完成报文,存储器读写请求TLP使用地址路由方式进行数据传递。
length段:
在存储器读请求TLP中,length字段表示需要从目标设备数据区域读取的数据长度。
在存储器写TLP中,length字段表示当前报文的data payload长度。
length字段的最小单位是DW。当字段为n时,表示需要获取的数据长度或者当前报文的数据长度为n个DW。注意n=0,表示长度为1024的DW。
DW BE字段:
PCIe总线以字节为基本单位进行数据传输的,但是length字段以DW为最小单位。为此,TLP使用last DW BE和First DW BE这两个字段进行字节使能,使得在一个TLP中,有效数据以字节为单位。
这两个 DW BE 字段各由4位组成,其中 Last DW BE 字段的每一位对应数据 Payload 最后一个双字的字节使能位;而 First DW BE 字段的每一位对应数据 Payload 第一个双字的字节使能位。其对应关系如下图所示。
"Zero-Length"读请求的引入是为了实现"读刷新"操作,该操作的主要目的是为了确保之前使用 Posted 方式所传送的数据,到达最终的目的地,与"Zero-Length"读对应的读完成报文中不含有负载,从而提高了 PCIe 链路的利用率。
requester ID:
requester ID字段包含生成这个TLP报文的PCIe设备的总线号(bus number)、设备号(device number)、功能号(function number)。
对于non-posted数据请求,目标设备需要使用完成报文作为回应。在这个完成报文中,需要使用源设备的requester ID字段。
因此在non-posted数据请求TLP中,如存储器读请求、IO和配置读写请求、必须使用requester ID字段。
IO读写请求TLP规则:
I/O 读写请求 TLP 只能使用32位地址模式和基于地址的路由方式且只能使用 Non-Posted 方式进行传递。
2.2 完成报文TLP
PCIe 总线支持 Split 传送方式,目标设备使用完成报文向源设备主动发送数据。
完成报文使用 ID 路由方式,由 TLP Predix、报文头和 Data Payload 组成,但是在某些完成报文可以不含有 Data Payload,如 I/O 或者配置写完成和 Zero-Length 读完成报文。
所有的数据读请求,包括存储器、I/O 读请求、配置读请求和原子操作请求。当一个PCIe设备 发出这些数据请求报文后,必须收到目标设备的 完成报文后,才能结束一次数据传送。这一类完成报文必须包含 Data Payload。完成报文格式如下图:
requester ID和tag字段:
完成报文使用ID路由方式。完成报文头的长度为3DW,完成报文头中包含了transaction ID,由requester ID和tag字段组成,这个ID必须和源设备发送的数据请求报文的tansaction ID对应,完成报文使用transaction ID进行ID路由,并将数据发送给源设备。
当PCIe设备收到存储器读、IO读写或者配置读写请求TLP时,需要首先保证保存这些报文的transaction ID,之后当该设备准备好完成报文后,将完成报文requester ID和tag ID字段赋值为之前保存的transaction ID字段。
completer ID字段:
completer ID字段的含义与requester ID字段较为相似,只是该字段存放发送完成报文的PCIe设备的ID号。
PCIe设备进行数据请求时需要在TLP字段中包含requester ID字段,而完成报文结束数据请求时,需要提供completer ID字段。
status字段:
status字段保存当前完成报文的完成状态,表示当前TLP是正确地将数据传递给数据请求端,还是在数据传输过程中出现错误,或者要求数据请求方式进行重试。
BCM 位与 Byte Count 字段:
bcm(byte count modified)字段由pci-x设备设置的。
pci-x设备也支持split transaction传送方式。当pci-x设备进行存储读请求时,且目标设备不一定一次将所有数据传递给源设备。此时目标设备在进行第一次数据传送时,需要设置byte count字段和bcm位。
bcm位表示byte count字段是否被更改,该位仅对pci-x设备有效,而PCIe设备不能操作BCN位。
byte count字段记录源设备还需要从目标设备中,获取多少字节的数据就能完成全部数据传递,当前的TLP中的有效负载也被byte count字段统计在内。该字段由12位组成。
该字段为0b0000-0000-0001表示还剩一个字节,为0b1111-1111-1111表示还剩4095个字节,而为0b0000-0000-0000表示还剩4096个字节。
除了存储器读请求的完成报文外,大多数完成报文的 Byte Count 字段为4。
lower address字段:
如果当前完成报文为存储器读完成TLP,该字段存放在存储器读完成TLP中第一个数据所对应地址的最低位。
值得注意的是,在读完成报文中,并不存在first DW BE和last DW BE字段。
因此接收端必须使用存储器读完成 TLP 的 Low Address 字段,识别一个 TLP 中包含数据的起始地址。
配置读写请求 TLP:
配置读写请求 TLP 由 RC 发起,用来访问 PCIe 设备的配置空间。配置请求报文使用基于ID 的路由方式。PCIe 总线也支持两种配置请求报文,分别为 Type 00h 和 Type 01h 配置请求。配置请求 TLP 的格式如下图。
消息请求报文:
在 PCIe 总线中,多数消息报文使用隐式路由方式,其格式如下图:
PCIe 总线规定了以下几类消息报文:
INTx 中断消息报文(INTx Interrupt Signaling);
电源管理消息报文(Power Management);
错误消息报文(Error Signaling);
锁定事务消息报文(Locked Transaction Support);
插槽电源限制消息报文(Slot Power Limit Support);
Vendor-Defined Messages;
三、TLP中与数据负载相关的参数
在 PCIe 总线中,有些 TLP 含有 Data Payload,如存储器写请求、存储器读完成 TLP 等。
在 PCIe 总线中,TLP 含有的 Data Payload 大小与 Max_Payload_Size、Max_Read_Request_Size和 RCB 参数相关。
Max_Payload_Size 参数:
PCIe 总线规定在 TLP 报文中,数据有效负载的最大值为4KB,但是 PCIe 设备并不一定能够发送这么大的数据报文。PCIe 设备含有"Max_Payload_Size"和"Max_Payload_SizeSupported"参数,这两个参数分别在Device Capability 寄存器 和Device Control寄存器中定义。
PCIe设备发送数据报文时,使用Max_Payload_Size 参数 决定 TLP 的最大有效负载。当PCIe 设备的所传送的数据大小超过 Max_Payload_Size 参数时,这段数据将被分割为多个 TLP进行发送。
Max_Payload_Size参数的大小与 PCIe 链路的传送效率成正比,该参数越大,PCIe链路带宽的利用率越高,该参数越小,PCIe 链路带宽的利用率越低。
Max_Read_Request_Size 参数:
Max_Read_Request_Size 参数由 PCIe 设备决定,该参数规定了 PCIe 设备一次能从目标设备读取多少数据。
PCIe 总线规定存储器读请求,其读取的数据长度不能超过 Max_Read_Request_Size 参数,即存储器读 TLP 中的 Length 字段不能大于这个参数。如果一次存储器读操作需要读取的数据范围大于 Max_Read_Request_Size 参数时,该 PCIe 设备需要向目标设备发送多个存储器读请求 TLP。
RCB 参数:
RCB 位在 Link Control 寄存器中定义。RCB 位决定了 RCB 参数的值,在 PCIe 总线中,RCB 参数的大小为64B 或者128B,如果一个 PCIe 设备没有设置 RCB 的大小,则 RC 的 RCB参数缺省值为64B,而其他 PCIe 设备的 RCB 参数的缺省值为128B。PCIe 总线规定 RC 的 RCB参数的值为64B 或者128B,其他 PCIe 设备的 RCB 参数为128B。
Read Completion Boundary (RCB),读完成边界,是 Completer 响应读请求的一种地址边界对齐策略,应用于 CplD。
第一笔completion必须开始于request的起始地址,当request的length不大于RCB时不进行切分,当request的length大于RCB时在RCB处结束。
最后一笔completion返回的地址必须满足所有completion payload长度满足request的length。
所有中间的completions payload大小必须满足RCB。
1. Read request length 不大于RCB
例如RCB为128 Byte,read request length 小于128 Byte。这时不会返回multi-completions,所以不会对返回包进行切分,从request的起始地址读够length长度的数据返回。
Read request length 大于RCB,这种情况会返回multi-completions,且与起始地址有关系
例如:
1. 例如RCB为128 Byte,read request length 为200 Bytes,起始地址为0X60。这时会有三笔completion返回,
第一笔从0X60开始读取32 Bytes数据,第二笔数据从0X80开始读取128 Bytes数据,第三笔从0X100地址开始读取40 Bytes数据。
2. 例如RCB为128 Byte,read request length 为200 Bytes,起始地址为0X10。这时会有两笔completion返回,
第一笔从0X10开始读取112 Bytes数据,第二笔数据从0X80开始读取88 Bytes数据。
四、未完待续
下章将继续介绍核心的基本概念:内核态的线程/进程技术。
欢迎关注知乎:北京不北,+vbeijing_bubei
欢迎关注douyin:near.X (北京不北)
欢迎+V:beijing_bubei
获得免费答疑,长期技术交流。