4、PCIe Switch核心参数:端口数量与类型(上游/下游)、通道宽度(x1/x2/x4/x8/x16)、数据包路由机制(ID路由、地址路由、隐式路由)

各位工程师朋友,咱们接着聊。上一章我们把PCIe Switch的拓扑结构讲清楚了,这一章我打算深入它的“内脏”——也就是那些你在选型时不得不看的核心参数。

说实话,很多刚接触PCIe的工程师,拿到Switch的Datasheet就懵了。端口数量、通道宽度、路由机制……这些词看着都认识,但真到选型时,往往不知道该优先看哪个。我当年也踩过这个坑,所以今天咱们就把它彻底掰开揉碎。

4.1 端口数量与类型:上游与下游的“身份”差异

先讲端口。一个PCIe Switch,说白了就是一堆端口的集合。但端口不是平等的,它分两种:上游端口(Upstream Port)下游端口(Downstream Port)

怎么区分?很简单。离CPU近的那个叫上游,离设备近的那个叫下游。上游端口通常只有一个,负责和Root Complex(RC)通信。下游端口可以有多个,每个接一个Endpoint(EP)或者另一个Switch。

我在项目中遇到过一种情况:有人把下游设备接到了上游端口上,结果系统死活枚举不出来。嗯,这里要注意——上游端口和下游端口的电气特性虽然一样,但协议层的角色完全不同。上游端口只能连接RC或上游Switch,下游端口只能连接EP或下游Switch。你反过来接,链路能训练成功,但事务层包(TLP)的转发逻辑会乱套。

避坑指南: 我曾经在一个多级级联的项目里,因为搞混了上游和下游端口,导致整个PCIe树形结构无法正确枚举。后来花了整整两天才定位到问题。所以,画原理图时,请务必在端口旁边标注“UP”和“DP”,别偷懒。

端口数量怎么选?这取决于你的系统需要挂多少个设备。比如你有一个x16的CPU接口,想接4个x4的NVMe SSD,那你就需要一个至少带1个上游端口和4个下游端口的Switch。但要注意,端口数量越多,Switch内部的Crossbar(交叉开关)越复杂,延迟和功耗也会相应增加

4.2 通道宽度:x1、x2、x4、x8、x16 怎么选?

通道宽度,就是Lane的数量。x1就是1对差分线(TX+RX),x16就是16对。这个参数直接决定了带宽。

很多人觉得“通道越宽越好”,其实不然。我见过一个项目,CPU只支持x4的接口,结果选了个x16的Switch,白白浪费了12个Lane,还多花了钱。你想想看,通道宽度必须和上下游匹配

举个例子:

  • 上游端口是x8,下游接了4个x4的设备。这时候Switch内部需要做“带宽拆分”——把x8的带宽分给4个x4用。
  • 如果上游是x16,下游接了8个x1的设备,那就更浪费了。因为x1设备根本用不完带宽。

我个人习惯的做法是:先算总带宽需求,再反推通道宽度。比如你的下游设备总带宽需要32 GT/s(PCIe 3.0 x8),那上游至少也得是x8,否则就会成为瓶颈。

关键点: 通道宽度可以不对称。上游x16,下游可以同时接x8、x4、x1的设备。Switch会自动协商每个端口的宽度。但要注意,所有端口的通道宽度之和,不能超过Switch内部的总线带宽。否则就会出现拥塞。

另外,通道宽度还影响PCB布局。x16需要16对差分线,走线长度要等长,阻抗要控制。我建议你在设计初期就和Layout工程师沟通好,别等到布线时才发现空间不够。

4.3 数据包路由机制:ID路由、地址路由、隐式路由

这部分是Switch的核心中的核心。数据包(TLP)进入Switch后,怎么知道该往哪个端口走?靠的就是路由机制。PCIe定义了三种路由方式:ID路由、地址路由、隐式路由

4.3.1 ID路由:基于BDF(Bus:Device.Function)

ID路由是最常用的。每个PCIe设备都有一个唯一的BDF号,比如00:00.0。Switch内部维护一张路由表,根据TLP头部的BDF号,决定转发到哪个端口。

我记得有一次调试,发现某个设备总是无法被访问。查了半天,原来是Switch的路由表没有正确配置。说白了,ID路由依赖系统枚举时分配的BDF号。如果枚举顺序乱了,路由表就会出错。

ID路由的优点是精确,缺点是路由表需要动态更新。系统启动时,BIOS或OS会枚举所有设备,然后配置Switch的路由表。这个过程叫“配置空间扫描”。

4.3.2 地址路由:基于内存地址或IO地址

地址路由用于Memory Read/Write和IO Read/Write请求。Switch根据TLP中的目标地址,查找内部地址映射表,决定转发到哪个端口。

举个例子:CPU要写数据到某个设备的BAR空间,地址是0xF000_0000。Switch收到这个TLP后,会检查地址映射表。如果0xF000_0000属于下游端口3的设备,就把包转发到端口3。

地址路由的好处是灵活,不需要知道设备的BDF号。但坏处是,地址映射表需要提前配置好。如果地址冲突,或者映射表没更新,包就会丢。

个人经验: 我建议你在设计地址映射时,给每个设备分配独立的地址窗口,不要重叠。比如设备A用0xF000_0000-0xF000_FFFF,设备B用0xF001_0000-0xF001_FFFF。这样Switch的路由表会简单很多,调试也方便。

4.3.3 隐式路由:用于特殊消息

隐式路由最特殊。它不依赖BDF号,也不依赖地址,而是靠TLP头部的“路由类型”字段来决定。主要用于一些特殊消息,比如PME(电源管理事件)、Error Message等。

隐式路由的规则是:所有Switch端口都会收到这个包,但只有符合条件的端口才会处理。比如PME消息,会从下游端口广播到上游端口,最终到达RC。

你想想看,这种路由方式其实很像“广播”。但PCIe不允许随意广播,只有特定类型的消息才能用隐式路由。我刚开始学的时候,总觉得隐式路由很神秘,后来发现它其实就是一种“定向广播”。

4.4 三种路由的协同工作

在实际系统中,这三种路由是同时存在的。一个TLP进入Switch后,Switch会先检查TLP头部,判断用哪种路由方式:

  • 如果是Memory/IO请求,用地址路由。
  • 如果是Configuration请求,用ID路由。
  • 如果是特殊消息,用隐式路由。

Switch内部有一个路由引擎,它会根据TLP类型,自动选择对应的路由表。这个过程是硬件完成的,不需要软件干预。但路由表的内容,必须由软件(BIOS或驱动)在初始化时配置好。

注意: 我曾经在一个项目中,因为忘记配置地址路由表,导致所有Memory写请求都被Switch丢弃了。系统看起来能枚举,但一跑数据就死机。所以,路由表的初始化是PCIe系统稳定性的关键。建议你在调试时,先验证路由表是否正确。

4.5 选型实战建议

最后,我总结一下选型时的核心思路:

  1. 先定端口数量:数一下你需要挂多少个设备,留1-2个冗余端口。
  2. 再定通道宽度:计算总带宽需求,确保上游带宽不小于下游总带宽。
  3. 最后看路由能力:确认Switch支持ID路由和地址路由,并且路由表大小足够。

另外,别忘了看Datasheet里的“路由表深度”参数。有些低端Switch的路由表只有几十条,如果你的系统设备很多,可能会不够用。

嗯,这一章的内容就到这里。下一章我会讲Switch的流控和缓冲区管理,那才是真正考验系统设计能力的地方。咱们下回见。