PCIe分层架构:事务层、数据链路层、物理层的功能与作用

聊PCIe,绕不开它的分层架构。很多初学者会问:为什么搞三层?直接传数据不行吗?

我的回答是:分层就像快递系统。你只负责下单(事务层),仓库分拣打包(数据链路层),快递员开车送货(物理层)。任何一层出问题,都不影响其他层重构。我在项目里吃过亏,有一回物理层链路不稳,但事务层代码一句没改,这就是分层的好处。

事务层(Transaction Layer)——协议的核心大脑

事务层是离软件最近的一层。它处理的是“事务”,说白了就是一次完整的请求-响应交互。

  • 主要职责:封装和解封装TLP(Transaction Layer Packet)。软件写BAR空间、发起DMA,最终都变成某一类TLP。
  • 事务类型:Memory、IO、Configuration、Message。最常见的是Memory读写,占了80%以上流量。
  • 路由机制:基于地址路由(Memory/IO)、ID路由(Completion)、隐式路由(Message)。我建议你重点掌握地址路由,实际项目中99%的调试点都在这里。
我个人习惯:画流程图时,把事务层画成一个“翻译官”。它把软件读写请求翻译成统一的TLP格式,再往下扔。反过来,收到对端TLP,它解析后通知软件。

举个实例。CPU读某个MMIO地址,事务层先查这个地址落在哪个BAR范围内,然后构造一个Memory Read TLP。TLP里包含:Fmt/Type字段告诉下层这是读请求,Requester ID标明谁发的,Tag用于区分多个未完成的请求。

// TLP包头格式(简化)
Byte 0: Fmt[1:0] + Type[4:0]
Byte 1: Traffic Class(TC) + Reserved
Byte 2-3: Length(以DW为单位,数据部分长度)
Byte 4-7: Requester ID(Bus:Device:Function)
Byte 8-11: Tag + Last/BE
Byte 12-15: Address(配置空间或Memory地址)

我记得有一次调试NVMe SSD,发现DMA写总是超时。抓逻辑分析仪看TLP包,发现Requester ID写错了——下游桥设备重映射时把Bus号改了。嗯,事务层的ID路由不能想当然。

数据链路层(Data Link Layer)——可靠传输的保险杠

事务层只管生成TLP,但TLP在传输中可能丢包、错位。数据链路层就是干这个的——保证两个直连设备间的TLP可靠到达。

核心机制有两点:

  • 序列号+CRC:每个TLP前加12位序列号,尾部加32位LCRC。收方检查CRC,用序列号判断顺序和丢包。
  • ACK/NAK重传:收方正确收到后会送ACK;如果CRC错误或序列号跳变,就送NAK要求重传。我见过一个线上案例:某板卡数据链路层收到连续CRC错误,不断NAK导致链路退到Gen2,最终排查出来是电源纹波太大。
千万不要忽视数据链路层的“重传风暴”。我曾经调试一块FPGA加速卡,发现PCIe吞吐量只有理论值的60%。抓链路层NAK包,发现FPGA端内部FIFO不够深,导致背压反传给数据链路层,不断重传。换了个大FIFO就好了。

数据链路层还有流控(Flow Control)功能。每个VC有独立的信用量(Credits),用来告诉对端我还有多少接收空间。信用量不足时,事务层会暂停发送TLP。你想想看,如果没有流控,发送端一股脑往外扔,接收端缓冲区撑爆,整个链路就崩了。

功能事务层数据链路层
核心职责生成/解析TLP保证TLP可靠传输
关键机制路由、事务分类序列号、CRC、ACK/NAK、流控
出错处理返回错误Completion重传
与软件关系直接交互(配置/中断)对软件透明

物理层(Physical Layer)——从比特流到差分的魔法

物理层,真的就是“物理”的层。它负责把数据链路层交下来的DLLP(Data Link Layer Packet)和TLP转换成串行比特流,通过差分信号发出去。

  • 编码方式:Gen1/Gen2用8b/10b编码(每8位数据变成10位传输),Gen3/Gen4用128b/130b编码(效率更高)。我建议你记住一个点:8b/10b编码会损失20%带宽,所以Gen1/Gen2理论带宽要乘0.8才是有效值。
  • 链路训练:物理层包含LTSSM(Link Training and Status State Machine)。上电时,双方通过LTSSM协商速率、宽度、极性。我见过一个坑:某CPU插槽触点氧化,导致Gen3链路训练失败,反复回退到Gen2,系统启动慢得像蜗牛。
  • Lane反转与极性翻转:PCB布线不可能100%等长,物理层支持自动翻转。但注意,有些老版驱动不兼容极性翻转,我踩过这个坑,后来加了一段寄存器配置才搞定。

物理层调试口诀:

  • 链路不上去 → 先看LTSSM状态机停在哪一步(Polling、Configuration、Recovery等)
  • 速率不对 → 查双方能力寄存器(Device Capabilities 2)
  • 丢包严重 → 量眼图,看信号质量,或者换根线

我记得有一次调试远程服务器,PCIe链路死活上不了Gen4。我让现场同事把设备拔了重插,还是不行。最后发现BIOS里有个“PCIe Speed”选项被设成了“Gen3”,改过来就正常了。物理层的初始化,很多时候被BIOS/固件限制住了。

分层架构与数据流示意图

PCIe分层架构与数据流 事务层(Transaction Layer) 生成/解析TLP包 地址路由 / ID路由 / 隐式路由 数据链路层(Data Link Layer) 序列号 + LCRC ACK/NAK重传 / 流控 物理层(Physical Layer) 8b/10b 或 128b/130b 编码 LTSSM 链路训练 / 差分信号 数据流方向:事务层 → 数据链路层 → 物理层 → 对端设备(反方向同理)

从上图你能看到:数据从上往下流。事务层把读写请求变成TLP,交给数据链路层加“防护壳”,再交给物理层变成真正的比特流送到对端。反过来也一样。

在实际调试中,我会先锁定问题在哪一层。比如配置空间读到全F,大概率是物理层没训练好。如果TLP一直收不到Completion,可能是数据链路层流控堵住了。定位清楚后再下手,效率高很多。

避坑总结:

  • 事务层:小心Requester ID和Tag不匹配导致的超时
  • 数据链路层:监控重传计数,异常增加说明物理层信号质量有问题
  • 物理层:链路训练失败后检查LTSSM状态,不要盲目换硬件

嗯,这一章的内容差不多就是这些。记住三层各干各的,出了问题一层一层排查,基本都能找到根因。