Linux下PCIe BAR空间内存映射IO编程实战工程 - 第1节

1. PCIe基础概念

PCI Express(PCIe)是一种高速串行计算机扩展总线标准,旨在替代传统的 PCI、PCI-X 和 AGP 并行总线。其核心设计理念是采用点对点串行连接,每个设备都与交换器(Switch)建立专用链路,而非共享同一并行总线。这种架构从根本上消除了并行总线中因共享介质而产生的仲裁延迟和信号同步问题。

PCIe 总线架构由以下关键组件构成:

  • 根复合体(Root Complex, RC):连接 CPU、内存和 PCIe 交换器,是 PCIe 层次结构的根节点。它负责生成事务层数据包(TLP),并处理来自下游设备的请求。
  • 交换器(Switch):由上游端口(Upstream Port)和多个下游端口(Downstream Port)组成,负责在多个端点之间路由数据包。交换器内部包含一个虚拟的 PCI 桥,用于管理地址和配置空间。
  • 端点(Endpoint, EP):功能设备,如网卡、GPU、NVMe SSD。端点可以是传统功能(Legacy Endpoint)或支持单根 I/O 虚拟化(SR-IOV)的端点。
  • 桥(Bridge):用于连接 PCIe 与其它总线(如 PCI、PCI-X),实现协议转换。
关键概念: PCIe 使用“域(Domain)→ 总线(Bus)→ 设备(Device)→ 功能(Function)”的四级拓扑寻址方式,每个功能最多可拥有 6 个 BAR 空间(Base Address Register)。

1.2 拓扑结构

PCIe 采用树形拓扑结构,以根复合体为起点,向下逐级扩展。每个交换器可以连接多个端点或下级交换器,形成层次化的总线域。典型的桌面系统拓扑如下:

PCIe 树形拓扑结构图 根复合体 (RC) CPU / 内存 交换器 (Switch 1) 端点 (EP 1) - GPU 端点 (EP 2) - NVMe 交换器 (Switch 2) 端点 (EP 3) 拓扑说明 每个链路都是点对点连接;交换器内部通过虚拟 PCI 桥实现总线号分配和地址路由。

1.3 分层模型

PCIe 协议栈采用分层架构,从下到上依次为:物理层(Physical Layer)、数据链路层(Data Link Layer) 和 事务层(Transaction Layer)。每个层都有明确的职责和协议数据单元(PDU)。

层次 主要职责 数据单元 关键机制
事务层 生成/解析 TLP,管理事务顺序,处理内存/IO/配置请求 TLP(事务层数据包) 信用流控(Credit Flow Control)、事务排序
数据链路层 保证 TLP 在链路两端可靠传输,错误检测与重传 DLLP(数据链路层数据包) ACK/NAK 协议、CRC 校验、链路管理
物理层 串行/解串、编码/解码、电气特性、链路训练 PLP(物理层数据包) 8b/10b 或 128b/130b 编码、链路状态机
开发提示: 在 Linux 驱动中,我们主要与事务层打交道——通过 MMIO 访问 BAR 空间时,CPU 发起的读写请求会被 RC 封装为 Memory Read/Write TLP,经数据链路层和物理层传输到端点。

1.3.1 事务层(Transaction Layer)

事务层是 PCIe 协议栈的最上层,直接面向软件和驱动开发者。它负责:

  • TLP 封装与解析:将 CPU 的内存/IO 访问请求封装为 TLP,或从接收到的 TLP 中提取数据。
  • 地址空间支持:支持 Memory、IO、Configuration 三种地址空间,其中 Memory 空间又分为 Non-Prefetchable 和 Prefetchable 两种。
  • 事务类型:包括 Memory Read/Write、IO Read/Write、Configuration Read/Write、Message 等。
  • 信用流控(Credit Flow Control):基于 VC(Virtual Channel)的流量控制机制,防止接收端缓冲区溢出。

1.3.2 数据链路层(Data Link Layer)

数据链路层位于事务层和物理层之间,提供可靠的链路级数据传输:

  • TLP 序列化与重传:为每个 TLP 分配序列号(Sequence Number),接收端通过 ACK/NAK DLLP 确认接收状态,发送端在收到 NAK 或超时后重传。
  • CRC 校验:使用 LCRC(Link CRC)检测 TLP 传输错误。
  • 链路电源管理:支持 L0s、L1、L2 等低功耗状态。

1.3.3 物理层(Physical Layer)

物理层定义了电气特性、信号编码和链路训练过程:

  • 串行/解串(SerDes):将并行数据转换为高速串行差分信号,每个 Lane 使用一对差分信号对(TX+/- 和 RX+/-)。
  • 编码方案:Gen1/Gen2 使用 8b/10b 编码(20% 开销),Gen3/Gen4 使用 128b/130b 编码(约 1.5% 开销)。
  • 链路训练状态机(LTSSM):负责链路的初始化、速度协商、宽度协商和恢复。
PCIe 分层模型与数据流 事务层 (Transaction Layer) TLP 生成/解析 · 信用流控 · 事务排序 数据链路层 (Data Link Layer) 序列号 · ACK/NAK · LCRC 校验 · 重传 物理层 (Physical Layer) SerDes · 8b/10b / 128b/130b 编码 · LTSSM 数据流方向 发送路径:事务层 → 数据链路层 → 物理层 → 链路 接收路径:链路 → 物理层 → 数据链路层 → 事务层

1.4 关键概念对比

为了帮助理解 PCIe 与传统 PCI 的差异,下表列出了核心对比项:

特性 传统 PCI PCI Express
总线拓扑 共享并行总线 点对点串行交换
数据传输 并行(32/64 bit) 串行(1/2/4/8/16 Lane)
时钟方式 同步共享时钟 嵌入式时钟(8b/10b 或 128b/130b 编码)
热插拔 不支持(原生) 原生支持(Native Hot-Plug)
配置空间 256 字节(Type 0/1) 4 KB(扩展配置空间)
带宽示例 PCI 32/33: 133 MB/s PCIe 4.0 x16: ~32 GB/s
常见误区: PCIe 虽然名称中包含“PCI”,但两者在电气、协议和软件模型上有本质区别。Linux 驱动中,PCIe 设备仍然使用 PCI 子系统(struct pci_driver)进行管理,但底层配置空间访问和 BAR 映射方式已完全不同。

1.5 本章小结

本章建立了 PCIe 的基础知识框架:

  • PCIe 采用树形拓扑,由根复合体、交换器和端点组成,每个链路都是独立的点对点连接。
  • 协议栈分为事务层、数据链路层、物理层,驱动开发主要关注事务层的 TLP 和 BAR 空间访问。
  • 与传统 PCI 相比,PCIe 在带宽、可扩展性、热插拔和错误处理方面有显著优势。