1. PCIe概述:从并行总线到高速串行互联的演进
大家好,我是老李。做芯片验证十几年,PCIe协议算是我打交道最多的接口之一了。今天咱们聊聊PCIe的来龙去脉。说实话,每次带新人时,我都会先问一句:你知道为什么PCIe能取代PCI吗?
嗯,这个问题看似简单,但背后藏着整个总线架构的变革逻辑。
1.1 PCIe总线的发展历史
先说说PCI总线。上世纪90年代,Intel推出了PCI总线标准。那时候的电脑里,显卡、网卡、声卡都插在PCI插槽上。PCI总线是并行架构,32位或64位数据线同时传输。听起来挺快,对吧?
但并行总线有个致命问题——信号同步。随着频率提高,数据线之间的时延偏差越来越大。我记得当年做PCI验证时,最头疼的就是setup/hold time。频率一高,信号就乱套。PCI的最高频率也就33MHz或66MHz,带宽撑死了533MB/s。
后来有了PCI-X,算是PCI的增强版。频率提到了133MHz,甚至266MHz。但并行总线的天花板就在那里。你想想看,64根数据线要同时到达接收端,频率越高,布线难度呈指数级上升。
2003年,PCI-SIG组织发布了PCIe 1.0标准。这次彻底换了思路——从并行改成串行。单通道2.5GT/s的速率,x16链路就是40GT/s。更重要的是,PCIe采用差分信号对,抗干扰能力强多了。
我在项目中遇到过一件事:某款芯片的PCIe接口在实验室跑得好好的,一到客户现场就频繁掉链子。查了三天,最后发现是PCB上PCIe差分对的等长没做好。嗯,串行总线对信号完整性要求极高,这个后面会细讲。
PCIe的发展速度很快:
| 版本 | 发布年份 | 单通道速率 | x16带宽 |
|---|---|---|---|
| PCIe 1.0 | 2003 | 2.5 GT/s | 8 GB/s |
| PCIe 2.0 | 2007 | 5.0 GT/s | 16 GB/s |
| PCIe 3.0 | 2010 | 8.0 GT/s | 32 GB/s |
| PCIe 4.0 | 2017 | 16.0 GT/s | 64 GB/s |
| PCIe 5.0 | 2019 | 32.0 GT/s | 128 GB/s |
注意:PCIe 3.0开始采用了128b/130b编码,相比之前的8b/10b编码,效率从80%提升到了98.5%。这是我个人觉得最巧妙的设计之一。
1.2 PCIe与PCI/PCI-X的区别
说白了,PCIe和PCI完全是两套东西。虽然软件层面兼容,但硬件架构天差地别。
第一,拓扑结构不同。 PCI是共享总线架构。所有设备挂在同一条总线上,谁想通信得先申请总线使用权。这就好比一条单车道,所有车都得排队。PCIe则是点对点连接,每个设备都有自己的专用通道。Root Complex和Endpoint之间是直连的,不需要抢总线。
第二,数据传输方式不同。 PCI是并行传输,32根或64根数据线同时传。PCIe是串行传输,用差分对传数据。你可能会问:串行不是更慢吗?其实不然。串行可以跑很高的频率,而且没有并行信号的同步问题。
第三,可扩展性不同。 PCI总线上挂的设备越多,带宽就被分得越薄。PCIe通过Switch可以扩展出很多端口,每个端口都有独立的带宽。我在做服务器芯片验证时,经常要挂十几个NVMe SSD,PCIe的Switch拓扑结构就特别适合这种场景。
第四,热插拔支持。 PCI基本不支持热插拔。PCIe从设计之初就考虑了热插拔,这在服务器和数据中心场景中太重要了。我记得有一次客户要求我们的芯片支持热插拔,结果发现PCIe的链路训练和初始化流程天然就支持这个功能。
我个人习惯:在验证PCIe设备时,一定要测试热插拔场景。很多芯片在正常上电时链路训练没问题,但热插拔时就会出各种奇怪的问题。
1.3 PCIe的拓扑结构
PCIe的拓扑结构其实很简单,就三个核心组件:Root Complex、Switch、Endpoint。
Root Complex(RC):这是整个PCIe层次结构的根。它连接CPU和内存子系统,负责生成配置请求、I/O请求、内存请求等。说白了,RC就是PCIe世界里的"老大"。在x86架构中,RC通常集成在CPU内部或芯片组中。
Switch:这是PCIe的"交通枢纽"。它可以把一个上游端口扩展成多个下游端口。Switch内部有路由逻辑,知道哪个设备在哪个端口后面。我曾经调试过一个bug,Switch的配置空间读回来全是0,查了半天发现是复位时序没处理好。
Endpoint(EP):这是PCIe的"终端设备"。比如显卡、NVMe SSD、网卡等。Endpoint只能作为事务的发起者或完成者,不能像Switch那样转发事务。
还有一种特殊的设备叫Bridge,用于连接PCIe和传统的PCI/PCI-X总线。不过现在新设计中很少见了。
拓扑结构的关键点:
- 每个链路都是点对点的,没有共享总线
- 设备之间通过事务层包(TLP)通信
- 配置空间通过配置读写事务访问
- 每个设备有唯一的Bus:Device:Function编号
我曾经踩过一个坑:在验证Switch时,以为所有下游端口的行为都一样。结果发现不同端口的链路训练参数可能不同,尤其是去加重和摆幅设置。所以,验证时一定要覆盖所有端口。
嗯,说到链路训练,这就是咱们下一章要讲的内容了。PCIe的链路训练和初始化是整个协议中最核心、也最容易出问题的部分。我做了这么多年验证,链路训练相关的bug占了PCIe总bug数的40%以上。
你想想看,两个设备上电后,怎么知道对方的存在?怎么协商速率和链路宽度?怎么保证信号质量?这些都是链路训练要解决的问题。
好了,这一章就到这里。PCIe的基本概念搞清楚了,后面咱们才能深入聊链路训练的细节。