✨前言:
在PCI Express (PCIe) 技术中,数据包的路由方式对于确保信息能够高效、准确地传送至目标设备至关重要。PCIe定义了几种路由方式,主要有以下几种。
🌟地址路由(Address Based Routing)
这是最基本的路由方式,PCIe设备利用目的地址信息来决定数据包的路由路径。目的地址通常包括目标设备的总线号、设备号和功能号。在经过每一个交换节点时,基于这些信息来决定数据包是向下一个交换节点转发,还是到达了最终目标。
🌟ID路由(ID Based Routing)
在这种路由方式中,每个PCIe设备或端点都有一个唯一的ID,这个ID在数据包中用于识别目标设备。这种方式常用于结束点到结束点的直接信号传输,在多点传输场景下,尤其是在那些具有复杂拓扑结构的系统中,ID路由可以非常有效。
🌟隐式路由(Implicit Routing)
这种路由方式主要用于处理某些特定类型的数据包,如功率管理事件或热管理事件。这些数据包不需要明确的目标地址,因为它们通常由系统中的所有设备或者由特定处理这类事件的设备处理。隐式路由依赖于系统硬件和固件的内建规则来正确地处理和转发这些数据包。
具体采用哪一种路由方式是由TLP的类型所决定的,如下表所示:
📌注:AtomicOp是PCIe Spec V2.1新增的内容,有兴趣的可以自行阅读V2.1的相关内容。
📌注:一般情况下,Message都是使用模糊路由(Implicitly Routing)的,但是也有PCIe设备厂商自定义的Message会使用地址路由或者ID路由。
可能有的人要有疑惑了,既然Message可以使用地址路由或者ID路由,为什么还要单独搞出来一个模糊路由呢?原因很简单,使用模糊路由可以广播Message到每一个设备,采用其他的路由方式必须明确指定是哪一个设备。
那么PCIe中是如何来判断TLP的类型的呢?又是如何判断其为Request还是Completion的呢?实际上是通过TLP Header的Format和Type部分来确定的,如下图所示:
在PCI Express (PCIe) 架构中,事务层数据包(Transaction Layer Packets, TLPs)是数据通信的基本单位。TLPs用于在设备间传输数据、内存读写请求以及控制信息。TLP的类型、是否为请求(Request)还是完成(Completion)报文等,都通过TLP的头部信息来识别。
⭐️TLP头部信息
TLP头部包含了多个字段,其中一些关键字段用于指示TLP的类型以及它是请求还是完成报文:
格式(Format):指示TLP头部的长度和布局,不同类型的TLPs(如内存读/写、I/O读/写、配置读/写等)会使用不同的头部格式。
类型(Type):这是一个关键字段,它直接指示了TLP是什么类型的数据包。例如,内存读请求、内存写请求、I/O读写请求、配置读写请求或者是完成报文(用于响应之前的某个请求)。
请求者ID(Requester ID):在请求TLPs中,这个字段指示了发起请求的设备。 目的ID(Destination ID):在完成TLPs中,这个字段用于指示响应应当发送到哪个设备。
⭐️区分请求和完成
通过类型(Type)字段区分:TLP头部中的类型字段是区分TLP是请求还是完成报文的关键依据。例如,内存读请求和内存写请求被明确标记为请求类型,而完成报文则有其特定的标识符来指明是作为之前某个请求的响应。
格式字段辅助判断:虽然格式字段主要描述的是头部的大小和布局,但通过它与类型字段的组合,可以更确切地识别TLP的具体类型和性质。
下面就跟着我来详细了解一下这三种路由
✨一、ID Routing
ID 路由(ID Routing)有的时候也被称为BDF路由,即采用Bus Number、Device Number和Function Number来确定目标设备的位置。这是一种兼容PCI和PCI-X总线协议的路由方式,主要用于配置请求(Configuration Request)的路由,在PCIe总线中,其还可以被用于Completion和Message的路由。
TLP的Header有3DW的和4DW的,其中4DW的Header一般只用于Message中。使用ID路由的TLP Header以下两张图所示,第一个为3DW Header,第二个为4DW Header:
对于Endpoint来说,其只需要检查TLP Header中的BDF是否与自己的BDF一致,如果一致,则认为是发送给自己的,否则便会忽略该TLP。
📌注:采用ID路由的TLP Header中并未包含Requester的ID(BDF),那么Completer怎么确定Requester的位置呢?实际上这个问题并不难回答,因为ID路由主要用于配置请求和Completion,偶尔也用于一些厂商自定义的Message。首先,配置请求的Requester只能是Root,所以不需要确定其位置;再之,Completion用于对其他路由方式的回应,如地址路由中包含了Requester的BDF;最后,Message是Posted型的,即其根本不需要Completion,自然也就不需要Requester的BDF了。
📌注:实际上PCIe是一种点对点(Point-to-Point)的通信方式,即每个链路只能连接一个设备,因此大部分情况下使用5bit的空间来描述Device Number完全是多余的。为此,PCIe Spec提出了ARI格式,这里暂时不详细介绍了,有兴趣的可以自行阅读PCIe Spec的相关内容。
对于Switch来说,则需要根据TLP Header中的BDF来判断,这个TLP是给自己的还是给自己下属的其他设备的。如下图所示:
🌟请求者ID的作用
请求者ID(Requester ID)是一个重要字段,用于标识发起TLP请求的设备。在PCIe中,每个设备拥有一个唯一的ID,称为Bus/Device/Function(BDF)编号。这个ID确保了即使在复杂的系统拓扑中,完成者也能够确定并发送响应到正确的请求者。
🌟TLP中的请求者ID
对于请求TLP,无论是用于读操作还是写操作,头部中都会包含请求者ID字段。这个字段确保了,当完成者完成操作并需要发回完成(Completion)TLP时,知道将响应发送至何处。
对于完成TLP,头部包含的是完成者ID(Completer ID),这是因为响应需要标识出是哪个设备完成了操作。同时,完成TLP还包含了一个标签(TAG)字段,这个标签在请求时由请求者生成,并由完成者在生成完成TLP时复制过去,这样请求者就可以匹配响应到它原始的请求。
✨二、Address Routing
地址路由(Address Routing)的地址包括IO和Memory。对于Memory请求来说,32bit的地址使用3DW的Header,64bit的地址使用4DW的Header。而IO请求则只能使用32bit的地址,即只能使用3DW的Header。
注:再次强调,IO请求是为了兼容早期的PCI设备的,在新的PCIe设备中禁止使用。
3DW和4DW的TLP Header分别如以下两张图所示:
当Endpoint接收到采用地址路由的TLP时,其会根据该TLP Header中的地址信息和自己的配置空间中的BAR寄存器来判断这个TLP是不是自己的。如下图所示:
Switch的地址路由机制如下图所示:
✨三、Implicit Routing
模糊路由(Implicit Routing,又译为隐式路由)只能用于Message的路由。PCIe总线相对于PCI总线的一大改进便是消除了大量的边带信号,这正是通过Message的机制来实现的。
PCIe定义的Message主要有以下几种类型:
1.Power Management(电源管理): 这类消息用于管理设备的电源状态,比如将设备置于不同的睡眠状态(L1, L2等),或者唤醒设备。这对于节能和热管理非常关键。
2.INTx Legacy Interrupt Signaling(INTx传统中断信号): 尽管PCIe设备推荐使用基于消息的中断(MSI或MSI-X),但为了向后兼容,PCIe也支持通过特殊消息来模拟传统的PCI中断线(INTA,
INTB, INTC, INTD)。
3.Error Signaling(错误信号): PCIe设备和交换机可以通过发送特定的错误消息来报告诸如不可纠正错误、可纠正错误等问题。这些消息对于确保系统稳定运行和及时诊断故障至关重要。
4.Locked Transaction Support(锁定事务支持): 用于支持特定类型的原子操作,在确保数据一致性和事务的原子性方面非常重要。
5.Hot Plug Signaling(热插拔信号): 这类消息支持系统动态地检测和配置新增或移除的设备,比如在不需要关闭电源的情况下添加或移除扩展卡。
6.Vendor‐Specific Signaling(厂商特定信号): 这使得厂商可以定义自己特定的消息类型进行通信和控制,为设备制造商提供了设计灵活性。
7.Slot Power Limit Settings(插槽功率限制设置): 用于传递有关插槽可提供给插入设备的最大功率限制的信息,有助于电源管理和避免过载。
所有采用模糊路由的TLP的Header都是4DW的,具体如下图所示:
其中Type决定了模糊路由的类型,具体如下图所示:
000b: 路由到RC
001b:使用地址路由
010b: 使用ID路由
011b:来自RC的广播报文
100b:本地消息,在接收端结束(legacy中断消息使用这种报恩格式,传递来自PCI总线的中断报文)。
101b:用于PCIe电源管理(PME_TO_Ack报文使用)
110b-111b:保留字段
当一个Endpoint收到一个Message TLP,检查TLP Header,如果是RC的广播Message(011b)或者该Message终结于它(100b),它就接受该Message。当一个Switch收到一个Message TLP,检查TLP Header,如果是RC的广播Message(011b),则往它每个下游端口复制该Message然后转发。如果该Message终结于它(100b),则接受该TLP。如果下游端口收到发给RC的Message,则往上游端口转发。