PCIe学习之《理解TLP的基本结构》
理解TLP的组成
帧头(Header)+ 数据载荷(Data Payload)+ Digest(可选)
理解帧头各字段含义
Fmt[1:0]字段
表示帧头大小以及是否包含数据载荷:00b = 3DW 头部,无数据;01b = 4DW 头部,无数据;10b = 3DW 头部,有数据;11b = 4DW
头部,有数据。Type[4:0]字段
Type 字段与 Fmt[1:0] 字段一起使用,以指定事务类型、头部大小以及是否存在数据载荷。具体表示事务类型见附表。TC(流量类别)
TC用于为TLP分配优先级,支持8个等级(TC0到TC7),数值越大优先级越高,绝大多数设备默认使用TC0。系统会为高优先级TC(如TC7)分配独立的VC缓冲区,确保其优先被处理。正确使用TC可避免重要数据(如视频流)被海量普通数据阻塞。TD(TLP 摘要字段存在)
设置为 1 时,该 TLP 包含可选的 1 DW TLP 摘要字段,其中包含 ECRC 值。所有接收端必须(使用此位)检查摘要字段的存在。TD=1 但无摘要字段的 TLP 被处理为畸形 TLP。如果设备支持 ECRC 检查且 TD=1,则必须执行 ECRC 检查。如果设备不支持 ECRC 检查(可选),则必须忽略摘要。EP(中毒数据)
EP = 0:数据有效。
EP = 1:数据无效。事务仍会正常完成,但接收方应忽略数据。此机制常用于错误处理。Attr(属性)
Bit 5 = Relaxed Ordering (宽松排序):
当 0 时(严格排序):如同在单车道上按序行驶,所有TLP(数据包)必须严格按照发出的顺序到达,前一个未完成,后一个就不能超车。这会拖慢传输速度,尤其在大数据量时。
当 1 时(宽松排序):允许“超车”。在高速公路上,如果目的地不同(不同数据流),允许后面的车(TLP)超过前面的车。这能大幅提高总线利用率和吞吐量,是PCIE高速传输的关键。
Bit 4 = No Snoop (禁止侦听)
当 0 时(默认,需要侦听):当CPU要读取数据时,会先检查缓存(Cache) 里是否已有副本(即“Snoop(侦听)”过程)。这会产生额外开销,但在需要保证数据一致性时是必需的。
当 1 时(禁止侦听):明确告诉系统:“别查缓存了,直接从内存拿数据!”这跳过了缓存检查,让数据传输“飞”起来,但不保证CPU缓存与内存数据完全同步。Length [9:0]
TLP 数据载荷传输大小,以 DW 为单位。最大传输大小为 10 位,2^10 = 1024DW(4KB)。编码:0000000001b = 1DW … 1111111111b = 1023DW,0000000000b = 1024DW。Last DW和First DW字节使能
TLP包传输的最小单位是4字节(DW),如果一次传输不满足四字节整数倍时,就需要用到Last DW和First DW字段,用来屏蔽掉4字节中多余的字节,以保证传输字节的任意性。例如,我要通过一个TLP包传输27字节的数据,此时不满足4字节的整数倍,可以设置First DW=1100b,使第一个DW的后两个字节有效;设置 Last DW=0001b,使最后一个DW的第一个字节有效。中间的24字节刚好6个DW。
理解数据载荷
可选字段。0-1024 DW 载荷,可进一步使用字节使能来获得字节地址和字节传输大小
分辨率。
理解Digest(可选)
可选字段。如果存在,始终为 1 DW 大小。用于端到端 CRC(ECRC)和数据中毒。
理解3DW Header和4DW Header的区别(32位 vs 64位地址寻址)
注意:3DW 头部和 4DW 头部之间的区别在于起始地址字段的位置和大小:
3DW 头部(32 位寻址):地址位 31:2 在 Bytes 8-11 中,Bytes 12-15 不使用。
4DW 头部(64 位寻址):地址位 31:2 在 Bytes 12-15 中,地址位 63:32 在 Bytes 8-11 中。
其他头部字段相同。
列出TLP的四种事务类型:Memory、IO、Configuration、Message
| 地址空间 | 事务类型 | 用途 |
|---|---|---|
| 内存(Memory) | 读、写 | 向/从系统内存映射中的某个位置传输数据。协议还支持锁定内存读事务。 |
| IO | 读、写 | 向/从系统 IO 映射中的某个位置传输数据。PCI Express IO 地址分配给传统设备。原生 PCI Express 设备不允许使用 IO 寻址。 |
| 配置(Configuration) | 读、写 | 向/从 PCI Express 设备配置空间中的某个位置传输数据。与 PCI 一样,配置用于发现设备能力、编程即插即用功能,并使用 4KB PCI Express 配置空间检查状态。 |
| 消息(Message) | 基线、厂商特定 | 提供带内消息传递和事件报告(不消耗内存或 IO 地址资源)。这些事务的处理方式与 posted 写事务相同。 |