1. 从一根插槽说起PCIE接口协议到底在解决什么问题很多人第一次接触PCIE是在装机的时候把显卡往主板那条最长的插槽里一插拧上螺丝就完事了。但如果你做过驱动开发、板卡调试或者服务器运维就会知道这条插槽背后藏着一整套相当讲究的协议体系。PCIE全称Peripheral Component Interconnect Express中文一般叫“高速外围组件互连标准”它本质上是一套点对点、全双工、基于数据包交换的高速串行总线协议。注意这几个关键词点对点意味着每条链路只连接两个设备不像早期的PCI总线那样大家共享一条并行总线全双工意味着收发可以同时进行基于数据包则说明它借鉴了网络通信的思路用TLPTransaction Layer Packet来承载事务。那它到底解决了什么问题简单说就是带宽和扩展性。早期的PCI总线是并行共享架构所有设备抢一条总线频率上不去引脚还多。PCIE改用串行差分信号每条lane用两对差分线一对发一对收频率可以拉得很高而且可以通过增加lane的数量线性扩展带宽。这就好比原来是一条乡间小路大家挤着走现在改成了多车道高速而且每条车道还能独立提速。这套协议适合谁来深入了解我梳理了一下大致是这几类人一是做硬件设计的需要选型、布线、做信号完整性分析二是做驱动和固件的要处理枚举、配置空间、中断和DMA三是做系统集成和运维的经常碰到掉卡、降速、兼容性这些糟心事四是做FPGA和加速卡开发的Xilinx PCIE、PCIE仿真这些词基本天天见。不管你是哪一类理解PCIE协议的核心机制都能让你在遇到问题时少走很多弯路。接下来我会从协议分层、枚举过程、带宽计算、常见故障排查、仿真验证这几个角度把PCIE这套东西掰开揉碎讲清楚。内容会偏实战穿插一些我自己踩过的坑和总结出来的经验尽量让刚入门的朋友也能看懂同时让有基础的同行也能捞到点干货。2. PCIE协议分层架构与核心机制拆解2.1 三层结构事务层、数据链路层、物理层PCIE协议在逻辑上分为三层从上到下依次是事务层Transaction Layer、数据链路层Data Link Layer和物理层Physical Layer。这个分层思路和网络协议栈很像每一层各司其职上层不用关心下层的实现细节。事务层是最靠近软件的一层它负责组装和解析TLP。你发出的一个内存读写请求、一个配置读写请求最终都会被封装成TLP。事务层还管着流量控制Flow Control通过Credit机制确保接收端有足够的缓冲区避免发出去的数据被丢掉。我个人的理解是事务层就像快递公司的下单系统你告诉它要寄什么、寄到哪它负责把订单信息打包好。数据链路层夹在中间主要干两件事一是给TLP加上序列号Sequence Number和LCRCLink CRC校验保证传输的可靠性二是负责ACK/NAK重传机制。如果接收端发现某个TLP的LCRC校验失败就会回一个NAK发送端收到后重传。这一层还生成DLLPData Link Layer Packet用于链路管理和流量控制信用的更新。说白了数据链路层就是快递公司的中转站负责核对包裹有没有损坏坏了就要求重发。物理层是最底层直接和信号打交道。它负责把数据链路层下来的数据做8b/10b或者128b/130b编码然后通过差分信号发送出去。物理层还管理着链路的训练Link Training和状态机LTSSM链路能不能起来、跑多快、用几条lane都是物理层在协商。这一层就像公路本身路修得好不好、几车道、限速多少直接决定了上面能跑多快。提示很多人调试PCIE问题时只盯着事务层看其实大量链路问题都出在物理层的LTSSM状态机上。用lspci -vv看链路状态时LnkSta那一行显示的speed和width就是物理层协商的结果如果和预期不符优先查物理层。2.2 配置空间PCIE设备的身份证每个PCIE设备都有一块配置空间Configuration Space这是协议规定必须实现的。传统PCI的配置空间是256字节PCIE扩展到了4096字节。前256字节兼容PCI后面的是PCIE扩展能力结构Extended Capabilities。配置空间里最关键的是基地址寄存器BARBase Address Register。设备通过BAR告诉系统“我需要多大一块地址空间是内存空间还是IO空间。”系统在枚举时会给BAR分配具体的基地址。如果BAR配置错了设备就没法被正确访问表现出来就是设备能识别但驱动加载失败或者干脆认不到设备。配置空间的前64字节是标准头部里面有Vendor ID、Device ID、Class Code、Command、Status等字段。Vendor ID和Device ID是设备的身份标识驱动就是靠这两个值来匹配设备的。Class Code表示设备类型比如0x020000是以太网控制器0x030000是显示控制器。Command寄存器里有几个关键位比如Memory Space Enable、Bus Master Enable如果这两个位没置起来设备的内存空间就访问不了DMA也做不了。我遇到过好几次这样的情况设备明明在lspci里能看到但驱动就是probe失败。后来一查发现是BIOS没有正确分配BAR空间或者BAR的大小和实际需求不匹配。这种问题在嵌入式平台和国产主板上尤其常见因为BIOS的PCIE枚举实现质量参差不齐。2.3 TLP类型与事务模型PCIE的事务类型主要有这么几类Memory Read/Write、IO Read/Write、Configuration Read/Write、Message。其中Memory事务用得最多驱动读写设备寄存器、DMA传输数据底层都是Memory事务。每个TLP都有一个Header里面包含Requester ID、Tag、Address等字段。Requester ID标识发起方Tag用于匹配请求和完成Completion。这里有个坑Tag字段的位数决定了同一时刻能有多少个未完成的请求。早期PCIE的Tag是5位最多32个未完成请求后来扩展到8位能到256个。如果你的设备在高负载下性能上不去可以查查是不是Tag数量不够导致请求被阻塞了。Completion TLP是响应Memory Read、IO Read、Config Read这些需要返回数据的事务的。Completion里有个Status字段如果返回的是Unsupported RequestUR或者Completer AbortCA说明请求出了问题。AERAdvanced Error Reporting就是靠这些状态位来报错的。2.4 中断机制INTx、MSI、MSI-XPCIE支持三种中断方式传统的INTx、MSIMessage Signaled Interrupt和MSI-X。INTx是兼容PCI的老方式用带外信号线效率低现在基本不推荐用了。MSI是通过写一个特定地址来触发中断本质上是Memory Write事务。MSI-X是MSI的增强版支持更多的中断向量而且每个向量可以独立配置地址和数据。在实际项目里我强烈建议用MSI-X。原因很简单MSI-X支持的中断向量多可以做到每个队列一个中断避免多个队列共享一个中断导致的锁竞争。而且MSI-X的配置更灵活每个向量的地址和数据都可以单独设置。很多高性能网卡和NVMe SSD都是靠MSI-X来实现多队列中断的。配置MSI-X的时候要注意首先要检查设备是否支持MSI-X能力结构然后要正确设置Message Control寄存器里的Table Size和Function Mask。Table Size是只读的告诉你设备支持多少个向量Function Mask可以临时屏蔽所有中断。Table Offset和PBA Offset指向MSI-X Table和Pending Bit Array在BAR空间里的位置这两个偏移必须正确否则中断就乱了。3. PCIE枚举过程系统是怎么发现你的设备的3.1 枚举的整体流程PCIE枚举是系统启动时由固件BIOS/UEFI或者操作系统完成的。整个过程大致是这样的首先扫描总线0上的设备读取每个设备的Vendor ID如果是0xFFFF说明没有设备。对于存在的设备读取它的Header Type判断是普通设备还是桥设备。如果是桥就继续扫描桥下面的总线。这个过程递归进行直到把所有总线、设备、功能都扫一遍。枚举的核心任务是分配总线号和地址空间。每个桥下面挂的总线号是动态分配的BAR空间也是动态分配的。系统需要确保不同设备之间的地址空间不冲突同时尽量把设备放在合适的地址范围内。这里有个细节值得说PCIE的枚举是从上到下、深度优先的。系统先给根桥分配总线号然后扫描根桥下面的设备。遇到桥就继续往下扫扫完再回来扫下一个设备。这种深度优先的方式保证了总线号的连续性但也意味着如果某个桥下面的设备很多枚举时间会比较长。3.2 BAR空间分配的那些坑BAR空间分配是枚举里最容易出问题的地方。每个设备的BAR都声明了自己需要多大的空间系统需要找到一块足够大的、对齐的、不冲突的地址范围分配给它。BAR的大小是怎么确定的其实很简单往BAR里写全1然后读回来读回来的值里低位为0的位数就表示需要的大小。比如读回来是0xFFFFF000说明低12位是0需要4KB空间。这个机制叫“BAR sizing”是PCI/PCIE标准规定的。但实际中经常遇到的问题是系统分配的地址空间不够或者BIOS的枚举实现有bug导致某些BAR没分配上。表现出来就是设备能识别但驱动加载失败或者访问设备寄存器时返回全F。我遇到过一块国产网卡在某个主板上死活认不到换到另一块主板上就正常。后来用lspci -vv一看发现BAR的地址是0根本没分配。刷了主板BIOS就好了。注意如果你在做嵌入式开发自己写枚举代码一定要处理好BAR sizing和地址对齐。地址对齐的规则是BAR的大小是多少基地址就必须按多少对齐。比如需要4KB空间的BAR基地址必须是4KB对齐的。3.3 总线号、设备号、功能号PCIE的拓扑用总线号Bus、设备号Device、功能号Function来标识一个具体的设备。总线号是桥分配的设备号是物理位置决定的功能号表示一个物理设备里的多个功能。一个PCIE设备最多可以有8个功能每个功能都有自己的配置空间。比如一个双口网卡可能就是一个设备两个功能每个功能对应一个网口。操作系统会把每个功能当成一个独立的设备来看待。BDFBus:Device.Function的格式是XX:YY.Z比如00:1f.2。在Linux下用lspci看设备时第一列就是BDF。这个编号在调试时很有用因为你可以通过BDF精确定位到某个设备然后用setpci命令直接读写它的配置空间。3.4 枚举失败的常见原因枚举失败的原因很多我整理了几类常见的第一类是物理层问题。链路根本没训练起来LTSSM卡在Polling或者Configuration状态。这种情况用lspci看不到设备dmesg里可能会有link down的报错。排查方法是查参考时钟、查差分线有没有接反、查电源和复位信号。第二类是配置空间问题。设备能识别但BAR没分配或者分配错了。这种情况lspci能看到设备但驱动加载失败。排查方法是看BAR的值是不是0或者是不是和其他设备冲突。第三类是兼容性问题。某些老设备在新平台上枚举失败或者新设备在老平台上认不到。这通常是因为双方对协议的理解有差异或者固件的枚举实现不够健壮。遇到这种情况先查有没有固件更新然后查设备的Errata。4. 带宽计算与链路协商你的设备到底能跑多快4.1 带宽计算公式PCIE的带宽计算其实不复杂但很多人算不对因为忽略了编码开销。公式是这样的单向带宽 链路速率 × 每lane位宽 × lane数量 × 编码效率 / 8以PCIE 2.0 x4为例链路速率是5 GT/sGiga Transfers per second每lane每周期传1位编码是8b/10b编码效率是80%。所以单向带宽 5 × 10^9 × 1 × 4 × 0.8 / 8 2 GB/s双向带宽就是4 GB/s。注意这里的GB是10^9字节不是2^30字节。如果按GiB算大概是1.86 GiB/s单向。有人问“a1398内置PCIE 2.0 x4可以到多少速度”按上面的公式算就是单向2 GB/s左右。但实际能跑多少还要看协议开销、TLP Header开销、流量控制等因素通常能到理论值的70%到85%就不错了。4.2 各代PCIE带宽对照版本链路速率编码x1单向带宽x4单向带宽x8单向带宽x16单向带宽1.02.5 GT/s8b/10b250 MB/s1 GB/s2 GB/s4 GB/s2.05 GT/s8b/10b500 MB/s2 GB/s4 GB/s8 GB/s3.08 GT/s128b/130b~984 MB/s~3.94 GB/s~7.88 GB/s~15.75 GB/s4.016 GT/s128b/130b~1.97 GB/s~7.88 GB/s~15.75 GB/s~31.5 GB/s5.032 GT/s128b/130b~3.94 GB/s~15.75 GB/s~31.5 GB/s~63 GB/s注意3.0以后的编码效率是128/130约98.46%比8b/10b的80%高了不少。所以3.0的8 GT/s虽然速率只比2.0的5 GT/s高了60%但实际带宽翻了将近一倍。4.3 链路协商为什么我的设备降速了链路协商是物理层在LTSSM的Configuration状态完成的。双方会交换Link Capabilities和Link Status然后协商出一个双方都支持的最高速率和最大lane数。降速降speed和降lane降width是实际中最常见的问题。原因通常有这么几类一是信号完整性问题。链路速率越高对信号质量的要求越高。如果PCB走线不好、连接器质量差、线缆太长高速率下误码率太高链路就会自动降到低速率。这种情况用lspci -vv看LnkSta如果显示“Speed 2.5GT/s (downgraded)”之类的基本就是信号问题了。二是参考时钟问题。PCIE要求参考时钟的精度在±300ppm以内如果时钟源质量不好高速率下会失锁。有些主板为了省成本用了便宜的时钟芯片结果PCIE 3.0的设备只能跑在2.0。三是兼容性问题。某些设备组合在一起就是跑不到最高速率这是双方SerDes的均衡参数不匹配导致的。遇到这种情况可以尝试手动设置链路速率或者更新固件。四是电源管理。有些平台为了省电会把空闲的链路降到低速率。如果设备在低负载时降速高负载时能升回去这是正常的。但如果一直升不回去就要查ASPMActive State Power Management的配置了。4.4 掉卡问题的排查思路掉卡是比降速更严重的问题设备直接消失了。掉卡的原因也很多我按排查顺序列一下第一步查dmesg。看有没有AER报错、link down、timeout之类的信息。AER报错会告诉你具体是哪种错误比如Correctable Error、Uncorrectable Error、Fatal Error。第二步查物理连接。金手指有没有氧化、插槽有没有灰尘、螺丝有没有拧紧。听起来很基础但我遇到过好几次就是接触不良导致的掉卡。第三步查电源。PCIE设备对电源的要求不低尤其是高性能显卡和加速卡。如果电源功率不够或者供电不稳高负载下就会掉卡。第四步查散热。温度过高会导致芯片工作异常进而掉卡。用sensors或者ipmitool看一下温度。第五步查驱动和固件。有些掉卡是驱动bug或者固件bug导致的更新到最新版本可能就好了。第六步查ASPM和电源管理。有些平台在ASPM L1状态下会出问题可以在内核启动参数里加pcie_aspmoff试试。5. AER错误报告与PCIE稳定性问题深度解析5.1 AER是什么AER全称Advanced Error Reporting是PCIE协议里定义的一套错误报告机制。它把错误分成三类Correctable Error可纠正错误、Uncorrectable Error不可纠正错误、Fatal Error致命错误。Correctable Error包括Receiver Error、Bad TLP、Bad DLLP、Replay Timer Timeout等。这些错误可以被硬件自动纠正通常不会影响功能但频繁出现说明链路质量有问题。Uncorrectable Error包括Completer Abort、Unsupported Request、ECRC Error、Malformed TLP等。这些错误会导致事务失败驱动需要处理。Fatal Error是最严重的通常会导致链路down掉设备直接消失。5.2 用AER排查稳定性问题AER的错误计数器在配置空间的Advanced Error Capabilities and Control寄存器里。你可以用setpci或者devlink来读这些计数器。在Linux下dmesg里会打印AER错误格式大概是这样的pcieport 0000:00:1c.0: AER: Corrected error received: 0000:01:00.0 pcieport 0000:00:1c.0: AER: PCIe Bus Error: severityCorrected, typePhysical Layer如果看到Corrected Error频繁出现说明链路有信号完整性问题但还没严重到影响功能。如果看到Uncorrectable Error就要重视了可能是设备故障或者兼容性问题。我处理过一个案例一台服务器上的网卡时不时丢包dmesg里全是AER Corrected Error。换了网卡、换了插槽都没用。最后查出来是主板PCIE走线太长信号衰减太大。在BIOS里把链路速率从3.0降到2.0问题就消失了。虽然带宽降了一半但至少稳定了。5.3 掉卡、降速、AER的关联分析这三个问题经常是关联的。链路信号质量差首先表现为AER Corrected Error增多然后链路可能降速来维持稳定如果信号继续恶化就会出现Uncorrectable Error最终导致掉卡。所以排查的时候要按这个顺序来先看AER计数器再看链路速率和宽度最后看设备是否还在。如果AER计数器增长很快说明物理层有问题优先查信号完整性。如果AER正常但链路降速了可能是兼容性问题或者电源管理问题。如果设备直接消失了先查物理连接和电源再查固件和驱动。5.4 常见问题速查表现象可能原因排查方法解决思路lspci看不到设备物理层未训练、电源问题、复位问题查dmesg、查LTSSM状态、查电源和复位查参考时钟、查差分线、换插槽设备能识别但驱动加载失败BAR未分配、BAR冲突、配置空间错误lspci -vv看BAR值、看dmesg报错更新BIOS、手动分配BAR、查Errata链路降速信号完整性、参考时钟、兼容性lspci -vv看LnkSta、查AER计数器降速使用、换线缆、更新固件链路降lane差分线故障、连接器问题lspci -vv看LnkSta、查物理连接查差分线通断、换连接器AER Corrected Error频繁信号完整性、链路质量读AER计数器、看dmesg降速、改善信号、换硬件掉卡电源、散热、ASPM、固件查dmesg、查温度、查电源关ASPM、加强散热、更新固件性能不达标Tag数量不足、中断配置不当、DMA效率低查Tag位数、查MSI-X配置、查DMA描述符用MSI-X、增加Tag、优化DMA6. PCIE仿真与验证在流片之前把问题找出来6.1 为什么需要PCIE仿真PCIE协议很复杂如果等到流片回来再调试成本太高了。所以在设计阶段就要做仿真验证确保你的PCIE控制器或者设备能正确响应各种事务。PCIE仿真通常分几个层次协议层仿真、链路层仿真、物理层仿真。协议层仿真主要验证TLP的组装和解析是否正确链路层仿真验证ACK/NAK重传和流量控制物理层仿真验证SerDes和LTSSM。做仿真需要一套PCIE VIPVerification IP市面上有商业的也有开源的。商业的比如Synopsys、Cadence的VIP功能全但贵开源的比如PCIe-BFM功能有限但够用。6.2 仿真环境的搭建一个典型的PCIE仿真环境包括Root Complex模型、Endpoint模型、参考时钟模型、监视器Monitor和记分板Scoreboard。Root Complex模型模拟主机侧的行为发起配置读写、内存读写等事务。Endpoint模型就是你要验证的设备。监视器抓取总线上的TLP记分板比对预期结果和实际结果。搭建仿真环境的时候我建议先从简单的场景开始比如配置空间读写、单次内存读写然后再逐步增加复杂度比如DMA传输、中断、错误注入。不要一上来就搞全场景容易把自己绕进去。6.3 仿真中的常见问题仿真中最常见的问题是超时。PCIE协议里有很多超时机制比如Completion Timeout、Replay Timer Timeout。如果仿真环境没有正确处理这些超时就会卡死。另一个常见问题是流量控制Credit不匹配。发送端和接收端的Credit数量如果不一致要么发不出去要么发出去被丢掉。仿真的时候要确保双方的Credit配置一致。还有就是LTSSM状态机卡死。物理层仿真里LTSSM要在各个状态之间正确跳转。如果某个状态的条件没满足就会卡在那里。调试LTSSM的时候把状态机的跳转条件打印出来对照协议规范一条条查。6.4 Xilinx PCIE IP的使用经验Xilinx的PCIE IP核用得很多我分享几个使用经验。第一IP核的配置参数很多尤其是链路速率、lane数量、BAR配置这些一定要和硬件设计一致。第二IP核的参考时钟要求很严格必须是100MHz ±300ppm而且抖动要小。第三IP核的复位逻辑要处理好PCIE的复位分好几种比如Fundamental Reset、Hot Reset、Link Down Reset每种复位的处理方式不一样。Xilinx的XDMADMA Subsystem for PCIe是个好东西它把DMA和中断都封装好了驱动也提供了拿来就能用。但要注意XDMA的BAR配置和中断配置需要根据实际需求调整默认配置不一定适合你的场景。7. 热插拔与兼容性那些让人头疼的实战问题7.1 PCIE热插拔功能解析PCIE热插拔Hot Plug是协议支持的一个特性允许在系统运行的时候插入或拔出设备。这个功能在服务器和存储领域很有用比如在线更换故障的网卡或者SSD。热插拔的实现需要几个条件一是硬件要支持插槽要有独立的电源控制和存在检测引脚二是固件要支持BIOS/UEFI要正确配置热插拔相关的寄存器三是操作系统要支持Linux下的pciehp驱动就是干这个的。热插拔的流程大概是这样的用户按下插槽上的按钮或者通过软件触发系统收到热插拔事件然后给插槽断电用户拔出设备。插入的时候反过来系统检测到设备存在给插槽上电然后枚举设备。实际用的时候热插拔经常出问题。最常见的是电源控制时序不对导致设备上电不成功。还有就是存在检测信号抖动系统误判设备状态。我建议在做热插拔设计的时候严格按照PCIE规范里的时序要求来电源稳定后再释放复位复位释放后再开始链路训练。7.2 Realtek PCIE GBE网卡的兼容性问题Realtek的PCIE GBE网卡比如RTL8111、RTL8168系列用得非常多但兼容性问题也不少。尤其是在32位系统上有时候驱动加载失败或者性能很差。32位系统的问题主要是地址空间限制。32位系统只能访问4GB以下的物理地址如果BAR被分配到4GB以上驱动就访问不了。解决办法是在BIOS里设置“Above 4G Decoding”为Disabled或者强制BAR分配到4GB以下。另一个常见问题是ASPM兼容性。Realtek的网卡在某些平台上开启ASPM后会掉线或者性能下降。可以在驱动参数里加aspm0来关闭ASPM。还有就是中断问题。Realtek网卡默认可能用INTx中断在高负载下性能不好。可以在驱动加载时加msi1来启用MSI中断。7.3 Liteon PCIE Tool Box与调试工具Liteon PCIE Tool Box是一个用于调试Liteon SSD的工具可以查看SSD的SMART信息、固件版本、链路状态等。类似的工具还有nvme-cli、smartctl等。调试PCIE设备的时候我常用的工具组合是这样的lspci看设备列表和配置空间setpci读写配置空间dmesg看内核日志lspci -vv看链路状态和能力结构perf看性能计数器。如果是NVMe SSD还会用nvme命令看SMART和错误日志。这些工具用熟了大部分PCIE问题都能定位到。关键是要知道看哪些寄存器、哪些字段以及这些字段的含义。7.4 40hx解锁PCIE 2.0的案例分析“40hx翻身了解锁PCIE 2.0”这个热词说的是某些显卡或者加速卡通过修改固件或者硬件把PCIE链路从1.0解锁到2.0。这种做法有风险但确实有人这么干。从技术角度分析PCIE 1.0和2.0的物理层差异不大主要是速率从2.5 GT/s提升到5 GT/s。如果芯片本身支持2.0但被固件限制在1.0理论上可以通过修改固件来解锁。但如果芯片本身只支持1.0那就没办法了。解锁PCIE 2.0的收益是带宽翻倍对于带宽敏感的应用比如GPU计算、高速采集提升明显。但风险是信号完整性可能不达标导致链路不稳定或者掉卡。我的建议是如果官方没有提供解锁方法不要轻易尝试稳定性比带宽更重要。8. 实操心得与避坑指南8.1 硬件设计阶段的注意事项做PCIE硬件设计的时候有几条经验我觉得很值得分享。第一差分线一定要等长长度偏差控制在5mil以内。差分线不等长会导致共模噪声影响信号质量。第二参考时钟要远离干扰源尤其是开关电源和高速时钟。参考时钟的抖动直接决定了链路能跑多快。第三AC耦合电容要选对PCIE要求用0.1uF的AC耦合电容放在发送端。电容的封装要小0402或者0201最好减少寄生电感。第四复位信号要处理好PCIE的复位是低有效复位释放要和参考时钟同步。第五电源要干净PCIE对电源纹波的要求是50mV以内高速率下要求更严。第六金手指和连接器要选好的劣质连接器是信号完整性的杀手。8.2 驱动开发阶段的注意事项写PCIE驱动的时候我踩过的坑主要有这几个。第一BAR映射要用ioremap不能用直接指针访问。第二DMA缓冲区要物理连续或者用IOMMU/SMMU做地址映射。第三中断处理要快进快出不要在中断上下文里做耗时操作。第四配置空间读写要用内核提供的API比如pci_read_config_dword不要自己直接访问。第五电源管理要处理好suspend/resume的时候要正确保存和恢复设备状态。第六错误处理要完善AER错误、Completion Timeout这些都要有处理逻辑。第七多队列要配MSI-X每个队列一个中断向量避免锁竞争。8.3 系统调试阶段的注意事项系统调试的时候我建议按这个顺序来先确认物理层链路起来了再看配置空间是否正确然后看驱动是否加载成功最后看功能和性能是否达标。查物理层链路用lspci -vv看LnkCap和LnkSta。LnkCap是设备支持的能力LnkSta是当前协商的状态。如果LnkSta的Speed和Width低于LnkCap说明链路降速或者降lane了。查配置空间用lspci -xxx看BAR的值、Command寄存器的值、Capabilities结构。如果BAR是0或者全F说明没分配好。查驱动用dmesg和lsmod看驱动有没有加载、有没有报错。如果驱动加载失败看dmesg里的报错信息通常是BAR分配失败或者中断配置失败。查性能用perf或者自己写测试程序看带宽和延迟是否达标。如果性能不达标查Tag数量、中断配置、DMA效率。8.4 常见误区澄清最后澄清几个常见误区。第一个误区是“PCIE 3.0比2.0快一倍”。实际上3.0的8 GT/s比2.0的5 GT/s只高了60%但因为编码效率从80%提升到98.46%实际带宽确实翻了将近一倍。第二个误区是“lane越多越好”。lane越多带宽越高但功耗和成本也越高而且很多应用根本用不到那么多lane。第三个误区是“PCIE是共享总线”。PCIE是点对点每条链路独享带宽不像PCI那样共享。第四个误区是“热插拔随便用”。热插拔需要硬件、固件、系统三方都支持缺一不可。第五个误区是“AER报错无所谓”。Corrected Error偶尔出现没关系但频繁出现说明链路有问题迟早会变成Uncorrectable Error。第六个误区是“仿真能代替实测”。仿真能发现大部分逻辑问题但信号完整性问题、电源问题、兼容性问题还是要靠实测。我个人在实际操作中的体会是PCIE这套东西理论不难难在细节。协议规范几千页但真正影响稳定性和性能的就是那么几个关键点信号完整性、电源、时钟、配置空间、中断、DMA。把这几个点吃透了大部分问题都能搞定。遇到搞不定的问题先查Errata再查社区最后实在不行就降速使用稳定第一。
阅读完成 · 觉得有帮助?