PCIe基础回顾:从拓扑到物理层
讲NVMe之前,我觉得有必要先聊聊PCIe。毕竟NVMe就是跑在PCIe上面的协议,底层都不懂,上层肯定也玩不转。我见过不少工程师,NVMe命令背得滚瓜烂熟,一问PCIe事务层怎么工作的,立马卡壳。嗯,咱们今天就把这块补上。
PCIe拓扑结构:不是总线,是网络
传统PCI是共享总线架构,所有设备挂在一根线上,谁用谁申请。PCIe完全不一样,它用的是点对点连接。说白了,每个设备都有自己的专用通道,不用跟别人抢。
一个典型的PCIe系统包含这几个角色:
- Root Complex(根复合体):CPU和内存的代言人,所有事务的起点
- Switch(交换器):相当于网络交换机,把一条上游链路扩展成多条下游链路
- Endpoint(端点):真正的设备,比如NVMe SSD、GPU、网卡
- Bridge(桥):用来连接老式PCI/PCI-X设备,现在见得少了
我刚开始接触PCIe时,总觉得Switch就是个简单的信号中继器。后来调一个多NVMe SSD的系统才发现,Switch内部有复杂的路由逻辑,每个端口都有自己的VC(虚拟通道)和仲裁策略。选型选不好,性能直接腰斩。
关键点:PCIe拓扑是树形结构,从Root Complex出发,经过Switch,最终到达Endpoint。每个链路都是独立的,全双工通信。
事务层(TLP):PCIe的"快递包裹"
事务层是PCIe协议栈的最上层,负责生成和处理事务层包(TLP)。你可以把TLP想象成一个快递包裹——里面有收件地址、发件人、货物内容,还有校验信息。
TLP主要分这么几类:
| TLP类型 | 用途 | 我见过的坑 |
|---|---|---|
| Memory Read/Write | 读写内存空间,NVMe主要用这个 | 地址对齐不对,性能直接掉一半 |
| Configuration Read/Write | 枚举和配置设备 | 配置空间访问超时,设备没响应 |
| Message | 中断、错误通知等 | MSI-X配置错了,中断死活不来 |
| Completion | 对非Posted请求的回应 | Completion超时,驱动直接挂掉 |
每个TLP都有固定的格式:起始的帧标记(STP)、序列号、Header、数据负载(可选)、CRC校验(ECRC/LCRC),最后是结束标记(END)。Header里最关键的是Fmt(格式)和Type(类型)字段,决定了这个包是干啥的。
我的经验:调试NVMe驱动时,我经常用逻辑分析仪抓TLP。有一次发现写请求的地址总是不对,查了半天,原来是DMA引擎的地址寄存器配置反了。TLP里的Address字段清清楚楚写着0xFFFF...,一眼就看出问题了。
数据链路层(DLLP):保证不出错
数据链路层夹在事务层和物理层中间,干的是脏活累活。它的核心职责就两个:可靠传输和流量控制。
DLLP(数据链路层包)比TLP小得多,主要用来做:
- Ack/Nak协议:发送方每发一个TLP,接收方要回一个Ack或Nak。收到Nak就重传。我见过一个案例,链路信号质量差,Nak满天飞,吞吐量直接掉到原来的十分之一。
- 流量控制(Flow Control):接收方告诉发送方自己还有多少缓冲区空间。发送方根据这个信息决定发多少数据。说白了就是"你慢点,我快撑不住了"。
- 链路管理:链路的初始化、电源状态切换等。
数据链路层还负责给TLP加上序列号和LCRC(链路CRC)。序列号用来检测丢包,LCRC用来检测传输错误。这两个字段是硬件自动加的,软件完全感知不到。
注意:数据链路层的重传机制是硬件自动完成的,但重传次数多了会触发链路退化(Link Degradation)。我曾经遇到过一块NVMe SSD,因为PCB走线太长,信号衰减严重,链路从Gen4 x4自动降级到Gen3 x2,性能直接砍掉四分之三。
物理层:信号怎么跑
物理层是最底层,负责把数据变成电信号在差分对上传输。PCIe物理层分两部分:逻辑子层和电气子层。
逻辑子层干的事:
- 8b/10b编码(Gen1/Gen2)或128b/130b编码(Gen3+):保证DC平衡,方便时钟恢复
- 加扰(Scrambling):防止频谱尖峰,减少EMI
- 链路训练(Link Training):上电后自动协商速率和宽度
电气子层就是实实在在的差分信号、阻抗匹配、预加重这些。嗯,这块我其实不太擅长,毕竟我是做协议和软件的,硬件细节交给硬件工程师去操心。
不过有一点我得提醒你:链路训练状态机(LTSSM)是物理层最复杂的部分。从Detect到Polling,再到Configuration、L0(正常工作),中间有十几个状态。如果链路训练失败,设备就认不到了。我调试过一块板子,NVMe SSD死活枚举不出来,最后发现是参考时钟的抖动太大,链路训练一直卡在Polling状态。
一句话总结:PCIe四层协议栈——事务层负责"干什么",数据链路层负责"保证干成",物理层负责"怎么干"。NVMe跑在事务层之上,用Memory Read/Write TLP来传输命令和数据。
好了,PCIe基础就回顾到这儿。这些概念后面讲NVMe队列、PRP、SGL时都会用到,你心里有个底就行。