2. PCIe协议基础回顾:PCIe拓扑结构、事务层、数据链路层、物理层、配置空间与BAR机制

在开始PCIe驱动从x86向ARM的移植适配之前,必须对PCIe协议的核心层次与机制建立精确的理解。本章将系统回顾PCIe的拓扑结构、分层协议栈(事务层、数据链路层、物理层)、配置空间结构以及BAR(基地址寄存器)机制。这些知识是后续分析硬件差异、调试驱动问题的基石。

2.1 PCIe拓扑结构

PCIe采用树形拓扑,由根复合体(Root Complex, RC)、交换器(Switch)和端点(Endpoint, EP)组成。与传统的PCI共享总线不同,PCIe使用点对点串行链路,每个设备通过独立的逻辑通道与上游通信。

关键概念: 在x86平台上,Root Complex通常集成在CPU内部(如Intel的PCH或AMD的SoC);而在ARM平台上,Root Complex往往是独立的IP核(如Synopsys DesignWare、Cadence),或者集成在SoC内部,但配置方式与x86存在显著差异。
移植提示: ARM平台上的RC配置空间访问方式(ECAM vs. 自定义MMIO)是移植过程中第一个需要确认的硬件差异点。
PCIe拓扑结构示意图 PCIe 树形拓扑结构 Root Complex (RC) Switch Switch Endpoint (EP) Endpoint (EP) Legacy EP (PCI) Endpoint (EP) 拓扑要点: • RC是树的根,负责CPU与PCIe域之间的地址转换与事务路由。 • Switch内部包含一个上游端口(Upstream Port)和多个下游端口(Downstream Port)。 • 每个链路(Link)由一对差分信号对(TX/RX)组成,支持1/2/4/8/16通道(Lane)宽度。 • 虚拟通道(VC)机制允许在同一物理链路上复用多个独立的数据流。

2.2 PCIe分层协议栈

PCIe协议栈分为三个逻辑层:事务层(Transaction Layer)、数据链路层(Data Link Layer)和物理层(Physical Layer)。每个层都有独立的职责和协议数据单元(PDU)。

层次 PDU名称 核心功能 驱动关注点
事务层 TLP(事务层包) 生成/解析读写请求、完成报文;处理端序、地址转换 BAR映射、DMA描述符、MSI/MSI-X中断
数据链路层 DLLP(数据链路层包) 链路管理、错误检测(CRC)、重传(ACK/NAK) 链路状态寄存器、错误日志(AER)
物理层 PLP(物理层包) 串行/解串、8b/10b或128b/130b编码、链路训练 链路宽度/速率协商、LTSSM状态机
移植陷阱: ARM平台上的RC可能不支持某些TLP类型(如原子操作、TLP处理提示),或者对Completion Timeout的处理机制与x86不同。在移植DMA驱动时,务必检查RC的TLP路由能力。
PCIe分层协议栈与数据流 PCIe 分层协议栈与数据流 事务层 (Transaction Layer) TLP: 读/写请求、完成报文、消息 数据链路层 (Data Link Layer) DLLP: 链路管理、CRC校验、ACK/NAK重传 物理层 (Physical Layer) PLP: 串行/解串、编码、链路训练 (LTSSM) 物理介质 (差分信号对 TX/RX) 数据流方向: • 发送路径:事务层 → 数据链路层 → 物理层 → 链路 • 接收路径:链路 → 物理层 → 数据链路层 → 事务层 • 每个层在发送时添加头部/CRC,在接收时剥离并校验。

2.3 配置空间与BAR机制

PCIe配置空间是驱动与硬件交互的核心接口。每个PCIe功能(Function)都拥有独立的4KB配置空间(传统PCI只有256字节)。前64字节是配置头,包含Vendor ID、Device ID、Class Code、BAR等关键字段。

2.3.1 配置空间布局

偏移地址 寄存器名称 宽度 说明
0x00 Vendor ID / Device ID 16+16 bit 厂商与设备标识,驱动匹配的关键
0x04 Command / Status 16+16 bit 控制I/O、内存、总线主控使能
0x08 Revision ID / Class Code 8+24 bit 设备分类(如网络控制器、存储控制器)
0x10 - 0x24 BAR0 - BAR5 32 bit each 基地址寄存器,定义设备地址空间
0x2C Subsystem Vendor / Subsystem ID 16+16 bit 子系统标识,用于精确匹配
0x34 Capabilities Pointer 8 bit 指向能力链表(MSI、PCIe、AER等)
0x3C Interrupt Line / Pin 8+8 bit 传统中断路由信息(ARM平台可能无效)

2.3.2 BAR机制详解

BAR(Base Address Register)是设备向系统声明其所需地址空间的机制。每个BAR可以映射内存空间或I/O空间(I/O空间在ARM平台上通常不支持)。驱动通过读取BAR值获取系统分配的物理地址,然后将其映射到内核虚拟地址空间。

BAR探测流程:
  1. 向BAR写入全1(0xFFFFFFFF)。
  2. 回读BAR值,低比特位表示空间类型和大小信息。
  3. 根据回读值计算所需地址空间大小(取反后加1)。
  4. 恢复原始BAR值。
  5. 系统固件(BIOS/UEFI/设备树)在枚举时分配实际基地址。
BAR配置与地址映射流程 BAR 配置与地址映射流程 设备配置空间 BAR0: 0xFE000000 BAR1: 0xFE100000 BAR2: 0x00000000 ... 系统物理地址空间 0xFE000000 - 0xFE0FFFFF 0xFE100000 - 0xFE1FFFFF (未分配) 内核虚拟地址 ioremap() 返回虚拟地址 供CPU访问 ARM平台BAR移植要点: 1. ARM平台通常不支持I/O空间,所有BAR必须映射为Memory Space。 2. 设备树(Device Tree)中的 ranges 属性定义RC的地址转换规则。 3. 64位BAR在ARM上需要检查RC是否支持 >4GB地址空间(DMA地址掩码)。 4. 使用 dma_set_mask_and_coherent() 设置DMA地址宽度。 5. 避免使用 pci_ioremap_bar() 的默认行为,显式指定映射属性(如非缓存)。

2.4 事务层协议:TLP结构与路由

TLP(事务层包)是PCIe通信的基本单元。一个TLP由头部(Header)、数据负载(Data Payload)和可选的摘要(Digest)组成。头部长度根据地址格式分为3DW(双字)或4DW。

/* TLP 头部格式 (3DW, 内存读请求) */
struct tlp_header_mrd {
    u32 fmt_type;       // [31:24] FMT, [23:16] Type
    u32 length;         // [9:0] 数据负载长度 (以DW为单位)
    u32 requester_id;   // [31:16] Bus/Device/Function
    u32 tag;            // [15:8] 事务标签
    u32 first_be;       // [7:4] 首双字字节使能
    u32 last_be;        // [3:0] 尾双字字节使能
    u32 address;        // [31:2] 32位地址, [1:0] 保留
};

TLP路由方式有三种:地址路由(基于地址)、ID路由(基于Bus/Device/Function)和隐式路由(用于消息)。驱动开发中最常用的是地址路由(内存读写)和ID路由(配置读写)。

2.5 数据链路层与物理层关键机制

数据链路层负责链路完整性,包括CRC校验、重传和流量控制。物理层则管理链路训练状态机(LTSSM),负责协商链路宽度和速率。

状态 描述 驱动调试意义
Detect 检测对端设备是否存在 检查硬件连接和复位时序
Polling 发送训练序列,协商位锁定 确认参考时钟和信号完整性
Configuration 协商链路宽度和通道极性反转 检查链路宽度是否达到预期
L0 正常工作状态 驱动正常收发TLP
Recovery 链路错误后重新训练 检查错误日志和AER寄存器
调试技巧: 在ARM平台上,如果设备无法枚举,首先检查LTSSM是否停留在Detect或Polling状态。使用 lspci -vvv 或直接读取RC的链路状态寄存器(如 PCI_EXP_LNKSTA)确认当前链路宽度和速率。

2.6 本章小结

PCIe协议栈的层次化设计为驱动移植提供了清晰的抽象边界。在x86到ARM的移植过程中,需要重点关注:

  • 拓扑差异: ARM的RC实现方式多样,配置空间访问方式(ECAM vs. 自定义)是首要确认点。
  • 配置空间: ARM平台可能依赖设备树进行地址分配,而非BIOS/UEFI。
  • BAR映射: 必须使用 ioremap() 并注意DMA地址掩码设置。
  • 链路训练: 硬件复位时序和参考时钟配置是常见问题根源。