4. Linux PCIe子系统架构

Linux内核的PCIe子系统是一个高度层次化的软件栈,负责管理从设备枚举、资源分配到驱动绑定和数据传输的全生命周期。理解其层次结构和核心数据结构,是开发RC(Root Complex)和EP(Endpoint)驱动的基础。

4.1 PCIe子系统层次结构

PCIe子系统在Linux内核中分为三个主要层次:总线层、设备层和驱动层。每一层都通过特定的数据结构抽象,并通过内核提供的API进行交互。

层次概览: 总线层(pci_bus)管理拓扑和配置空间访问;设备层(pci_dev)代表一个具体的PCIe功能;驱动层(pci_driver)实现设备的具体操作逻辑。
Linux PCIe子系统三层架构 驱动层 (Driver Layer) pci_driver probe() / remove() / suspend() / resume() 设备层 (Device Layer) pci_dev vendor / device / class / irq / resource[] / cfg_space 总线层 (Bus Layer) pci_bus parent / children / devices / ops / busn_res 驱动层通过pci_driver与设备层绑定,设备层通过pci_bus访问配置空间和资源

4.2 核心数据结构详解

PCIe子系统的核心由三个数据结构支撑:pci_dev、pci_bus和pci_driver。它们分别对应设备、总线和驱动,构成了整个PCIe驱动框架的基石。

4.2.1 pci_dev:PCIe设备抽象

pci_dev是内核中代表一个PCIe功能(Function)的核心结构体。无论是RC端的桥设备,还是EP端的端点设备,最终都会被枚举为一个pci_dev实例。

字段类型说明
vendorunsigned int厂商ID(如0x8086为Intel)
deviceunsigned int设备ID
classunsigned int设备类别(如0x060400为PCI桥)
irqunsigned int中断号(INTx或MSI/MSI-X)
resource[]struct resource6个BAR空间及ROM资源描述
busstruct pci_bus *指向所属总线的指针
devstruct device内核通用设备,用于驱动模型
cfg_sizeint配置空间大小(256B或4KB)
关键点: 在RC模式下,pci_dev代表的是PCIe桥或下游端口;在EP模式下,pci_dev代表端点自身。驱动通过pci_dev访问BAR空间和配置寄存器。

4.2.2 pci_bus:PCIe总线拓扑

pci_bus结构体描述了一条PCIe总线,包括其父总线、子总线以及挂载在该总线上的所有设备。它构成了PCIe树形拓扑的节点。

字段类型说明
parentstruct pci_bus *父总线(上游总线)
childrenstruct list_head子总线链表
devicesstruct list_head挂载在此总线上的设备链表
selfstruct pci_dev *指向此总线的桥设备(若为根总线则为NULL)
numberunsigned char总线编号(由BIOS或内核分配)
opsstruct pci_ops *配置空间访问操作函数集
busn_resstruct resource此总线的子总线编号范围
pci_bus 拓扑关系示例 pci_bus 0 (Root Bus) pci_dev (Bridge) pci_bus 1 (Downstream) pci_bus 2 (Downstream) pci_dev (EP) pci_dev (EP) 每个pci_bus通过parent/children形成树形结构,devices链表挂载该总线上的所有pci_dev 桥设备(pci_dev)同时作为上游总线的设备,和下游总线的self指针

4.2.3 pci_driver:PCIe驱动模型

pci_driver是驱动开发者最常接触的结构体。它通过内核的驱动模型与pci_dev进行匹配和绑定。

struct pci_driver {
    const char *name;                    // 驱动名称
    const struct pci_device_id *id_table; // 支持的设备ID表
    int  (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
    void (*remove)(struct pci_dev *dev);
    int  (*suspend)(struct pci_dev *dev, pm_message_t state);
    int  (*resume)(struct pci_dev *dev);
    // ... 其他回调
};
回调函数触发时机典型操作
probe()设备枚举完成,驱动匹配成功时启用设备、分配资源、注册中断、初始化硬件
remove()设备热拔出或驱动卸载时释放资源、注销中断、关闭设备
suspend()系统进入低功耗状态时保存设备状态、停止DMA
resume()系统从低功耗状态恢复时恢复设备状态、重新初始化
RC与EP驱动差异: 在RC模式下,probe()通常用于初始化桥设备或下游端口,并可能触发子总线的扫描;在EP模式下,probe()专注于端点自身的功能初始化,如配置BAR空间和DMA引擎。

4.3 数据结构之间的协作关系

三个核心数据结构通过内核驱动模型紧密协作,形成完整的PCIe设备管理闭环:

  1. 枚举阶段: 内核通过pci_bus的ops访问配置空间,发现设备后创建pci_dev实例,并将其挂载到对应总线的devices链表。
  2. 匹配阶段: 内核遍历已注册的pci_driver,将id_table与pci_dev的vendor/device/class进行匹配。
  3. 绑定阶段: 匹配成功后,内核调用pci_driver的probe()回调,传入pci_dev指针,驱动开始初始化硬件。
  4. 运行阶段: 驱动通过pci_dev的resource[]访问BAR空间,通过irq注册中断处理函数。
pci_bus / pci_dev / pci_driver 协作流程 pci_bus 枚举 创建 pci_dev 匹配 pci_driver 调用 probe() pci_bus提供拓扑和配置访问能力 → pci_dev承载设备属性 → pci_driver实现设备控制逻辑 probe()是驱动与设备绑定的入口,也是RC/EP驱动初始化的起点

4.4 关键API与使用模式

在驱动开发中,以下API是操作这三个核心数据结构的常用入口:

API所属层功能
pci_get_device()设备层按vendor/device查找pci_dev
pci_enable_device()设备层启用设备(使能I/O和内存空间)
pci_request_regions()设备层申请BAR资源
pci_iomap()设备层将BAR映射到CPU虚拟地址空间
pci_register_driver()驱动层注册pci_driver到内核
pci_bus_read_config_*()总线层通过pci_bus读取配置空间
RC驱动提示: 在RC模式下,经常需要遍历pci_bus的children和devices链表来发现下游设备,并使用pci_bus_alloc_resource()分配总线资源。