Files
dpdk-blog/notes/phase0/day01-pcie-topology.md
T
newbie 41531c19c2 init: DPDK → DPU learning blog (VitePress)
- VitePress static site for rendering all markdown documents
- Auto-discovers .md files from dpdk-roadmap-v3 and dpdk-study-kb
- Features: full-text search, dark mode, responsive design
- Pages: roadmap, notes (Phase 0-3), product docs, knowledge base
2026-08-09 15:42:47 +00:00

5.0 KiB
Executable File
Raw Blame History

Phase 0 · Day 1: PCIe 总线拓扑与 Config Space


一、BDF 地址:每个设备的唯一身份

0000 : 02 : 01 . 0
  │     │    │   └── Function (0~7) — 一个物理芯片可以有多个功能
  │     │    └────── Device  (0~31) — 同一总线上最多 32 个设备
  │     └─────────── Bus     (0~255) — 256 条总线
  └───────────────── Domain  (0~65535) — 多 CPU socket 系统有多个 domain

单 CPU 系统 domain=0000。多路服务器每个 socket 一个 domain。

DPDK 通过 BDF 地址接管网卡:dpdk-devbind.py -b vfio-pci 02:01.0

为什么需要三级?

PCI 是树形拓扑。每个 Bridge 引入一条新 bus。256 条 bus × 32 设备 × 8 功能 = 65536 个可寻址功能。如果没有 bus 层级,只靠 5-bit device 最多 32 个设备——一张显卡+一张网卡就满了。

二、拓扑中的四种角色

角色 你的实例 职责
Root Complex 00:00.0 CPU 和 PCIe 世界的桥梁,把 load/store 翻译成 TLP
PCI Bridge 00:11.0 → Bus 02 传统 PCI 桥,用 subtractive decode 转发未认领的访问
PCIe Root Port 00:15.0 → Bus 03 PCIe 原生桥,点对点链路,支持更高带宽
Endpoint 02:01.0 03:00.0 叶子节点,实际的网卡设备

关键差异:02:01.0 (e1000) 是挂在传统 PCI Bridge 后面的老式设备,多条设备共享 Bus 02。03:00.0 (VMXNET3) 是 PCIe Endpoint,独享 Bus 03 的整条链路(5GT/s × x32)。

二、PCIe 拓扑

[0000:00] ← Root Complex (Host Bridge)
  │          CPU 访问 PCIe 设备的唯一入口
  │
  ├── 11.0 → [02] ← PCI Bridge (老式总线)
  │   ├── 01.0  e1000 (Endpoint)
  │   └── 04.0  e1000 (Endpoint)
  │
  └── 15.0 → [03] ← PCIe Root Port (真正的 PCI Express)
       └── 00.0  VMXNET3 (Endpoint)

数据流:CPU → Root Complex → TLP 封装 → PCIe 链路 → Endpoint。

三、Config Space 完整解码

e1000 (02:01.0) 的 256 字节 Config Space,逐字段解码:

Offset 字段 Hex 值 含义
0x00-01 Vendor ID 0x8086 Intel
0x02-03 Device ID 0x100f 82545EM
0x04-05 Command 0x0113 IO+Mem enable, BusMaster OFF
0x0a-0b Class Code 0x020000 Network Controller
0x0e Header Type 0x00 Endpoint
0x10-13 BAR0 0xfd5c0004 Memory@0xfd5c0000, 64bit, 128KB, Non-Prefetchable
0x18-1b BAR2 0xfdff0004 Memory@0xfdff0000, 64KB
0x20-23 BAR4 0x00002001 IO Port@0x2000
0x34 Capability Ptr 0xdc 链表起点
0x3c Interrupt Line 0x07 IRQ 7
0x3d Interrupt Pin 0x01 INTA#

BAR flag bit 解码: bit0=Memory/IO, bit[2:1]=32b/64b, bit3=Prefetchable。0xfd5c0004 中的 4 = 0100₂ → 64-bit Memory, Non-Prefetchable。真实基址 = 0xfd5c0004 & ~0xF = 0xfd5c0000。

Capability 链表: 0xdc→PM(ID=1)→0xe4→PCI-X(ID=7)→0x00(End)。

四、VMXNET3 对比 (真正的 PCIe 设备)

e1000 VMXNET3
总线 PCI-X (老) PCIe v2.0
Capability PM + PCI-X PM + PCIe Express + MSI + MSI-X + Serial#
MSI-X 无 25 向量, BAR2 offset 0, PBA offset 0x1000

五、实战踩坑

坑 1: Bus Master 没开

  • 现象: DPDK 启动后一个包都收不到
  • 根因: Command bit2=0 → 网卡不能 DMA
  • 定位: lspci -vvv | grep "BusMaster"
  • 修复: pci_set_master(pdev) 或 setpci -s XX:XX.X COMMAND=0x117

坑 2: 64-bit BAR 误读

  • 现象: 物理地址 >4GB 时 MMIO 地址错误
  • 根因: 只用 uint32_t 读 BAR0 低 32 位
  • 修复: 用 resource_size_t pci_resource_start(pdev, 0)

坑 3: MSI-X 向量不够

  • 现象: 多队列网卡性能不增长
  • 根因: pci_alloc_irq_vectors 返回数 < RX 队列数
  • 定位: cat /proc/interrupts | grep PCI-MSI | wc -l
  • 修复: 增大内核 MSI-X 限制或 BIOS 调整

坑 4: PCIe 链路降速

  • 现象: 100Gbps 网卡只能跑 25Gbps
  • 定位: lspci -vvv | grep -E "LnkCap:|LnkSta:" → Speed 2.5GT/s
  • 修复: 检查物理槽位宽度、PCIe 延长线、BIOS 设置

坑 5: AER 静默数据损坏

  • 现象: 偶尔出现 mbuf 数据乱码但不 crash
  • 定位: dmesg | grep AER → Uncorrectable Error
  • 修复: 必须换硬件,链路已不可靠

六、核心认知

CPU 操作网卡的全路径:

读 Config Space → 匹配 Vendor/Device ID → 确定驱动
  → pci_enable_device → ioremap(BAR0) → 拿到虚拟地址
    → ioread32/iowrite32 操作寄存器 → 网卡开始工作

BAR 是 MMIO 的入口,Config Space 是身份证,Capability 链表是扩展机制。

七、检验标准

  • 能解释 BDF 地址含义
  • 能手写 Config Space 前 16 字节字段
  • 能从 hex 值解码 BAR 的基址和大小
  • 能画 Capability 链表结构
  • 能对比 e1000(PCI-X) vs VMXNET3(PCIe v2)
  • 能解释为什么 Bus Master bit 不置位就没 DMA