diff --git a/PCIe_Knowledge_Summary.md b/PCIe_Knowledge_Summary.md index ebcb6b08a5ec0f..0472772bdb2387 100644 --- a/PCIe_Knowledge_Summary.md +++ b/PCIe_Knowledge_Summary.md @@ -8,14 +8,53 @@ ## 目录 1. [PCIe 基础概念](#1-pcie-基础概念) + - 1.1 [什么是 PCIe?](#11-什么是-pcie) + - 1.2 [PCIe vs PCI 对比](#12-pcie-vs-pci-对比) + - 1.3 [PCIe 带宽速率](#13-pcie-带宽速率) + - 1.4 [Lane(通道)概念](#14-lane通道概念) + - 1.5 [PCIe 发展历程](#15-pcie-发展历程) 2. [PCIe 拓扑结构](#2-pcie-拓扑结构) + - 2.1 [整体架构](#21-整体架构) + - 2.2 [核心组件说明](#22-核心组件说明) + - 2.3 [PCIe Switch 内部结构](#23-pcie-switch-内部结构) 3. [PCIe 配置空间](#3-pcie-配置空间) + - 3.1 [配置空间结构](#31-配置空间结构) + - 3.2 [重要寄存器说明](#32-重要寄存器说明) + - 3.3 [BAR (Base Address Register) 解析](#33-bar-base-address-register-解析) 4. [PCIe 事务层协议](#4-pcie-事务层协议) + - 4.1 [PCIe 分层架构](#41-pcie-分层架构) + - 4.2 [TLP (Transaction Layer Packet) 类型](#42-tlp-transaction-layer-packet-类型) + - 4.3 [TLP 包结构](#43-tlp-包结构) 5. [Linux 内核 PCIe 子系统架构](#5-linux-内核-pcie-子系统架构) + - 5.1 [内核 PCIe 目录结构](#51-内核-pcie-目录结构) + - 5.2 [核心数据结构关系](#52-核心数据结构关系) 6. [PCIe 设备枚举流程](#6-pcie-设备枚举流程) + - 6.1 [枚举总体流程](#61-枚举总体流程) + - 6.2 [关键代码路径](#62-关键代码路径) + - 6.3 [BDF 地址编码](#63-bdf-地址编码) 7. [PCIe 驱动加载流程](#7-pcie-驱动加载流程) + - 7.1 [驱动注册与匹配流程](#71-驱动注册与匹配流程) + - 7.2 [驱动结构定义](#72-驱动结构定义) + - 7.3 [Probe 函数典型实现](#73-probe-函数典型实现) + - 7.4 [设备初始化步骤图](#74-设备初始化步骤图) 8. [关键数据结构](#8-关键数据结构) + - 8.1 [struct pci_dev](#81-struct-pci_dev) + - 8.2 [struct pci_driver](#82-struct-pci_driver) + - 8.3 [struct pci_bus](#83-struct-pci_bus) 9. [实践示例](#9-实践示例) + - 9.1 [查看系统 PCIe 设备](#91-查看系统-pcie-设备) + - 9.2 [内核配置空间访问](#92-内核配置空间访问) + - 9.3 [sysfs 接口](#93-sysfs-接口) +10. [常见问题与调试](#10-常见问题与调试) + - 10.1 [调试命令](#101-调试命令) + - 10.2 [常见问题](#102-常见问题) +11. [pci-utils 基本用法](#11-pci-utils-基本用法) + - 11.1 [安装](#111-安装) + - 11.2 [lspci — 列出 PCI 设备](#112-lspci--列出-pci-设备) + - 11.3 [setpci — 读写 PCI 配置空间](#113-setpci--读写-pci-配置空间) + - 11.4 [update-pciids — 更新 PCI ID 数据库](#114-update-pciids--更新-pci-id-数据库) + - 11.5 [实用调试场景](#115-实用调试场景) + - 11.6 [pciutils 库 (libpci) 编程接口](#116-pciutils-库-libpci-编程接口) --- @@ -93,6 +132,117 @@ └─────────────────────────────────────────────────────┘ ``` +### 1.5 PCIe 发展历程 + +PCIe 技术从传统 PCI 总线演化而来,经历了多次重大技术革新,以下是完整的发展脉络: + +#### 1.5.1 前 PCIe 时代 + +| 时间 | 标准 | 说明 | +|------|------|------| +| **1990年** | PCI 草案 | Intel 主导制定 PCI (Peripheral Component Interconnect) 规范草案 | +| **1992年** | PCI 1.0 | 正式发布,32位/33MHz 并行总线,带宽 133MB/s | +| **1993年** | PCI 2.0 | 改进规范,完善电气特性和协议细节 | +| **1995年** | PCI 2.1 | 支持 66MHz,带宽提升至 266MB/s (32位) 或 533MB/s (64位) | +| **1998年** | PCI-X 1.0 | 面向服务器市场,64位/133MHz,带宽达 1066MB/s | +| **2002年** | PCI-X 2.0 | 支持 266MHz/533MHz,但共享总线架构的瓶颈愈发明显 | + +``` + PCI 总线 (共享并行架构的局限) + ┌──────────────────────────────────────────────────────────────┐ + │ │ + │ CPU ◄══════════════════════════════════════════════► │ + │ ║ ║ ║ ║ │ + │ 设备A 设备B 设备C 设备D │ + │ │ + │ 问题:所有设备共享同一总线带宽,存在竞争和冲突 │ + │ 并行信号高频下的串扰和时序问题严重 │ + └──────────────────────────────────────────────────────────────┘ +``` + +#### 1.5.2 PCIe 各代际发展 + +**PCIe 1.0 (2003年)** +- 由 Intel、Dell、HP、IBM 等联合推出 +- 采用**点对点串行**架构,彻底取代 PCI 共享并行总线 +- 每通道 (Lane) 传输速率 2.5 GT/s,采用 8b/10b 编码 +- 单通道 (x1) 有效带宽 250 MB/s(双向 500 MB/s) +- 支持 x1, x2, x4, x8, x12, x16, x32 通道配置 +- 定义了完整的分层协议架构(事务层、数据链路层、物理层) + +**PCIe 1.1 (2005年)** +- 对 1.0 的小幅改进 +- 完善了信号完整性要求和测试规范 + +**PCIe 2.0 (2007年)** +- 传输速率翻倍至 **5.0 GT/s**,仍使用 8b/10b 编码 +- 单通道有效带宽 500 MB/s(双向 1 GB/s) +- 保持与 PCIe 1.x 完全向后兼容 +- 引入链路速度自动协商机制 + +**PCIe 3.0 (2010年)** +- 传输速率提升至 **8.0 GT/s** +- 编码方式从 8b/10b 改为 **128b/130b**,编码效率从 80% 提升至 ~98.5% +- 单通道有效带宽约 984 MB/s(双向约 1.97 GB/s) +- 成为最长寿、应用最广泛的 PCIe 版本之一 +- 此后很长一段时间,大量显卡、SSD 和网卡基于此标准 + +**PCIe 4.0 (2017年)** +- 传输速率再翻倍至 **16.0 GT/s**,编码仍为 128b/130b +- 单通道有效带宽约 1.97 GB/s(双向约 3.94 GB/s) +- AMD Zen 2 架构(如 Ryzen 3000 系列)率先支持 +- NVMe SSD(如 Samsung 980 PRO)开始大量采用 PCIe 4.0 x4 + +**PCIe 5.0 (2019年)** +- 传输速率提升至 **32.0 GT/s**,编码仍为 128b/130b +- 单通道有效带宽约 3.94 GB/s(双向约 7.88 GB/s) +- Intel 第 12 代 Alder Lake 和 AMD Zen 4 架构开始支持 +- 主要面向高端 SSD、AI 加速卡、高速网卡(100G/200G 以上) + +**PCIe 6.0 (2022年)** +- 传输速率再次翻倍至 **64.0 GT/s** +- 编码方式革命性改变:采用 **PAM4 (4级脉冲幅度调制)** + **1b/1b FLIT 编码** + **FEC (前向纠错)** +- 引入 FLIT (Flow Control Unit) 固定大小包机制,取代传统的可变长 TLP +- 单通道有效带宽约 7.88 GB/s(双向约 15.75 GB/s) +- x16 配置下双向带宽高达 **252 GB/s** + +**PCIe 7.0 (预计 2025年)** +- 目标传输速率 **128.0 GT/s** +- 继续使用 PAM4 调制 +- x16 双向带宽预计将达 **512 GB/s** +- 主要面向数据中心、AI/ML 训练、高性能计算 (HPC) + +``` + PCIe 各版本发展时间线与带宽演进 + ═══════════════════════════════════════════════════════════════ + + 2003 2007 2010 2017 2019 2022 2025(预计) + │ │ │ │ │ │ │ + ▼ ▼ ▼ ▼ ▼ ▼ ▼ + 1.0 2.0 3.0 4.0 5.0 6.0 7.0 + 2.5GT/s 5GT/s 8GT/s 16GT/s 32GT/s 64GT/s 128GT/s + 8b/10b 8b/10b 128b/130b 128b/130b PAM4 PAM4 + + x16 双向带宽: + 8GB/s → 16GB/s → 32GB/s → 64GB/s → 128GB/s → 252GB/s → 512GB/s + ×2 ×2 ×2 ×2 ×2 ×2 + + 关键技术节点: + ├─ 2003: 串行取代并行,点对点取代共享总线 + ├─ 2010: 128b/130b 编码取代 8b/10b,编码效率质的飞跃 + ├─ 2022: PAM4 调制 + FLIT 机制,信号层面革命性变化 + └─ 2025: 继续倍增,面向 AI/HPC 超大带宽需求 +``` + +#### 1.5.3 PCIe 标准管理组织 + +PCIe 规范由 **PCI-SIG (PCI Special Interest Group)** 制定和维护: + +- **成立时间**: 1992 年 +- **成员**: 超过 900 家企业(含 Intel、AMD、NVIDIA、Broadcom、Samsung 等) +- **职责**: 制定 PCI/PCIe 规范、合规性测试、互操作性认证 +- **官网**: https://pcisig.com + --- ## 2. PCIe 拓扑结构 @@ -880,14 +1030,350 @@ $ lspci -vvv -s 01:00.0 | grep -i "lnk" --- +## 11. pci-utils 基本用法 + +**pciutils** (也写作 pci-utils) 是 Linux 下用于查看和操作 PCI/PCIe 设备的标准用户态工具集,由 Martin Mares 维护,是每一位内核开发和系统管理员的必备工具。 + +### 11.1 安装 + +```bash +# Debian / Ubuntu +$ sudo apt install pciutils + +# RHEL / CentOS / Fedora +$ sudo dnf install pciutils +# 或 +$ sudo yum install pciutils + +# Arch Linux +$ sudo pacman -S pciutils + +# 源码编译 +$ git clone https://github.com/pciutils/pciutils.git +$ cd pciutils +$ make && sudo make install +``` + +### 11.2 lspci — 列出 PCI 设备 + +`lspci` 是 pciutils 中最常用的命令,用于列出系统中所有 PCI/PCIe 设备信息。 + +#### 基本用法 + +```bash +# 列出所有 PCI 设备(简洁模式) +$ lspci +00:00.0 Host bridge: Intel Corporation 12th Gen Core Processor Host Bridge (rev 02) +00:02.0 VGA compatible controller: Intel Corporation Alder Lake-P GT2 (rev 0c) +00:1f.0 ISA bridge: Intel Corporation Alder Lake PCH eSPI Controller (rev 01) +01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd NVMe SSD ... +02:00.0 Network controller: Intel Corporation Wi-Fi 6 AX201 (rev 20) +``` + +#### 常用选项 + +```bash +# -v / -vv / -vvv 逐步增加详细程度 +$ lspci -v # 简要详细信息 +$ lspci -vv # 更详细信息 +$ lspci -vvv # 最详细信息(包括所有 Capability 解析) + +# -s 指定设备(BDF 地址过滤) +$ lspci -s 01:00.0 # 查看特定设备 +$ lspci -s 01: # 查看总线 01 上的所有设备 +$ lspci -s :00.0 # 查看所有总线上 device=00, function=0 的设备 + +# -d 按 Vendor:Device ID 过滤 +$ lspci -d 8086: # 列出所有 Intel (0x8086) 设备 +$ lspci -d :1234 # 列出 Device ID 为 0x1234 的设备 +$ lspci -d 10de:* # 列出所有 NVIDIA (0x10de) 设备 + +# -t 树形拓扑显示 +$ lspci -tv +-[0000:00]-+-00.0 Intel Corporation 12th Gen Core Processor Host Bridge + +-02.0 Intel Corporation Alder Lake-P GT2 + +-1c.0-[01]----00.0 Samsung Electronics Co Ltd NVMe SSD + +-1c.4-[02]----00.0 Intel Corporation Wi-Fi 6 AX201 + \-1f.0 Intel Corporation Alder Lake PCH eSPI Controller + +# -n 显示数字格式的 Vendor/Device ID(不解析名称) +$ lspci -n +00:00.0 0600: 8086:4621 (rev 02) +01:00.0 0108: 144d:a80a + +# -nn 同时显示名称和数字 ID(最实用) +$ lspci -nn +00:00.0 Host bridge [0600]: Intel Corporation 12th Gen ... [8086:4621] (rev 02) +01:00.0 NVMe controller [0108]: Samsung Electronics [144d:a80a] + +# -k 显示设备使用的内核驱动和模块 +$ lspci -k +01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd ... + Subsystem: Samsung Electronics Co Ltd ... + Kernel driver in use: nvme + Kernel modules: nvme + +# -x / -xx / -xxx / -xxxx 以十六进制 dump 配置空间 +$ lspci -x -s 01:00.0 # 标准配置空间 (前64字节) +$ lspci -xx -s 01:00.0 # 标准配置空间 (前256字节) +$ lspci -xxx -s 01:00.0 # 扩展配置空间 (需 root) +$ lspci -xxxx -s 01:00.0 # 完整 4KB 扩展配置空间 (需 root) + +# -D 始终显示 Domain 号 +$ lspci -D +0000:00:00.0 Host bridge: Intel Corporation ... +``` + +#### 组合使用示例 + +```bash +# 查看 NVMe SSD 完整信息 + PCIe 链路状态 +$ sudo lspci -vvv -s 01:00.0 + +# 输出中重点关注: +# LnkCap: Speed 8GT/s, Width x4 ← 设备支持的最大链路能力 +# LnkSta: Speed 8GT/s, Width x4 ← 当前实际链路状态 +# LnkCtl: ASPM L1 Enabled ← 电源管理状态 + +# 查看所有网络设备及其驱动 +$ lspci -nn -k -d ::0200 +02:00.0 Ethernet controller [0200]: Intel Corporation I210 [8086:1533] (rev 03) + Kernel driver in use: igb + +# 以机器可读格式输出(适合脚本解析) +$ lspci -mm +$ lspci -vmm # 每个字段独立一行 +$ lspci -vmm -s 01:00.0 +Slot: 01:00.0 +Class: Non-Volatile memory controller +Vendor: Samsung Electronics Co Ltd +Device: NVMe SSD Controller ... +``` + +### 11.3 setpci — 读写 PCI 配置空间 + +`setpci` 用于直接读取或写入 PCI 设备的配置空间寄存器,是底层调试和硬件配置的利器。 + +> **警告**: 错误使用 `setpci` 可能导致系统不稳定甚至硬件损坏,请谨慎操作。 + +#### 基本语法 + +```bash +setpci [选项] -s <寄存器>[.<宽度>][=<值>] + +# 宽度说明: +# .B = Byte (1字节) +# .W = Word (2字节) +# .L = Long (4字节, 默认) +``` + +#### 常用示例 + +```bash +# 读取 Vendor ID (偏移 0x00, 2字节) +$ sudo setpci -s 01:00.0 0x00.W +144d + +# 读取 Device ID (偏移 0x02, 2字节) +$ sudo setpci -s 01:00.0 0x02.W +a80a + +# 读取 Command 寄存器 (偏移 0x04, 2字节) +$ sudo setpci -s 01:00.0 COMMAND.W +0407 + +# 读取 Status 寄存器 +$ sudo setpci -s 01:00.0 STATUS.W +0010 + +# 读取 Class Code (偏移 0x08, 4字节,包含 revision) +$ sudo setpci -s 01:00.0 0x08.L +01080200 + +# 读取 BAR0 +$ sudo setpci -s 01:00.0 BASE_ADDRESS_0.L +a1200004 + +# 使用寄存器名称(更易读) +$ sudo setpci -s 01:00.0 VENDOR_ID.W +$ sudo setpci -s 01:00.0 DEVICE_ID.W +$ sudo setpci -s 01:00.0 CLASS_DEVICE.W + +# 写入 Command 寄存器(启用 Bus Master) +$ sudo setpci -s 01:00.0 COMMAND.W=0x0407 + +# 使用位掩码进行部分写入 +# 格式: 寄存器.宽度=值:掩码 +# 仅修改掩码为1的位 +$ sudo setpci -s 01:00.0 COMMAND.W=0004:0004 # 仅设置 Bus Master 位 + +# 读取 PCIe Capability 中的 Link Status +# 首先找到 PCIe Cap 偏移 (通常在 Capability List 中) +$ sudo setpci -s 01:00.0 CAP_EXP+12.W # Link Status Register +``` + +#### 寄存器名称速查 + +```bash +# setpci 支持的常用寄存器名称: +VENDOR_ID # 0x00 厂商 ID +DEVICE_ID # 0x02 设备 ID +COMMAND # 0x04 命令寄存器 +STATUS # 0x06 状态寄存器 +REVISION # 0x08 修订号 +CLASS_PROG # 0x09 编程接口 +CLASS_DEVICE # 0x0a 设备类别 +CACHE_LINE_SIZE # 0x0c 缓存行大小 +LATENCY_TIMER # 0x0d 延迟计时器 +HEADER_TYPE # 0x0e 头类型 +BASE_ADDRESS_0 # 0x10 BAR0 +BASE_ADDRESS_1 # 0x14 BAR1 +BASE_ADDRESS_2 # 0x18 BAR2 +BASE_ADDRESS_3 # 0x1c BAR3 +BASE_ADDRESS_4 # 0x20 BAR4 +BASE_ADDRESS_5 # 0x24 BAR5 +INTERRUPT_LINE # 0x3c 中断线 +INTERRUPT_PIN # 0x3d 中断引脚 + +# PCIe Capability 相关 (通过 CAP_EXP 前缀访问): +CAP_EXP+02.W # PCIe Capabilities Register +CAP_EXP+08.L # Device Capabilities +CAP_EXP+0c.W # Link Capabilities (低16位) +CAP_EXP+10.W # Link Control +CAP_EXP+12.W # Link Status +``` + +### 11.4 update-pciids — 更新 PCI ID 数据库 + +`lspci` 依赖 PCI ID 数据库来将数字 ID 解析为可读的厂商和设备名称。 + +```bash +# 更新本地 PCI ID 数据库(需要网络) +$ sudo update-pciids +Downloaded daily snapshot dated 2026-02-05 ... + +# 数据库文件位置 +$ ls -la /usr/share/misc/pci.ids* +# 或 +$ ls -la /usr/share/hwdata/pci.ids + +# 数据库来源: https://pci-ids.ucw.cz/ +``` + +### 11.5 实用调试场景 + +#### 场景一:排查 PCIe 链路降速 + +```bash +# 1. 查看设备的链路能力和当前状态 +$ sudo lspci -vvv -s 01:00.0 | grep -E "LnkCap|LnkSta" + LnkCap: Port #0, Speed 16GT/s, Width x4, ... + LnkSta: Speed 8GT/s (downgraded), Width x4 (ok), ... + +# 解读: 设备支持 PCIe 4.0 x4,但当前运行在 PCIe 3.0 x4 (降速) +# 可能原因: 主板限制、BIOS 设置、信号完整性问题 + +# 2. 同时检查上游端口 (Root Port 或 Switch Downstream Port) +$ sudo lspci -vvv -s 00:1c.0 | grep -E "LnkCap|LnkSta" +``` + +#### 场景二:检查 MSI/MSI-X 中断配置 + +```bash +# 查看设备的 MSI-X 信息 +$ sudo lspci -vvv -s 01:00.0 | grep -A5 "MSI-X" + Capabilities: [b0] MSI-X: Enable+ Count=128 Masked- + Vector table: BAR=0 offset=00002000 + PBA: BAR=0 offset=00003000 +``` + +#### 场景三:识别未知设备 + +```bash +# 1. 获取设备的 Vendor:Device ID +$ lspci -nn -s 03:00.0 +03:00.0 Unclassified device [00ff]: Unknown device [1234:5678] + +# 2. 在线查询 +# 访问 https://pci-ids.ucw.cz/ 输入 Vendor ID 和 Device ID 查询 + +# 3. 查看 subsystem ID 获取更多线索 +$ lspci -vvv -s 03:00.0 | grep -i subsystem +``` + +#### 场景四:导出设备信息用于 Bug 报告 + +```bash +# 完整导出所有 PCI 信息(适合附在 Bug 报告中) +$ sudo lspci -vvvnn > pci_info.txt + +# 导出完整配置空间十六进制 dump +$ sudo lspci -xxxx > pci_config_dump.txt + +# 导出机器可读格式 +$ lspci -vmm > pci_machine_readable.txt +``` + +### 11.6 pciutils 库 (libpci) 编程接口 + +pciutils 还提供了 C 语言库 `libpci`,可以在用户态程序中直接使用: + +```c +/* 使用 libpci 读取设备信息的示例 */ +#include +#include + +int main(void) +{ + struct pci_access *pacc; + struct pci_dev *dev; + char namebuf[1024]; + + /* 初始化 libpci */ + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); + + /* 遍历所有设备 */ + for (dev = pacc->devices; dev; dev = dev->next) { + pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES | + PCI_FILL_CLASS | PCI_FILL_CAPS); + + printf("%04x:%02x:%02x.%d vendor=%04x device=%04x class=%04x\n", + dev->domain, dev->bus, dev->dev, dev->func, + dev->vendor_id, dev->device_id, dev->device_class); + + /* 获取可读名称 */ + printf(" %s\n", + pci_lookup_name(pacc, namebuf, sizeof(namebuf), + PCI_LOOKUP_DEVICE, + dev->vendor_id, dev->device_id)); + } + + pci_cleanup(pacc); + return 0; +} +``` + +编译方式: + +```bash +$ gcc -o pci_scan pci_scan.c -lpci +$ sudo ./pci_scan +``` + +--- + ## 参考资料 1. **PCI Express Base Specification** - PCI-SIG 2. **Linux Kernel Documentation** - `Documentation/PCI/` 3. **Linux Device Drivers, 3rd Edition** - O'Reilly 4. **Understanding Linux Network Internals** - O'Reilly +5. **pciutils 项目主页** - https://github.com/pciutils/pciutils +6. **PCI ID 数据库** - https://pci-ids.ucw.cz/ --- -> **文档版本**: 1.0 -> **最后更新**: 2026年1月 +> **文档版本**: 1.1 +> **最后更新**: 2026年2月