尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

半高PCIe板卡设计与调试实战:从结构到驱动的完整复盘

半高PCIe板卡设计与调试实战:从结构到驱动的完整复盘 手头正好在折腾一个“Low-Profile PCIe Board Platform”的小项目这块板子从结构设计到驱动的坑几乎踩了个遍写一篇复盘分享出来希望对正在做半高扩展卡、PCIe 存储控制器或者 FPGA 板卡的朋友有帮助。这个项目标题拆开看其实很清楚Low-Profile 指的是半高/矮版尺寸面向 1U 或 2U 机箱PCIe 是接口协议和链路体系Board Platform 则是从机械、电气到固件的一整套板级方案。所以它不只是一张“能插上 PCIe 槽”的卡而是要兼顾散热高度、结构强度、信号完整性、枚举开机、DMA 地址映射甚至还要考虑后续量产的稳定性。1. 项目概况与整体设计思路1.1 我为什么选这个方向当时的需求场景是一台 1U 存储服务器机器本身高度只有 44.5mm标准全高卡根本放不进去只能使用半高卡。功能上要扩出额外的 SATA 端口用来挂系统盘或者做备份盘。最开始我图省事直接买了一张现成的 PCIe 转 SATA 卡但连续遇到两个问题一是部分主板上识别不到二是拷贝大量数据时系统卡顿甚至直接死机。后来查了不少资料才知道这类问题有很大概率出在板卡本身的电源去耦、信号质量和链路协商上而不是控制器芯片本身。与其在成品卡上打补丁不如自己从零设计一个平台把可能出问题的环节都掌握在手里。这就是这个项目最初的出发点。做这种板子核心目标有三个尺寸必须满足半高约束信号和电源设计要保证 PCIe 链路稳定固件和调试手段要能快速定位问题。如果你正在做类似的东西我建议一开始就把这三条当成硬指标不然后面返工成本很高。1.2 方案选型桥片、Switch 和 FPGA 怎么选Low-Profile PCIe 板卡的核心器件按功能可以分成三条路线桥片/控制器路线例如 ASM1061PCIe x1 转双 SATA、JMB585转 5 SATA、Intel 的万兆网卡芯片等。这类芯片把协议处理都封装好了硬件设计相对简单出问题后也容易用现成驱动验证。PCIe Switch 路线例如 PEX 8608、PEX 8717。适合要把一个 x4/x8 扩展成多个 x1/x4 接口的场景比如多网卡、多 NVMe 的扩展板。Switch 不是终端设备而是协议中继设计时除了链路本身还要考虑端口配置、NTB 这些高级功能。FPGA 路线例如 Xilinx 的 Artix/Kintex 系列、紫光同创的 Logos 系列。适合做自定义协议、数据采集、视频处理这类需要灵活改逻辑的项目。FPGA 内部要做 PCIe 硬核或软核的初始化工作量大很多但可控性最好。我的板子最终选了 ASM1061 作为主控制器理由很直接目标应用是存储扩展不是高速计算x1 Gen2 的带宽理论 500MB/s 每 lane已经够用同时它的外围简单参考资料多适合作为第一个 Low-Profile 平台的验证载体。等到平台稳定后再考虑把 PCIe Bridge 换成 JMB585 或者兼容的控制器板级改动不会伤筋动骨。这里也建议你在选型的时候做一个性价比表格把“单 lane 带宽需求”“功耗上限”“驱动成熟度”“PCB 布线难度”四列列出来。比如像 ASM1061 这种芯片驱动在 Linux 内核里已经不缺但某些工控主板上会出现兼容性问题如果项目工期紧就要有备选方案。2. 机械、电源与 PCB 设计要点2.1 半高挡板、PCB 尺寸和散热约束Low-Profile 的机械标准重点看两个尺寸全高卡外形高度大约 120mm而半高卡挡板高度大约 69mmPCB 高度要控制在 64.4mm 左右。半长卡的长度标准通常是 167.65mm但机箱可能更短所以最好先确认目标机箱的槽位空间再画板框。我的板子用的是半长半高尺寸长度 145mm 左右这样在多数 1U 机箱里都能装下。散热是低矮板卡的隐形杀手。全高卡可以把散热片做厚但半高卡的散热器高度通常不能超过 14mm否则挡板装不上或者会和机箱上盖短接。对于 ASM1061 这种功耗只有 2~3W 的芯片一个带导热垫的小铝散热片就够了但如果板子上有 PCIe Switch 或者 10G 网卡芯片功耗可能到 10W 以上这时候无风冷环境基本没法用必须考虑机箱风道或者主动风扇。我的经验是在设计阶段就把散热器高度当作 PCB 布局的约束条件而不是等板子回来了再找散热方案。另外一个容易忽略的点是挡板接地。PCIe 挡板不仅要固定板卡还承担了一部分 EMI 屏蔽和接地任务。半高挡板比全高挡板接触面积小如果接地不实在整机的辐射骚扰和信号稳定性都会变差。我画板时会在挡板安装孔附近加宽接地铜皮并用螺丝拧紧到机箱钣金上实测对长期稳定性有明显帮助。2.2 PCB 叠层、阻抗和差分走线规则PCIe 板卡一般不建议用两层板因为差分阻抗不好控制参考平面不连续。四层板是比较常见的选择顶层走信号第二层做完整地第三层走电源底层走控制信号。如果链路速率到 PCIe Gen416GT/s或者 Gen532GT/s四层板就不太够了至少要六层甚至八层同时要考虑更严格的过孔残桩和背钻。我做 Gen3 的时候用过六层板效果比四层稳不少。差分阻抗要求是 85Ω ± 10%。Layout 时注意三点PCIe 差分线对内等长要控制在 5mil 以内对间等长不需要特别严苛但要尽量保证参考地完整中间不要打孔换层必须换层时至少加两个回流地过孔。高速信号线到板边的距离也尽量留足避免被机箱金属边缘影响。耦合电容也必须重视。PCIe 规范要求在发送端放置 0.1uF 的 AC 耦合电容用来隔直流。这个电容对焊盘寄生电容敏感如果布线太细或焊盘过大会产生阻抗突变。我在 Gen3 项目里看到过因为 AC 耦合电容封装选错导致眼图闭合的情况换成 0402 并优化焊盘后恢复正常。还有一点PCIe 走线下面不要有其他信号穿过特别是 SATA、USB 这类会带来时域串扰的信号。如果实在无法避免至少让它们垂直交叉并且保证交叉区域下方有完整地平面。2.3 电源轨设计与功耗预算PCIe 插槽提供 12V、3.3V 和 3.3V 辅助供电。全高卡理论上能从插槽取到 75W 功率12V 最多 5.5A但半高卡受散热限制通常只能按 10~15W 来设计。我的板子整体功耗目标控制在 5W 以内这样电源部分可以用低成本的 DC-DC不会因为热超标出问题。我画电源部分时把 ASM1061 的内核电压 1.0V 单独用一颗 LDO/DCDC 供电3.3V 直接从 PCIe 插槽取另外预留了一个 12V 转 5V 的降压电路给 SATA 接口供电。注意 3.3V 是从插槽取还是从辅助电源取直接决定了掉电时序。很多设备识别不到的问题根源就是 PERST# 释放太早或电源未稳定就允许链路训练所以我在复位电路上加了 RC 延时保证上电后至少 100ms 再释放 PERST#这个时序在 PCIe 规范里有明确要求别省。供电去耦也有讲究。ASM1061 这类芯片在工作时会动态拉电流如果去耦电容不足电源纹波会直接叠加到高速信号上。我曾遇到一张试验板在长时间高负载时偶发掉性能量电源发现 1.0V 稳压输出纹波有 60mV远高于预期的 20mV后来在芯片电源脚附近补了几颗 1uF 和 0.1uF 电容后问题基本消失。所以做板子时去耦电容宁可多放也别少放尤其是芯片下面靠近电源脚的位置。3. PCIe 链路、时钟与协议基础3.1 PCIe 引脚和边带信号不止是收发差分线很多人以为 PCIe 就是那几对差分线其实板卡能不能被正确识别很大程度上取决于边带信号。常用的有 PERST#复位、REFCLK/-参考时钟、WAKE#唤醒、CLKREQ#时钟请求以及 SMBus 引脚 SMCLK/SMDAT。PERST# 是全局复位信号必须等各路电源稳定后再拉高REFCLK 是 100MHz 差分时钟终端设备的时钟源可以从插槽取也可以在板载晶振产生。CLKREQ# 在需要 L1 低功耗子状态的板卡上基本是必须的如果没接或者没拉对电平系统可能无法进入低功耗状态。这里要特别提醒一下 PRSNT# 信号。有的板卡没有接 PRSNT# 检测引脚导致主板以为卡没插入自然就枚举不到设备。设计时一定要确认 PCIe 连接器的 PRSNT1#/PRSNT2# 引脚和板卡的对应关系必要时用 0 欧电阻连接或预留焊盘。3.2 时钟拓扑共同时钟与独立参考时钟PCIe 系统对参考时钟的要求比较严格。早期平台基本都用“共同时钟”架构也就是主板把 100MHz 参考时钟播给所有端点板上不需要独立时钟源。现在有些平台开始支持“独立参考时钟”架构端点和 RC 各自用自己的时钟源允许一定的扩频时钟差异。如果你的板卡设计为独立参考时钟架构而主板只支持共同时钟链路可能训练失败或速率只有 Gen1。我在调试一块 FPGA 板时遇到过这种情况FPGA 板载晶振工作正常但插到某块服务器主板上只能协商到 Gen1。后来确认是主板的 REFCLK 输出和板载晶振频率偏差超过了允许范围改成使用主板参考时钟后恢复正常。所以设计时建议把时钟来源做成可配置的至少预留焊盘供选择。扩频时钟也要注意。有的 BIOS 会开启 SSC展频时钟来降低 EMI如果端点的时钟恢复电路对 SSC 支持不好会造成锁定失败。调试时可以进 BIOS 关闭 Spread Spectrum 试试如果关掉后链路正常基本就是时钟问题。3.3 链路训练和均衡为什么跑不上 Gen3PCIe 一上电物理层会经历一个链路训练状态机依次包括 Detect、Polling、Configuration、L0、Recovery 等状态。操作系统和 BIOS 看到的“识别到设备”实际上已经是链路训练完成、配置空间能够读取之后的结果。如果卡在 Polling 或 Configuration主板就会报“找不到设备”。到了 Gen3 和更高速率还要经历均衡Equalization过程。发送端会根据接收端的能力调整去加重和预加重参数接收端也做自适应均衡。这个过程如果因为链路质量不好而失败会自动降到较低速率。很多人抱怨“明明卡是 Gen3 的主板只显示 Gen2”十有八九是链路上的插入损耗或反射超过阈值。排查方法是用示波器在插槽和卡端分别量眼图或者先把 BIOS 里的 Pcie Speed 手动改成 Gen2看是否稳定作为排除手段。3.4 枚举流程和 TLP 头部格式PCIe 枚举是 BIOS 和操作系统发现设备的基础。Root Complex 会为每个总线分配总线号通过配置 TLP 读取设备的 Vendor ID、Device ID、Class Code 和 BAR 等信息。对于一张新板卡来说如果这些寄存器响应不正确系统就会跳过它。配置请求 TLP 的头部格式建议你自己画一遍印象会深很多。以 Type 0 配置读请求为例通常包含 Fmt/Type 字段、总线号/设备号/功能号和寄存器偏移事务层会按这个头部去访问设备的配置空间。我在做 FPGA 的 PCIe 控制器时最痛苦的就是自己拼 TLP 头一个位域错位枚举就失败而且错误信息不明显。如果你也是在FPGA里做 PCIe 硬核或软核强烈建议先用逻辑分析仪抓一下主板发来的配置请求确认硬件能正确解析再接数据通路。Linux 下可以用lspci -xxx直接查看设备的配置空间或者用setpci读写指定寄存器。这些工具在调试阶段比仿真器方便得多。4. 实际调试记录和故障排查实录4.1 设备识别不了先按四步排查我的板子第一次上电时就出现识别不了的情况这其实是 Low-Profile PCIe 板最常见的故障。我习惯按这个顺序排查量供电和复位万用表确认 12V、3.3V、内核电压都有PERST# 拉高时间是否在上电后足够久。量参考时钟示波器看 REFCLK 有没有起振频率是否在 100MHz 正负 300ppm 范围内。量链路训练用支持 PCIe 协议分析功能的示波器或逻辑分析仪看插槽侧的 TS1/TS2 序列确认卡在哪个状态。读配置空间如果链路已经处于 L0说明物理层基本通了问题多半在配置空间逻辑用lspci看是否读出正确的 Vendor ID。大部分情况下问题都出在第 1 步或第 3 步。如果是 FPGA 板卡识别不到还要检查硬核的复位逻辑和时钟是否已经通过 PCIe PHY如果 PHY 根本没锁存参考时钟硬核是不工作的。4.2 ASM1061 卡死问题复盘网上对 ASM1061 卡死的讨论很多我自己也踩过。现象是设备能识别但进行大量 SATA 读写时系统隔一段时间卡顿十几秒严重时直接死机。排查时我把重点放在三处电源纹波、ASPM 电源管理和 SATA 链路质量。先看电源纹波结果在 12V 转 5V 的 DC-DC 输出端看到了明显开关噪声虽然 ASM1061 核心电压不是直接从这路取但 SATA 接口供电和芯片的 I/O 电源可能与它共路导致噪声串进芯片。解决方法是增加 LC 滤波并把模拟地在电源附近单点接地。再看 ASPM。有的主板默认开启 ASPM 省电功能ASM1061 对 L1 子状态支持不完美进入节能状态后偶尔唤不醒表现为间歇性卡死。解决方式是进 BIOS 关闭 ASPM或者在 Linux 里用lspci -vvv查看设备 ASPM 状态手动禁用。这个方法排查效率最高确认后可以在板卡设计上把 ASPM 的工厂默认配置调成禁用。最后是 SATA 线缆。ASM1061 是 PCIe 转 SATA 桥如果外接 SATA 线过长或质量差错误重传会占用大量 PCIe 带宽。我的板子在最终测试时把 SATA 线换成了短线高速线卡顿明显减少。虽然每一条原因都很简单但叠加起来就会造成“玄学”卡死所以这类问题要逐项排除。4.3 地址空间、SMMU/IOMMU 和 DMA 启动参数PCIe 设备访问内存靠的是 DMA。传统平台上设备用 BAR 和 DMA 地址直接访问物理内存但现代平台有 IOMMU/SMMU设备看到的是 I/O 虚拟地址必须经过页表翻译才能落到真实的物理内存。如果 IOMMU 驱动没配好DMA 写内存时要么找不到目标要么访问到错误地址表现就是设备“跑起来了但数据全乱”。BIOS 里关于 PCIe 和 DMA 的参数我调试时重点关注这几项Above 4G Decoding如果系统有大量内存或需要访问 4G 以上地址必须开启否则某些设备的 64 位 BAR 无法映射。VT-d / IOMMU开启后系统才能做 DMA 重映射。对普通扩展卡来说开启或关闭都能工作但这影响性能和安全机制。调试期间如果 DMA 相关异常可以先关闭 IOMMU 快速验证。SR-IOV如果你的板卡支持虚拟化透传需要开启。Resizable BAR也建议开启方便大数据块 DMA 映射。在 Linux 下可以用dmesg | grep -i iommu查看 IOMMU 是否启用用lspci -vvv查看设备当前 BAR 和 Capabilities。如果设备识别但驱动报 DMA 错误多半是 IOMMU 映射问题而不是硬件坏了。4.4 FPGA 平台的调试以紫光同创为例FPGA 做 PCIe 板卡的优势是灵活但调试成本高。紫光同创的 PCIe 硬核和 Xilinx 的 IP 类似上电后会扫描链路再根据主机发送的配置请求返回配置空间内容。设备识别不了时经常不是 IP 逻辑的问题而是时钟或复位没有按硬核要求来。我在调紫光同创板子时踩过一个坑FPGA 配置从 FLASH 加载完成后硬核才开始上电此时主机可能已经结束枚举。所以需要用 PCIe 的 PERST# 信号作为硬核的复位来源并且保证 FPGA 加载完成时间和 PERST# 释放时间匹配。另一个常见问题是硬核的 AXI 接口地址和 BAR 映射不一致导致主机读不到期望的寄存器内容。调试时我习惯在 FPGA 里做一个简单的“Vendor ID 和 Device ID 寄存器”模块先用lspci读到正确 ID再逐步添加其他功能这样能快速缩小问题范围。4.5 故障排查工具和速查表我常用的排查工具有lspci查看设备是否出现在总线上当前链路速率、宽度、BAR、ASPM 状态。setpci读写配置空间寄存器可以强制设置设备 ID 或控制链路速率。dmesg查看内核日志里的 PCIe 错误和 IOMMU 报错。devmem直接读写物理地址用来验证内存映射是否正确。示波器/逻辑分析仪看链路训练时的 TS1/TS2 序列检查时钟、复位时序。下面是一张我在项目现场用过的排查速查表遇到问题时按表走效率会高很多。现象优先排查顺序常用命令/工具设备完全没出现电源、复位、参考时钟、链路状态万用表、示波器、lspci链路速率低于预期均衡参数、布线损耗、参考时钟lspci -vvv、协议分析仪设备出现但驱动无法加载配置空间、ID、BAR、分配冲突setpci、dmesgDMA 错误/数据错乱IOMMU 映射、BAR 大小、MPS/MRRSdmesg、devmem系统间歇卡死ASPM、SATA 线缆、电源纹波lspci -vvv、示波器FPGA 板识别不到PERST# 时序、硬核复位、FLASH 配置逻辑分析仪、lspci4.6 链路层问题排查时的小技巧还有一个高频问题链路的最大载荷大小和读请求大小不匹配。如果 Root Complex 和 Endpoint 之间没有协商出一个双方都支持的 MPSMax Payload Size和 MRRSMax Read Request Size大块 DMA 就可能被拆成大量小包性能断崖式下降甚至触发流量控制错误。操作系统通常会自己协商但某些 FPGA 驱动或旧 BIOS 会处理不好。用lspci -vvv看设备的 DevCap/DevCtl 字段能看到当前 MPS 和 MRRS 分别是多少如果 MCPS 或 MRRS 明显偏小可以手动用setpci调整。PCIe 的错误上报也非常值得看。AERAdvanced Error Reporting会在链路出现严重错误时记录日志dmesg里的硬件错误信息往往直接指向问题。我在调试时会把 BIOS 里的 PCIe Error Reporting 开启这样链路质量差、接收端缓冲区溢出这类问题都能早期暴露。5. 一些个人经验和后续扩展方向走到这里Low-Profile PCIe 板卡平台的基本盘已经通了结构上能装进 1U/2U 机箱电气上链路稳定能跑满协议固件上能枚举、能 DMA、能连续高负载跑测试。我个人在实际操作中的一个强烈体会是这种板卡项目最难的不是原理图设计而是机械和电气的高度耦合。很多你以为是“软件问题”的现象追根到底可能是散热片压得太低导致芯片温度过高或是电源去耦不够导致信号眼图闭合。所以在整个项目里我改得最多的不是固件代码而是 PCB 的布局和电容位置。最后再分享一个小技巧一定要保留两个测试焊盘一个用于测量 PERST# 时序一个用于测量 REFCLK 差分对。板卡出了问题这两个信号是判断“主板有没有识别你”的第一道线索没有测试点的时候只能用探针捅连接器又危险又容易短路。我后来的板子干脆把这两个信号引到板边排针调试时一分钟就能定位问题。后续如果继续扩展我打算把 ASM1061 的方案换成 PCIe Switch 加多路 NVMe 的组合让一块半高卡能扩出四个 M.2 盘位这会涉及 PCIe Switch 的端口配置和 NTB 透传。到那时现在的调试经验和 TLP 分析思路还是能直接复用只是多了一道交换层的路由和流量管理等跑通了再写一篇专门讲 Switch 的复盘。
返回列表