15

LJgibbs · 2022年05月12日

《PCI Express Technology 3.0》Chapter 5

1652327199(1).png

关于上一章

上一章描述了一个 Function 通过 BARs 请求地址空间(内存地址空间或 IO 地址空间)的目的和方法,还描述了软件如何配置 Bridge 的 Base/Limit 寄存器,将源端口的 TLP 路由至正确的目的端口。我们还讨论了 PCIe 中 TLP 路由的一般概念,包括基于地址的路由、基于 ID 的路由,以及隐式路由(implicit routing)。

关于本章

在 PCIe 设备之间,信息是以包的形式进行传输的,包主要分为三类:TLP(Transaction Layer Packet,事务层包)、DLLP(Data Link Layer Packet,数据链路层包)和 Ordered Set(命令集,它应用于物理层)。本章将讲述 TLP 的用法、格式和不同种类的定义,并将详细讲解 TLP 的相关字段含义。关于 DLLP 的内容将会在 Chapter 9 “DLLP Element” 中进行单独讲解。

关于下一章

下一章将讨论流量控制协议(Flow Control Protocol)的目的和详细操作。流量控制是用来确保发送方在接收方无法接收 TLP 时,不再继续发送 TLP。流量控制避免了接收缓存的溢出,也消除了原本 PCI 工作方式中的一些低效行为,比如断开(disconnect)、重试(retry)和等待态(wait-state)。

5.1 基于数据包协议的介绍(Introduction to Packet-Based Protocol)

5.1.1 概括(General)

不同于并行总线,PCIe 这样的串行总线不使用总线上的控制信号来表示某时刻链路上正在发生什么。相反地,PCIe 链路上的发送方发出的比特流必须要有一个预期的大小,还要有一个可供接收方辨认的格式,这样接收方才能理解比特流的内容。此外,PCIe 在传输数据包时并不使用任何直接握手机制(immediate handshake)。

除了逻辑空闲符号(Logical Idle symbol)和 Ordered Set 的物理层包外,在活跃的 PCIe 链路上传输的信息的基本组块被称为 Packet(包),包是由符号组成的。链路上交换的两类主要的数据包为高层的 TLP(Transaction Layer Packet,事务层包),和低层的用于链路维护的包称为 DLLP(Data Link Layer Packet,数据链路层包)。这些包和它们的传输流如图 5‑1 所示。物理层的 Ordered Set 也是一种包,但是它并不像 TLP 和 DLLP 一样会被封装上包起始符号和包结束符号(也就是前面章节所讲的组帧符号),并且 Ordered Set 也并没有像 TLP 和 DLLP 一样的字节条带化过程,相反地,Ordered Set 会在链路的每个通道(lane)上都复制一份,而不是像字节条带化一样把信息按字节分配到各个通道上。

图 5‑1 TLP 和 DLLP 包

5.1.2 使用基于数据包协议的动机

使用基于包的协议(Packet-Based Protocol)有三个明显的优点,特别是对于数据完整性(data integrity)来说:

5.1.2.1 精心定义的数据包格式

像 PCI 这种早期的总线,它们允许总线上不确定数据量大小的传输,这使得只要传输没有结束就无法识别出数据荷载(payload)的边界。此外,任何一个设备都可以在此次传输完成前终止这个传输,这使得发送方很难去计算并传输一个覆盖了整个数据荷载的校验和或者 CRC。相反地,PCI 使用了一种简单的奇偶校验的方案,并在每个数据阶段(data phase)进行奇偶校验。(这里如果没理解请参阅 Chapter 1 内的 PCI 相关内容)

相比之下,PCIe 包具有一个已知的大小和格式。位于包的开头的部分为 Header,它用来指示这个包的类型,并包含了必需字段(required field)和可选字段(optional field)。除了地址字段以外,Header 中的其他字段长度都是固定的,地址字段可以为 32bit 也可以为 64bit。一旦一次传输开始,接收方不能暂停或者提前终止它。这种结构化的格式使得我们可以在 TLP 中加入一些信息来更有利于进行可靠的传输,例如加入组帧符号(framing symbol)、CRC、以及一个包的序列号(Sequence Number)。

5.1.2.2 使用组帧符号定义包的边界

在 PCIe Gen1 和 Gen2 操作模式中使用的是 8b/10b 编码,因此在这 Gen1 和 Gen2 中每个 TLP 和 DLLP 在发送前都会使用起始符号(Start)和结束符号(End)这两种控制符号来进行组帧,这样就可以给接收方清晰地定义出包的边界。这是在 PCI 和 PCI-X 上的重大改进,在 PCI 和 PCI-X 中使用一个单独的 FRAME# 信号来指示一个事务的开始和结束,如果 FRAME# 出现了毛刺,或者其他的控制信号出现了毛刺,那么都有可能造成目标设备对总线行为的误解。一个 PCIe 接收方必须在最后的链路活动开始或结束之前,就正确完成一个完整 10bit 符号的译码,这样接收方能更容易识别不期望出现或者无法识别的符号,并且将其作为一个错误来处理。

对于 PCIe Gen3 使用的 128b/130b 编码来说,控制字符不再被使用,并且也没有组帧符号了。对于更多的关于 Gen3 编码与早期版本的差异的内容,请参阅 Chapter 12“Physical Layer-Logical(Gen3)”。

5.1.2.3 使用 CRC 保障整个数据包的正确传输

在 PCI 体系结构中,会在地址阶段(address phase)和数据阶段(data phase)中使用奇偶校验边带(side-band)信号,但是在 PCIe 中则不同。PCIe 中使用带内(in-band)的 CRC 值来验证整个数据包是否进行了无错误的传输。同时 TLP 还会被发送方的数据链路层添加上一个序列号(Sequence Number),这使得当这个序列号的数据包传输出错时可以很简单的定位到它,并进行自动的重传。发送方会在自己的 Retry Buffer 内保存每个 TLP 的一个副本,直到接收方确认了这个 TLP 成功无错传输后才会将副本清除。这种 TLP 的确认机制被称为 Ack/Nak 协议(更多内容请参阅 Chapter 10 “Ack/Nak Protocol” ),它用来形成基础的链路级 TLP 错误检测和纠正机制。这种 Ack/Nak 协议提供的错误恢复机制使得我们可以在问题发生的地方或者链路上及时的解决问题,但是这也要求有一个本地的硬件解决方案来支持这种协议。

5.2 TLP 细节(TLP Details)

在 PCIe 中,高层次事务起源于发送方的 Device Core,终止于接收方的 Device Core。事务层会处理这些请求,其中,发送端的事务层组装 TLP,接收端的事务层解析 TLP。在这个过程中,每个设备的数据链路层和物理层也会参与包的组装。

5.2.1 TLP 的组包和拆包

如图 5‑2 所示的是链路的发送端组装 TLP 和接收端拆解 TLP 的一般流程。现在让我们讲一讲从一个包的生成,到它被传送到接收端的 Device Core 的各个步骤。下面列出了 TLP 组包和拆包的关键阶段,列出的编号与图 5‑2 中的编号相对应。

图 5‑2 PCIe TLP 的组包与拆包

发送方

  1. 设备 A 的 Device Core 向它的 PCIe 接口发送一个请求(具体 Device Core 是如何给 PCIe 接口发送请求的,这并不是 PCIe 协议或者本书的讨论范畴)。这个请求中包括:
  • 目标地址或者 ID(也就是路由信息)
  • 源端信息,例如 Requester ID 和 Tag
  • 事务类型/数据包类型(需要执行的命令,例如一个内存读取 MRd)
  • 数据荷载大小 payload size 和数据荷载内容(如果 TLP 需要带数据)
  • 流量类型(Traffic Class,用于分配数据包的优先级)
  • 请求的自身属性(No Snoop 无窥探、Relaxed Ordering 宽松排序,等等)
  1. 基于这个请求,事务层将会组建 TLP Header,并在其后附上数据荷载(如果有),以及如果启用并支持可选项的话也可以再附上 ECRC(End-to-End CRC)。随后 TLP 就会被放入一个虚拟通道 Buffer。这个虚拟通道会根据事务排序规则来管理 TLP 的顺序,并在向下转发 TLP 到数据链路层之前,确认接收方有足够的 Buffer 来接收一个 TLP。
  2. 当 TLP 到达数据链路层,它会被分配一个序列号(Sequence Number),并基于 TLP 的内容和序列号来计算出一个 LCRC(Link CRC)来附加在原 TLP 后。然后会将经过这些处理过程之后的 TLP 保存一个副本,这个副本会保存在数据链路层的重传 Buffer(Replay Buffer,也可称为 Retry Buffer)中,这是为了应对传输出错的情况。与此同时,这个 TLP 也会被向下转发至物理层。
  3. 物理层将会进行一系列的操作来准备对这个数据包进行串行传输,包括字节条带化(Byte Striping)、扰码(Scrambling)、编码(Encoding)以及并串转换(Serializing)。对于 Gen1 和 Gen2 的设备,当进行 8b/10b 编码时,会将 STP 和 END 这两个控制字符分别加在 TLP 的首端和尾端。最后,这个数据包通过链路进行传输。在 Gen3 操作模式中,STP 令牌(STP token)会被添加在 TLP 的首端,但是并不会在尾端加上 END,而是在 STP 令牌中包含 TLP 大小的信息来判断 TLP 的尾部位置。

接收方

  1. 在接收方(本例中是 Device B),为了发送包所做的一切准备现在都必须撤销。物理层将对比特流进行串并转换(deserialize)、对串并转换后的符号进行解码,然后再进行字节反条带化(un-stripes)。控制字符将被移除,因为它们仅在物理层有意义,然后这个数据包就会被向上转发至数据链路层。
  2. 数据链路层将会计算 CRC(具体一点是 LCRC)并与 TLP 中的 CRC 进行比较。如果 CRC 比较结果相同,那么就再检查序列号(Sequence Number)。如果都没有出现错误,那就把 CRC 和序列号都从 TLP 剥除,并随后将 TLP 向上转发给接收方事务层,与此同时要通过返回给发送方一个 Ack DLLP 来通知发送方这个 TLP 被成功接收。相反地,如果前面的过程中检查出了错误,那么就要返回给发送方一个 Nak DLLP,这样发送方将会使用它的重传 Buffer 来对 TLP 进行重传。
  3. 在事务层,TLP 被进行解码,并将 TLP 内的信息传递给 Device Core 来进行相应的操作。如果当前接收设备就是数据包的最终目的地,那么它可以检查 ECRC 错误,并在发现任何 ECRC 错误时报告给 Device Core。

5.2.2 TLP 结构

一个事务层包 TLP 中每个字段域的基本用法在表 5‑1 中进行了定义。

表 5‑1 TLP Header 的 Type 字段定义了事务不同种类

下面对表 5‑1 中的内容进行复述。

  • Header
  • 协议层次:事务层
  • 该组件用法:大小为 3 或 4DW(12 或 16Bytes)。Header 的格式会随类型而变化,但是 Header 也定义了一些参数,包括:
  • 事务类型(Transaction Type)
  • 目标地址、ID 等
  • 传输数据量大小(如果有数据)、字节使能(Byte Enable)
  • 属性(Attribute)
  • 流量类型(Traffic Class)
  • Data
  • 协议层次:事务层
  • 该组件用法:可选的 1-1024DW 大小的数据荷载,具体的大小由字节使能或者字节对齐的开始和结束地址来进行描述。需要注意指定的长度不能为 0,但是一个 0 长度的读取可以通过指定长度为 1DW 然后将字节使能全部置为 0 来进行近似处理(在某些情况下会使用)。来自 Completer 的结果数据虽然是未定义的种类,但是 Requester 并不使用它,因此就和指定 0 长度的目的等效了。
  • Digest/ECRC
  • 协议层次:事务层
  • 该组件用法:可选的功能。当需要使用时,ECRC 的大小永远为 1DW。

5.2.3 通用 TLP Header 格式(Generic TLP Header Format)

5.2.3.1 概括(General)

如图 5‑3 中,展示了一个 4DW 的通用 TLP Header 的格式和内容。在本节内,会对几乎所有事务的 TLP Header 中的公共字段进行总结,并会在稍后讨论与特定事务类型相关 Header 格式差异。

图 5‑3 通用 TLP Header 的各字段域

5.2.3.2 通用 Header 各字段摘要

表 5‑2 中对通用 TLP Header 中的每个字段的大小和用途进行了总结。需要注意的是,在图 5‑3 中被标注为“R”的字段是保留字段(reserve),应该被置为 0。

image.png

表 5‑2 通用 TLP Header 的各字段摘要

5.2.4 通用 TLP Header 详细说明(Generic TLP Header Details)

在接下来的几个小节中,我们将对图 5‑3 中展示的 TLP Header 的每一个字段都进行细节描述。

5.2.4.1 Header 的 Type/Format 字段编码含义

表 5‑3 中总结了 TLP Header 中 Type 字段和 Fmt 字段(Format)的编码含义。

image.png

表 5‑3 TLP Header 的 Type 字段和 Fmt 字段编码含义

5.2.4.2 Digest/ECRC 字段

TLP 的 Digest 位表示是否存在 ECRC(End-to-End CRC)。如果当前支持这个可选的特性,并且软件也启用了它,那么设备将会给自己产生的所有 TLP 都计算并且添加上一个 ECRC。需要注意,使用 ECRC 要求设备含有可选的 Advanced Error Reporting 寄存器,这是因为它的能力(Capability)和控制寄存器就位于 Advanced Error Reporting 寄存器中。

(l) ECRC 的生成和检查

ECRC 覆盖了所有在跨 Fabric 转发时不需要更改的字段。然而,当一个数据包在拓扑结构中移动时,有两个 bit 是可以合法的进行改变的:

  • Type 字段的 Bit 0:在一个配置事务通过一个 Bridge 时,这个配置事务有可能从 Type 1 变成 Type 0,因为这个 Bridge 的次级总线有可能就是配置事务的目标总线。在这个情况下,Type 地段的 bit 0 的值就会从 1 变成 0。
  • EP(Error/Poisoned)bit:当一个 TLP 在网络结构中移动时,如果与这个数据包相关的数据被认为是损坏的,那么就有可能引发这个 bit 值的改变。这是一种可选的特性,称为错误转发(error forwarding)。

(1) 谁来检查 ECRC

ECRC 的预定目标是 TLP 的最终接收者。对 LCRC(Link CRC)的校验是用来验证在当前给定链路上的传输没有出错,但是会在 Switch/Bridge 的出口端口(egress port)重新计算一个 LCRC,然后再转发给下一级链路,也就是说同一个 LCRC 的作用范围不会跨 Switch/Bridge,那么这将会使得 Switch/Bridge 这些路由元件内部发生的错误被掩盖。为了解决这个问题,就在 TLP 在 Requester 到 Completer 的整个传输过程中都加上一个不会改变的 ECRC(也就是这个过程中 ECRC 都不会被其他设备重新计算和替换)。当目标设备检查 ECRC 时,任何在整个传输过程中发生的错误都会极容易被发现。

关于 ECRC 校验中 Switch 的作用,PCIe 协议做了两个声明:

  • 如果一个 Switch 支持 ECRC 校验,那么它需要对 TLP 目的地为 Switch 自身时,对这个 TLP 中的 ECRC 进行校验。如果 TLP 的目的地并不是 Switch 自身,那么 Switch 必须在保持 ECRC 不变的前提下对其进行转发,把 ECRC 作为 TLP 不可分割的一部分。“On all other TLPs a Switch must preserve the ECRC (forward it untouched) as an integral part of the TLP.”
  • 注意,Switch 也可以对通过它的 TLP 进行 ECRC 检查。由 Switch 发现的 ECRC 错误的报告方法和其他设备一样,但是这不会改变 TLP 通过 Switch 的继续传输。“Note that a Switch may perform ECRC checking on TLPs passing through the Switch. ECRC Errors detected by the Switch are reported in the same way any other device would report them, but do not alter the TLPs passage through the Switch.”

5.2.4.3 使用字节使能(Using Byte Enables)

(l) 整体说明

类似 PCI 一样,对于有时传输大小或者起始/结束地址不是 DW 对齐时,PCIe 也需要一种机制来根据需要协调其 DW 对齐地址。为了达到这个目的,PCIe 利用了 2 个字节使能(Byte Enable)字段,如图 5‑3 中和表 5‑2 中所介绍,分别是首 DW 字节使能(First DW Byte Enable)和尾 DW 字节使能(Last DW Byte Enable),它们使得 Requester 可以对第一个 DW 和最后一个 DW 真正有效传输的字节进行限定。

(l) 字节使能规则

  1. 字节使能地各个 bit 是高有效的。如果某个字节使能 bit 值为 0,那么就表示数据荷载中相应的字节不应该被 Completer 使用,因为这个字节是无效的。若某个字节使能 bit 值为 1,那么就说明相应的字节应该被 Completer 使用。
  2. 如果有效的数据全都在一个单独的 DW 中,那么尾 DW 字节使能(Last DW Byte Enable)必须为 0000b。
  3. 如果 Header 中的 Length 字段表示了这次传输数据量大于 1DW,那么首 DW 字节使能(First DW Byte Enable)至少要有 1 个 bit 是有效的。
  4. 如果 Header 中的 Length 字段表示了这次传输数据量大于等于 3DW,那么首 DW 字节使能和尾 DW 字节使能都必须是相连的 bit 为 1。在这种情况中,字节使能仅能用来提供有效起始地址和结束地址与 DW 对齐地址的字节偏移量。
  5. 如果传输数据量大小为 1DW,那么才能允许只有首 DW 字节使能内是不连续为 1 的情况。
  6. 如果传输数据量大小为 1-2DW,那么才能允许首 DW 字节使能和第二 DW 字节使能内都是不连续为 1 的情况。
  7. 如果一个写请求,其 Length 字段表示其数据传输长度为 1DW,但是它的字节使能均为无效,这种情况对 Completer 不会有影响。
  8. 如果一个读请求,其 Length 字段表示其需要的数据传输长度为 1DW,但是没有字节使能有效,那么 Completer 会返回一个 1DW 数据荷载,这种数据荷载是未定义数据(undefined data)。这种情况可能被用作一种刷新机制(Flush mechanism),它利用事务排序规则,在这个 undefine data 的读请求完成包返回之前,强制之前发出的所有 posted write 输出到内存中。

(l) 字节使能示例

如图 5‑4 展示了字节使能字段是如何使用的。注意,数据传输长度必须从第一个 DW 中的任何有效字节延伸至最后一个 DW 中的任何有效字节。因为数据传输量大于 2DW,字节使能就只能用来标识这次传输中起始地址的位置(2d)和结束地址的位置(34d)。

图 5‑4 首 DW 字节使能和尾 DW 字节使能字段的使用

5.2.4.4 事务描述符字段(Transaction Descriptor Fields)

当事务在 Requester 和 Completer 之间移动时,必须要能够对各个事务进行唯一的标识,因为在任何时刻的 Requester 中都有可能有许多的拆分事务在排队。为了更好的进行标识,PCIe 协议在 TLP Header 中定义了多个重要字段,来组成一个唯一的事务描述符(Transaction Descriptor),如图 5‑5 所示。

图 5‑5 事务描述符字段

虽然事务描述符在 TLP Header 中并不是位置全连续的字段,但是这些不连续字段合起来可以一起描述事务的关键属性,包括:

(l) 事务 ID(Transaction ID)

事务 ID 由 Requester ID(Requester 的 BDF)和 TLP 的 Tag 字段共同组成。

(l) 流量类型(Traffic Class)

流量类型(Traffic Class,TC)是由 Requester 的 Device Core 来添加进 TLP 的,并且在拓扑结构中从 Requester 传输到 Completer 的过程中 TC 都不发生改变。在拓扑结构的每个链路中,TC 都映射到其中一个虚拟通道(Virtual Channel)。

(l) 事务属性(Transaction Attributes)

用于表示基于 ID 的排序(ID-based Ordering)、宽松排序(Relaxed Ordering)以及无窥探(No Snoop)的 bit 也存在于请求包中,被发送给 Completer。

5.2.4.5 带有数据荷载的 TLP 的一些额外规则

当一个 TLP 带有数据荷载时,就要遵从如下规则:

  1. Length 字段仅表示数据荷载的长度。
  2. 数据荷载的首字节(紧挨着 Header 的字节)的地址永远是最低位的。
  3. Length 字段永远表示的是整数 DW 的传输长度。对于不满整数 DW 的情况是使用首 DW 字节使能和尾 DW 字节使能来进行表示的。
  4. 在协议中有声明,当一个 Completer 在响应一个单独的 Memory 请求时如果返回了多个 TLP,那么中间的(也就是非首尾的)TLP 的数据荷载的地址必须结束于 RC 的 64byte 或 128byte 自然对齐的边界上。具体是那种边界是由一个可配置位称为 RCB(读完成边界,Read Completion Boundary)来控制的。所有的其他设备遵循 PCI-X 协议,并会将这种情况的 TLP 截断在 128byte 自然对齐边界上。
  5. 当发送 Message 请求时,Length 字段是保留字段,除非 Message 是带有数据荷载的,也就是 MsgD。
  6. TLP 的数据荷载一定不能大于设备控制寄存器(Device Control Register)中的最大数据荷载字段(Max\_Payload\_Size)。因为只有写事务会带有数据荷载,因此这种限制并不应用于读请求。接收方需要在被写入时检查是否存在 Max\_Payload\_Size 的违例,如果存在则认为这是一个畸形 TLP(Malformed TLP)。
  7. 接收方还需要检查 Length 字段和 TLP 实际传输的数据荷载长度。如果二者不相同则认为这是一个畸形 TLP(Malformed TLP)。
  8. 请求包中的起始地址和传输长度的组合信息,一定不能造成跨 4KB 边界的 Memory 访问。虽然这种检查是可选的,但是一旦发现了跨 4KB 边界访问的情况就认为这是一个畸形 TLP(Malformed TLP)。
原文: Mindshare
译者: Michael ZZY
校对: LJGibbs
文章来源:https://zhuanlan.zhihu.com/p/508501862

《PCI Express Technology 3.0》翻译系列

更多IC设计技术干货请关注FPGA的逻辑技术专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
10605
内容数
561
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息