PCI/PCIe子系统
PCI/PCIe子系统
1. 基础概念与拓扑结构
1.1 基本概念
- PCI (Peripheral Component Interconnect):连接计算机主板与外设的并行总线标准
- PCIe (PCI Express):PCI的串行演进,带宽更高、拓扑更灵活
- 配置空间(Configuration Space):每个PCI设备都有256B基础配置空间,用于存储设备信息与控制寄存器
- 桥(Bridge):连接不同总线域/segment的设备,负责地址域转换与请求/包转发
1.2 PCIe拓扑结构
PCIe系统结构按以下角色组织(树状层次结构):
- Root Complex(RC):CPU与PCIe拓扑之间的接口
- PCIe Bus / Link:数据传输通道
- Endpoint(端点设备):拓扑末端的设备
- Port / Bridge:连接不同总线域的设备
- Switch(交换/扩展):提供多个下游端口的设备
1.3 设备类型
- Root Complex(RC):位于倒立树拓扑的“根”,通过Host Bridge向系统暴露PCI bus 0
- Root Port:RC内部的端口,在PCI配置空间中表现为PCI-PCI bridge
- Bridge:提供与其他总线(PCI/PCI-X,甚至另一段PCIe)互联的设备
- Switch:PCIe-to-PCIe的桥/交换结构,提供扩展能力
- Endpoint:拓扑末端设备,可作为请求发起者或完成者
- Legacy PCIe Endpoint:兼容PCI的端点
- Native PCIe Endpoint:标准PCIe端点,通常以MMIO为主进行访问
- RCiEP(Root Complex Integrated Endpoint):直接挂到Root Complex上的集成设备
2. 设备表示与寻址
2.1 BDF(Bus:Device.Function)
系统启动/枚举后,每个PCI设备会被分配唯一地址BDF:
- Bus Number:8 bits(最多256条总线)
- Device Number:5 bits(每条总线最多32个设备)
- Function Number:3 bits(每个设备最多8个功能)
一般写作BB:DD.F。在Linux上可用lspci查看拓扑与BDF:
~$ lspci -t -v
# [Domain:Bus]
-[0000:00]-+-00.0 Intel Corporation 8th/9th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S]
+-02.0 Intel Corporation CoffeeLake-S GT2 [UHD Graphics 630]
+-12.0 Intel Corporation Cannon Lake PCH Thermal Controller
+-14.0 Intel Corporation Cannon Lake PCH USB 3.1 xHCI Host Controller
+-14.2 Intel Corporation Cannon Lake PCH Shared SRAM
+-15.0 Intel Corporation Cannon Lake PCH Serial IO I2C Controller #0
+-16.0 Intel Corporation Cannon Lake PCH HECI Controller
+-17.0 Intel Corporation SATA Controller [RAID mode]
+-1c.0-[01-02]----00.0-[02]--
+-1f.0 Intel Corporation Q370 Chipset LPC/eSPI Controller
+-1f.3 Intel Corporation Cannon Lake PCH cAVS
+-1f.4 Intel Corporation Cannon Lake PCH SMBus Controller
+-1f.5 Intel Corporation Cannon Lake PCH SPI Controller
\-1f.6 Intel Corporation Ethernet Connection (7) I219-LM
2.2 Function(多功能设备)
Function表示同一个PCI Device内部的不同逻辑功能单元。一个物理设备可包含多个独立功能模块,每个模块在系统看来像一个独立设备。
例如同一个1f号设备(Intel PCH)提供多个不同功能:
+-1f.0 Intel Corporation Q370 Chipset LPC/eSPI Controller
+-1f.3 Intel Corporation Cannon Lake PCH cAVS
+-1f.4 Intel Corporation Cannon Lake PCH SMBus Controller
+-1f.5 Intel Corporation Cannon Lake PCH SPI Controller
\-1f.6 Intel Corporation Ethernet Connection (7) I219-LM
2.3 Type 0 / Type 1(设备头类型)
从枚举与配置空间视角,常用两类“头”来区分角色:
- Type 0:最终端设备(如显卡、声卡、网卡等)
- Type 1:桥/端口类设备(如Root Port、PCIe Switch端口等)
3. 配置空间与访问机制
3.1 配置访问:Type 0 与 Type 1
- Type 0 配置访问:访问同一条总线上的端点设备(直连设备)
- Type 1 配置访问:访问桥设备或通过桥访问其他总线上的设备(跨桥/跨总线)
配置访问里常用的定位字段:
- Bus:总线号
- Device:设备号
- Function:功能号
- Register:寄存器偏移
3.2 ECAM(Enhanced Configuration Access Mechanism)
ECAM是现代平台常用的PCI配置空间访问机制:通过内存映射把“某个BDF + offset”的配置空间映射到CPU可访问的地址空间。
void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
{
struct pci_config_window *cfg = bus->sysdata;
void __iomem *base;
// 计算配置空间地址:
// bus号、devfn(设备+功能)、偏移地址 -> 映射到内存空间
}
4. 地址转换与包转发机制
4.1 地址转换原理
PCI/PCIe系统核心能力之一是地址转换:将CPU的系统地址转换为PCI设备可识别的地址,从而访问设备寄存器与MMIO空间。
关键点:
- 上电初始化:BIOS/固件/引导阶段会把地址映射信息写入桥设备的配置寄存器(资源窗口)
- 桥设备:作为中间层,负责地址域转换与请求转发
- 主机控制器驱动:相关驱动常归在
pci_host/host controller一类,用于管理PCI主机控制器与配置空间访问
4.2 包转发与转换
- Type 0:用于访问直接连接的设备
- Type 1:用于访问非直接连接的设备,在桥之间逐级转发
- 当Type 1到达目标总线对应的桥时,会在该桥处转换为Type 0,再由目标总线上的设备响应
端到端流程:
- CPU发起访问(地址/配置访问)
- 主机桥/端口进行地址/路由判定
- 生成Type 0或Type 1
- Type 1在桥之间转发
- 到达目标bus的桥后Type 1 → Type 0
- 目标设备处理请求并完成返回
4.3 地址范围请求与分配
- 桥设备会根据直接连接的下级设备需求,向上级总线控制器请求/索要地址范围(I/O、MMIO等资源窗口)
- 这保证地址空间合理分配并避免冲突
分配流程:
- 初始化:BIOS/引导程序提供基础资源规划
- 枚举:PCI子系统扫描总线设备
- 请求:桥根据下级需求向上级请求窗口
- 分配:上级分配合适范围
- 配置:写入桥设备配置寄存器,建立映射表
4.4 PCIe的“端口选通”
- PCI(并行):可从“地址线选通”角度理解桥后设备选择
- PCIe(点对点):每个端口后通常只连一个设备;拓扑上更像在“选通端口并沿树路由”,而不是共享总线上的广播选通
5. PCIe Switch结构
当需要连接不止一个下游设备时,使用PCIe Switch。其内部可抽象为:
- 一个Upstream Port + Bridge:连接上游(Root Port或上游Switch的Downstream Port)
- 一组Downstream Port + Bridge:连接下游端点或下游Switch
- 内部互联(虚拟总线/交换结构):把上/下游端口连接起来,使上游可访问下游设备
6. Linux PCI驱动架构
6.1 PCI核心功能
PCI核心驱动位于drivers/pci/pci.c,提供核心能力:
- 设备枚举与初始化:扫描总线上的设备并初始化
- 配置空间访问:读写设备配置寄存器
- 资源管理:分配和管理设备资源
- 电源管理:控制设备电源状态
- 中断管理:管理设备中断
6.2 主机控制器驱动
通用PCI主机控制器驱动示例:
static int gen_pci_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
struct pci_ecam_ops *ops;
of_id = of_match_node(gen_pci_of_match, pdev->dev.of_node);
ops = (struct pci_ecam_ops *)of_id->data;
return pci_host_common_probe(pdev, ops);
}
配置空间访问操作示例:
static struct pci_ecam_ops gen_pci_cfg_cam_bus_ops = {
.bus_shift = 16,
.pci_ops = {
.map_bus = pci_ecam_map_bus,
.read = pci_generic_config_read,
.write = pci_generic_config_write,
}
};
7. 核心代码分析
7.1 设备启用流程
int pci_enable_device(struct pci_dev *dev)
{
return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
}
static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
struct pci_dev *bridge;
u16 cmd;
u8 pin;
err = pci_set_power_state(dev, PCI_D0);
if (err < 0 && err != -EIO)
return err;
bridge = pci_upstream_bridge(dev);
if (bridge)
pcie_aspm_powersave_config_link(bridge);
err = pcibios_enable_device(dev, bars);
if (err < 0)
return err;
pci_fixup_device(pci_fixup_enable, dev);
// 启用中断
if (dev->msi_enabled || dev->msix_enabled)
return 0;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (pin) {
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (cmd & PCI_COMMAND_INTX_DISABLE)
pci_write_config_word(dev, PCI_COMMAND,
cmd & ~PCI_COMMAND_INTX_DISABLE);
}
return 0;
}
7.2 设备枚举
struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
{
struct pci_dev *dev;
u32 l;
if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l) != PCIBIOS_SUCCESSFUL)
return NULL;
if (l == 0xffffffff)
return NULL;
dev = pci_scan_device(bus, devfn);
if (!dev)
return NULL;
return dev;
}
7.3 电源管理
int pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
int error;
/* 状态验证 */
if (state > PCI_D3cold)
state = PCI_D3cold;
else if (state < PCI_D0)
state = PCI_D0;
else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
return 0;
/* 检查当前状态 */
if (dev->current_state == state)
return 0;
__pci_start_power_transition(dev, state);
/* 处理特殊情况 */
if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3))
return 0;
/* 设置电源状态 */
error = pci_raw_set_power_state(dev, state > PCI_D3hot ?
PCI_D3hot : state);
if (!__pci_complete_power_transition(dev, state))
error = 0;
return error;
}
7.4 配置空间访问
int pci_find_capability(struct pci_dev *dev, int cap)
{
int pos;
pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
if (pos)
pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
return pos;
}
8. PCIe特有机制
8.1 端点设备特性
- 端口单一设备:每个PCIe端口后只连接一个设备
- 端口地址:PCIe桥内部端口有独立地址
- 端口选通:选通的实际上是端口,而非设备本身
8.2 串行传输优势
- 串行差分信号:提供更高的带宽
- 多通道支持:x1, x2, x4, x8, x16等
- 点对点连接:每个设备直接连接到上游端口
9. 整体架构总结
CPU → 根复合体 (Root Complex) → PCIe交换机 → 端点设备
↑
主桥
↑
PCI总线
↑
PCI桥
↑
次级PCI总线
10. 技术要点
- Type 0/Type 1包:区分直接访问和跨桥访问;Type 1在桥间转发,到目标桥处转为Type 0
- ECAM:现代配置空间访问机制(内存映射方式)
- 地址/资源窗口:上电初始化与枚举过程中,通过桥设备配置寄存器建立映射与窗口
- 总线枚举:自动发现设备、分配bus number、设置桥窗口与设备BAR等资源
- BDF寻址:Bus:Device.Function的三层寻址方式
- 多功能设备:一个物理设备可包含多个逻辑功能
11. 学习建议
11.1 代码阅读顺序
- 先了解基本概念:PCI架构、配置空间、BDF编号
- 查看核心数据结构:
struct pci_dev、struct pci_bus - 分析核心函数:设备枚举、配置访问、资源管理
- 研究主机控制器:
drivers/pci/host/目录下的代码 - 跟踪地址转换:分析Type 0/Type 1包的处理流程
11.2 重点关注
- 配置空间访问:
pci_read_config_*和pci_write_config_*函数 - 设备枚举:
pci_scan_bus系列函数 - 资源分配:
pci_enable_resources函数 - 桥设备管理:地址范围请求和分配机制
- PCIe特有功能:AER、ASPM等高级特性
12. 总结
PCI/PCIe子系统通过层次化拓扑(RC/Port/Switch/Endpoint)、配置空间、地址转换与资源窗口、以及Type 0/Type 1转发/转换机制,为CPU与外设之间提供高效可靠的通信路径。
理解这些机制有助于驱动开发、系统优化与故障排查;结合Linux内核drivers/pci/与drivers/pci/host/的实现,可以把“规范里的抽象”与“实际平台行为”对应起来。
PCI总线架构的设计思想和实现机制,为现代计算机系统的外设连接提供了灵活、高效的解决方案,是计算机体系结构中的重要组成部分。