3. PCIe枚举与芯片识别
Broadcom 交换芯片(如 Trident、Tomahawk 系列)在板级 Bring-up 阶段,主机侧最先要确认的往往不是交换功能,而是“芯片是否被 PCIe 总线正确识别”。只有枚举成功、链路训练到预期宽度与速率、BAR 空间映射正确,后续的 SDK 初始化、寄存器访问、SerDes 配置才有物理基础。本节围绕这条主线展开:先厘清 RC 与 EP 的角色,再看链路训练与 BAR 映射,最后落到 lspci 读取与枚举失败排查。
RC 与 EP:谁发起,谁响应
PCIe 是点对点、基于事务层的分层总线。一次枚举的本质,是 Root Complex(RC)通过配置事务去探测下游设备。RC 通常位于 CPU 或 SoC 内部,负责发起配置读写、分配总线号与地址空间;Endpoint(EP)是功能设备,被动响应配置请求。Broadcom 交换芯片在典型单机 Bring-up 场景中作为 EP 挂在主机 RC 之下;但在某些带外管理或双主控架构中,交换芯片侧也可能配置为 RC,去枚举其下挂的 NVMe、网卡等设备。判断当前板级属于哪种模式,是排查一切枚举问题的起点。
配置空间访问依赖 BDF(Bus:Device.Function)三元组。RC 枚举时从总线 0 开始,逐设备扫描 Vendor ID 与 Device ID;若读到 0xFFFF_FFFF,说明该位置无设备或链路未就绪。Broadcom 交换芯片的 Vendor ID 通常为 0x14E4,Device ID 随具体型号不同,例如 Trident 系列常见 0xB960、Tomahawk 系列常见 0xB970 等(具体以数据手册为准)。识别到正确 ID,才说明配置通路已通。
链路训练:宽度与速率如何协商
链路训练由物理层 LTSSM 状态机完成,经历 Detect、Polling、Configuration、Recovery、L0 等状态。训练结果决定链路宽度(x1/x2/x4/x8/x16)和速率(Gen1 2.5GT/s、Gen2 5GT/s、Gen3 8GT/s、Gen4 16GT/s、Gen5 32GT/s)。Bring-up 时常见现象是:链路能到 L0,但宽度只有 x1 或速率停在 Gen1,这通常意味着参考时钟、差分对极性、AC 耦合电容、复位时序或均衡参数存在问题。
链路训练结果可通过配置空间的 Link Status 寄存器读取:Link Capabilities 给出支持的最大宽度与速率,Link Status 给出当前协商宽度与速率,Link Control 可设置目标速率。若当前值低于预期,应优先检查参考时钟是否稳定、PERST# 释放时序是否满足、TX/RX 差分对是否交叉接反,以及芯片侧 SerDes 固件是否已加载。
BAR 空间映射:寄存器访问的地址入口
枚举成功后,RC 会为 EP 的每个 BAR 分配一段系统物理地址。BAR 本身记录的是“需要多大空间”以及“是内存空间还是 I/O 空间”。以 64 位内存 BAR 为例,BAR0 与 BAR1 组合成一个 64 位基地址寄存器,低 4 位为属性位。系统写入全 1 再回读,可探测出该 BAR 请求的空间大小;随后 RC 写入实际分配的基地址,驱动即可通过“基地址 + 偏移”访问芯片内部寄存器。
Broadcom 交换芯片通常提供多个 BAR:一个用于 PCIe 配置与门铃寄存器,一个用于映射内部寄存器窗口,部分型号还有用于 DMA 或 MSI-X 的 BAR。若 BAR 未正确映射,表现为驱动能识别设备但读写寄存器返回全 0 或全 F,或访问即触发总线错误。此时应核对 BAR 大小是否与数据手册一致、是否与其它设备地址冲突、以及 RC 的地址窗口是否覆盖该范围。
lspci 与配置空间读取实操
在 Linux 主机上,最直接的验证手段是 lspci。先用 lspci -nn 列出所有设备,确认是否出现 14e4 开头的条目;再用 lspci -vv -s 01:00.0 查看该设备的详细配置,重点关注 LnkCap 与 LnkSta 两行。LnkCap 表示链路能力,LnkSta 表示当前状态。例如 LnkCap 显示 Speed 16GT/s、Width x16,而 LnkSta 显示 Speed 8GT/s、Width x8,就说明链路只训练到一半,需要排查物理层。
若 lspci 看不到设备,可用 setpci 直接读配置空间。例如读取总线 1、设备 0、功能 0 的 Vendor ID:
setpci -s 01:00.0 0x00.L
# 正常返回 14e4(Vendor ID)
# 返回 ffff 表示该位置无有效设备或链路未就绪
读取 Link Status 寄存器(偏移 0x12,16 位):
setpci -s 01:00.0 0x12.W
# 低 4 位为当前链路速率编码
# 位 4~9 为当前协商宽度
BAR 映射可通过 lspci -vv 中的 Region 行查看,也可用 setpci -s 01:00.0 0x10.L 读取 BAR0 的基地址。若 Region 显示为“not assigned”或地址为 0,说明 RC 未完成 BAR 分配,需检查 BIOS/UEFI 的 PCIe 资源分配策略或内核启动参数。
枚举失败排查路径
枚举失败最常见的现象是 lspci 完全看不到设备,或 setpci 读回 0xFFFFFFFF。排查应遵循从物理层到配置层的顺序,避免一上来就怀疑驱动。
- PERST# 复位时序:PCIe 规范要求 PERST# 在参考时钟稳定后至少保持 100ms 再释放。若释放过早,链路训练可能未完成。用示波器同时抓 PERST# 与参考时钟,确认时序余量。
- 参考时钟:检查 100MHz 差分参考时钟是否起振、幅度与共模电平是否满足芯片要求。时钟缺失时 LTSSM 会停在 Detect 状态。
- 差分对极性:TX/RX 若交叉接反,部分芯片支持极性反转可自动纠正,但若未使能则训练失败。核对原理图与 PCB 走线。
- SerDes 固件:部分 Broadcom 交换芯片需要先加载 SerDes 微码,PCIe 物理层才能正常工作。确认上电流程中固件加载是否先于 PCIe 枚举。
- 地址窗口冲突:若设备能被识别但 BAR 分配失败,检查 RC 的 MMIO 窗口是否足够大、是否与其它设备重叠。
完成上述检查后,一个可用的判断闭环是:lspci 能看到 14e4 设备 → LnkSta 达到预期宽度与速率 → BAR Region 已分配且可读写 → 用 setpci 读回芯片 ID 与预期一致。四步全部通过,才认为 PCIe 枚举与芯片识别完成,可以进入下一阶段的 SDK 初始化与寄存器级调试。