PCIe体系结构:层次化模型与拓扑结构
做硬件设计这些年,我遇到不少新人问:“PCIe到底长什么样?”
说白了,它就是一台精密的通信机器。这台机器有三层分工,外加一套成熟的连接体系。我个人习惯先理解层次化模型,再去看拓扑结构。今天我们就从内到外,把这套体系摸透。
层次化模型:三层架构
PCIe采用分层设计,从上到下分别是事务层、数据链路层、物理层。每层各司其职,又紧密配合。我在项目中调试链路时,最喜欢先看是哪层出了问题,能省不少时间。
| 层级 | 缩写 | 核心职责 | 处理的数据单位 |
|---|---|---|---|
| 事务层 | TL | 组装/解析事务层包(TLP),处理读写请求、完成消息 | TLP |
| 数据链路层 | DLL | 保证TLP无差错传输,管理链路状态 | DLLP |
| 物理层 | PHY | 串行化/解串,处理电气信号、链路训练 | PLP / 有序集 |
事务层(Transaction Layer)
事务层是最贴近软件的一层。它接收来自设备核心或CPU的请求,把数据、地址、属性打包成TLP。
TLP有四种类型:Memory、IO、Configuration、Message。我个人做存储卡项目时,最常打交道的就是Memory读写TLP。
TLP的头部格式因类型而异,我列一个Memory读写TLP的简化头部结构供参考:
Byte 0-3: Fmt + Type (指示格式和类型)
Byte 4-7: Length (数据载荷长度,单位DW)
Byte 8-15: Requester ID + Tag (请求者标识)
Byte 16-23: Address (目标地址) 或 First DW BE + Last DW BE
... Data Payload (0~1024 DW)
注意,TLP最大数据载荷是1024个双字(4KB),但实际设备通常只支持128或256字节。我建议设计时先确认设备能力,否则链路上会出现分割传输,影响性能。
数据链路层(Data Link Layer)
这一层负责链路的可靠传输。它给每个TLP加上序列号和CRC校验码,生成DLLP(数据链路层包)进行确认、重传、电源管理。
- ACK/NAK协议:发送端保存TLP副本,直到收到接收端的ACK。收到NAK则重发。我调试过一块老是丢包的FPGA板卡,最后发现是DLL层重传缓冲区溢出。嗯,这里要注意:重传缓冲区不能设太小。
- 流量控制(Flow Control):接收端通过DLLP通告自己的缓冲区剩余大小,发送端按量发送,防止丢数据。
- 错误检测:每收到一个TLP都做CRC校验,错误立即回复NAK。
物理层(Physical Layer)
物理层是真正的“电线工”。它把并行的TLP数据串行化成差分信号,通过一对发送、一对接收的Lane传出去。同时,它还要负责链路训练、速率协商、极性反转、扩频时钟同步等杂活。
为什么需要链路训练?
PCIe支持多速率(2.5GT/s、5GT/s、8GT/s等)。上电后双方不知道对方能力,得通过物理层的训练序列(TS1/TS2有序集)一步步握手。我记得有一次做Gen3链路兼容性测试,某款老主板训练到Gen3会失败,最后锁定物理层协商逻辑的timing不达标。折腾好几天。
| 物理子层 | 功能 |
|---|---|
| 逻辑子层 | 编解码(8b/10b、128b/130b)、扰码、有序集处理 |
| 电气子层 | 差分驱动、接收均衡、时钟恢复 |
物理层的数据单位是PLP(物理层包)和有序集。这些结构对软件几乎透明,但硬件工程师必须清楚。
三层之间的协作
数据从应用层向下走,逐层加工。我画张图帮大家理解:
拓扑结构:RC、Switch、Endpoint
PCIe的物理拓扑是一个树形结构。怎么理解呢?CPU端接一个根复合体(RC),RC下面挂Switch,Switch再分出去接多个Endpoint。简单、清晰、可扩展。
根复合体(Root Complex, RC)
RC是CPU和PCIe总线的桥梁。它内部集成了至少一个根端口(Root Port),每个根端口对应一个独立的PCIe域。
- RC负责将CPU的存储器访问转换成PCIe事务。
- 它生成配置请求,用于枚举总线上的所有设备。
- RC还处理中断、错误报告等系统级事务。
我调试的服务器主板上通常有2-4个根端口,分别接显卡、NVMe硬盘、网卡。设计时要注意每个根端口的Lane数分配,错了会影响性能。
交换机(Switch)
Switch是PCIe网络的核心扩展设备。它有1个上游端口(Upstream Port)连接RC,多个下游端口(Downstream Port)连接Endpoint。
它内部其实由两个或者多个逻辑PCI-to-PCI桥(PPB)背靠背组成。工作时遵循基于ID的路由规则:根据总线号、设备号、功能号决定转发路径。
端点(Endpoint)
Endpoint是PCIe树上的叶子节点。它不具备转发能力,只能作为请求者或完成者。
- 传统Endpoint:挂在Switch下游。
- 根端口集成Endpoint:直接挂在RC上(如显卡)。
端点内部必须实现完整的TL层、DLL层、PHY层。我见过一个做视频采集卡的客户,因为Endpoint的事务层没处理好Completer Abort,经常被操作系统报超时。
数据流动路径
举个例子,CPU从NVMe硬盘读数据:
- CPU发送内存读请求给RC。
- RC打包成Memory Read TLP,通过上游端口发往Switch。
- Switch解析TLP头部,根据目标地址把包转发到连接NVMe的下游端口。
- NVMe Endpoint收到TLP后解析,从闪存中读取数据,组装Completion with Data TLP原路返回。
- 一路上升,最终数据写入CPU指定的内存地址。
整个过程几乎没有软件介入,全靠硬件分层协作完成。为什么能做到?因为每一层都只处理自己的事。事务层不管路由,数据链路层不管地址,物理层只管传比特。真正做到了各扫门前雪。
| 组件 | 常用功能 | 是否包含事务层 |
|---|---|---|
| RC | 系统集成、配置、中断处理 | 是 |
| Switch | 扩展端口数、隔离流量 | 否(无TL层,仅有DLL+PHY) |
| Endpoint | 执行具体的I/O功能 | 是 |