4. PCIe RC与EP模式配置实战

Layerscape 系列处理器的 PCIe 控制器(PCIe Controller)在硬件上支持 Root Complex(RC)与 Endpoint(EP)两种角色,但同一时刻只能选择其中一种。RC 模式下,控制器负责发起配置事务、扫描总线、分配地址空间并枚举下游设备;EP 模式下,控制器作为被枚举的一方,等待上游 RC 通过配置空间读写来识别自己。本节以 LS1046A 开发板为例,说明如何通过设备树与 U-Boot 环境完成模式切换,并给出链路训练与枚举结果的判读方法。

一、RC 与 EP 的本质差异

理解模式配置前,先明确两种角色在硬件连接与软件行为上的区别。RC 侧需要提供参考时钟(REFCLK)、复位信号(PERST#)以及配置空间访问能力;EP 侧则接收这些信号,并在链路训练完成后通过 BAR(Base Address Register)向上游暴露自己的内存或寄存器窗口。Layerscape 的 PCIe 控制器内部包含 LTSSM(Link Training and Status State Machine),无论 RC 还是 EP,链路训练过程都由该状态机驱动,区别在于训练完成后谁发起枚举。

Layerscape PCIe RC / EP 模式配置与链路验证 RC 模式(Root Complex) LS1046A PCIe0 compatible = "fsl,ls1046a-pcie" 下游 EP 设备 NVMe / 网卡 / 自定义 EP 枚举 行为:发起配置读写、分配 BAR、扫描总线 设备树关键:device_type = "pci" U-Boot:pcie0 使能,模式为 RC 输出:lspci 可见下游设备 EP 模式(Endpoint) 上游 RC 主机 x86 / 另一片 LS 板 LS1046A PCIe0 作为 EP 被枚举 配置访问 行为:等待配置、暴露 BAR 窗口 设备树关键:device_type = "pci-endpoint" U-Boot:pcie0 模式设为 EP 输出:上游 lspci 可见 LS1046A 链路训练(LTSSM) Detect → Polling → Configuration → L0 双方速率/宽度协商,L0 表示链路就绪 验证判据 RC:lspci -tv 显示下游设备;EP:上游 lspci 显示 LS1046A 的 Vendor/Device ID dmesg 中 "link up" 与 "LTSSM state: L0" 为关键日志

二、设备树中的模式声明

Layerscape 的 PCIe 节点位于 arch/arm64/boot/dts/freescale/fsl-ls1046a.dtsi,板级文件(如 fsl-ls1046a-rdb.dts)通过 &pcie0 覆盖默认属性。RC 模式下,节点通常保持 device_type = "pci",并配置 ranges 映射、bus-range 与 interrupt-map。EP 模式则需要将 device_type 改为 "pci-endpoint",同时移除 RC 专属的 ranges 与 interrupt-map,改为声明 ep-bars 或由 EP 驱动动态配置 BAR。

以下为 RC 模式下的典型片段(示例参数,非实测值):

&pcie0 {
    compatible = "fsl,ls1046a-pcie";
    reg = <0x00 0x03400000 0x0 0x00100000>,
          <0x00 0x03480000 0x0 0x00100000>;
    device_type = "pci";
    bus-range = <0x00 0xff>;
    ranges = <0x81000000 0x0 0x00000000 0x00 0x03480000 0x0 0x00010000>,
             <0x82000000 0x0 0x40000000 0x00 0x40000000 0x0 0x40000000>;
    msi-parent = <&msi0>;
    status = "okay";
};

切换为 EP 模式时,关键改动如下:

&pcie0 {
    device_type = "pci-endpoint";
    /* 移除 ranges 与 interrupt-map */
    ep-bars = <0x0 0x40000000 0x0 0x00100000>;
    status = "okay";
};

注意:ep-bars 的具体格式随内核版本略有差异,部分版本使用 num-ob-windows 与 ob-window 描述出站窗口。修改后需重新编译 DTB 并更新到开发板启动分区。

三、U-Boot 环境与模式选择

Layerscape 的 PCIe 控制器在 U-Boot 阶段即可通过环境变量或 pcie 命令设定模式。常见做法是在 include/configs/ls1046a_common.h 中定义 CONFIG_PCIE0_MODE,或在启动时通过 setenv 覆盖。RC 模式对应 PCIE_RC,EP 模式对应 PCIE_EP。若使用 pcie 命令,可执行:

# RC 模式
pcie 0
# EP 模式
pcie 0 ep

实际工程中更推荐在设备树中固定模式,避免 U-Boot 与内核阶段不一致导致链路训练失败。若 U-Boot 以 RC 模式初始化了控制器,内核再以 EP 模式接管,LTSSM 可能停留在异常状态,表现为 dmesg 中反复出现 link down。

四、链路训练与枚举结果判读

配置完成后,通过串口观察启动日志。RC 模式下,内核 PCIe 主机控制器驱动会打印扫描到的总线号与设备号,典型日志包含 pcieport 0000:00:00.0: PCI bridge to [bus 01] 以及 pcieport 0000:00:00.0: link up, speed 5 GT/s, width x4。此时执行 lspci -tv 应能看到下游设备树状结构。

EP 模式下,LS1046A 自身不会主动枚举,需在上游 RC 主机上执行 lspci。若上游能看到 Vendor ID 为 0x1957(NXP)的设备,且 BAR 空间已正确分配,说明 EP 配置生效。同时,LS1046A 侧 dmesg 应出现 pcie-endpoint: link up 与 LTSSM state: L0。

若链路未训练成功,优先检查:1)参考时钟是否由 RC 侧提供;2)PERST# 复位时序是否满足 100ms 要求;3)设备树中 status 是否为 okay;4)U-Boot 与内核模式是否一致。可用示波器测量 REFCLK 与 PERST# 波形辅助定位。

五、常见问题与排查路径

实际调试中,lspci 无输出是最常见的现象。此时应依次确认:控制器是否使能(lspci -d 1957: 查看 RC 自身)、链路是否达到 L0(dmesg | grep -i ltssm)、设备树 ranges 是否覆盖下游 BAR 地址。若 EP 侧被枚举但 BAR 读写异常,检查 ep-bars 声明的窗口是否与上游 RC 的 ranges 重叠且无冲突。

对于需要双向通信的场景,RC 与 EP 的地址映射必须成对配置:RC 的 ranges 出站窗口对应 EP 的入站 BAR,EP 的出站窗口对应 RC 的入站区域。任何一侧缺失都会导致配置空间可读但内存访问失败。

建议在修改设备树前备份原始 DTB,并使用 dtc -I dtb -O dts 反编译确认最终生效的节点属性,避免因覆盖顺序导致模式声明被意外覆盖。