RK3588 kernel-6.1 — drivers/pci/hotplug 目录详细分析

RK3588 kernel-6.1drivers/pci/hotplug 目录详细分析

1. 文档范围

项目 说明
源码路径 rk3588/kernel-6.1/drivers/pci/hotplug
关联路径 include/linux/pci_hotplug.hdrivers/pci/pcie/(端口 HP 服务)、drivers/pci/probe.c 等枚举核心
目标 说明 PCI 带电插拔(Hotplug) 的软件分层、各后端驱动职责、与 PCIe 原生端口的关系,以及在 RK3588 / DT 场景下的取舍

2. 子系统在 PCI 栈中的位置

flowchart TB
  subgraph userspace [用户空间]
    sysfs["/sys/bus/pci/slots/..."]
    udev[udev / 策略]
  end
  subgraph hotplug_core [hotplug 通用核心]
    pci_hp["pci_hotplug_core.c\nhotplug_slot / pci_slot"]
  end
  subgraph backends [后端驱动 · 选一或多]
    pciehp["pciehp · PCIe Native Slot"]
    acpiphp["acpiphp · ACPI PCI"]
    shpchp["shpchp · SHPC"]
    gpio["gpio_php · DT GPIO"]
    other["cpqphp / ibmphp / cpci / …"]
  end
  subgraph pcie_port [PCIe 端口层]
    portdrv["pcie_port_bus_type\nPCIE_PORT_SERVICE_HP"]
  end
  subgraph pci_core [PCI 核心]
    scan["pci_scan_slot\npci_bus_add_devices"]
    remove["拔除路径 · remove/rescan"]
  end
  sysfs --> pci_hp
  pci_hp --> backends
  pciehp --> portdrv
  pciehp --> scan
  pciehp --> remove
  acpiphp --> pci_hp
  acpiphp --> scan
  gpio --> portdrv
  gpio --> pci_hp

要点

  • 框架层只认识 struct hotplug_slot + hotplug_slot_ops,不关心下面是 PCIe Slot 寄存器还是 ACPI。
  • PCIe 原生热插pciehp)必须建立在 CONFIG_PCIEPORTBUS 已为端口创建 HP 服务(pcie_device 的前提下(见 drivers/pci/pcie)。
  • 枚举/注销最终仍调用 PCI 核心的 pci_scan_*pci_stop_and_remove_bus_device_* 一类接口(具体由各后端在 enable/disable 路径里组合)。

3. 通用核心:pci_hotplug_core.c

3.1 数据结构(include/linux/pci_hotplug.h

struct hotplug_slot_ops — 各后端必须实现的回调(按需可为 NULL):

回调 典型用途
enable_slot / disable_slot 用户写 sysfs power 时上电/断电并触发扫描或拔除
get_power_status 读电源状态
set_attention_status / get_attention_status Attention 指示灯
get_latch_status MRL(Manual Retention Latch) 机械锁闩状态
get_adapter_status 槽内是否有卡(在 sysfs 中文件名为 adapter
hardware_test 可选硬件自检
reset_slot 可选:槽位或次级总线复位(避免与普通 secondary bus reset 副作用冲突时使用)

struct hotplug_slot

  • ops:上表回调表。
  • pci_slot:与 pci_create_slot() 建立的 struct pci_slot 绑定;pci_slot->hotplug 指回本结构。
  • owner / mod_name:模块所有权,sysfs 操作里 try_module_get 防止卸载竞态。

3.2 注册与生命周期 API

API 作用
pci_hp_register(slot, bus, devnr, name) __pci_hp_initialize + pci_hp_add 一步完成:分配 pci_slot、关联 hotplug、创建 sysfs、发 KOBJ_ADD uevent
pci_hp_initialize / pci_hp_add 两步:先只做 pci_create_slot,再 fs_add_slot + 加入全局链表
pci_hp_del 从链表摘除并 fs_remove_slot(撤 sysfs)
pci_hp_destroy pci_destroy_slot,断开 pci_slot->hotplug
pci_hp_deregister pci_hp_del + pci_hp_destroy

内核全局pci_hotplug_slot_list + pci_hp_mutex;按 hotplug_slot_name()(即 pci_slot_name)查找槽位。

3.3 对用户空间的 sysfs 接口(/sys/bus/pci/slots/<name>/

根据 hotplug_slot_ops 中非空成员 选择性创建

文件名 条件 读写
power 存在 enable_slot / disable_slot / get_power_status 读状态;写 0disable_slot1enable_slot
attention 存在 set_*get_attention_status 读写 Attention LED
latch 存在 get_latch_status 只读
adapter 存在 get_adapter_status 只读(适配器是否在槽)
test 存在 hardware_test 写触发测试

另外会为模块创建 符号链接pci_hp_create_module_link)。

3.4 模块初始化

device_initcall(pci_hotplug_init):若编译 CONFIG_HOTPLUG_PCI_CPCI,会调用 cpci_hotplug_init

模块参数debug(bool),打开后 pci_hotplug 内核日志更啰嗦。


4. ACPI 公共代码:acpi_pcihp.c

编入 pci_hotplug.o 的条件:CONFIG_ACPI(见 hotplug/Makefile)。

主要职责

  • acpi_get_hp_hw_control_from_firmware(pdev):对桥设备查找 ACPI 节点并评估 _OSHP,尝试 从固件取得 OS 对热插硬件的控制权(失败时的语义由各调用方处理)。
  • 配合 acpi_pci_root、host bridge 句柄遍历 PCI 设备 ACPI companion。

与原生驱动的分工:在 CONFIG_ACPIpci_hotplug.h 提供 pciehp_is_native / shpchp_is_nativehotplug_is_native(bridge) 表示二者其一为原生则视为原生路径占优,用于避免 ACPI 与原生 HPC 重复接管冲突。


5. Makefile 编译拓扑与链接顺序

文件:drivers/pci/hotplug/Makefile

5.1 核心与条件编译

1
CONFIG_HOTPLUG_PCI          → pci_hotplug.o ← pci_hotplug_core.o [+ cpci* ] [+ acpi_pcihp.o ]

5.2 按特性追加的对象(节选)

CONFIG 变量 组成
HOTPLUG_PCI_COMPAQ cpqphp.o cpqphp_core/ctrl/sysfs/pci [+ nvram]
HOTPLUG_PCI_IBM ibmphp.o ibmphp_core/ebda/pci/res/hpc
HOTPLUG_PCI_PCIE pciehp.o pciehp_core / ctrl / pci / hpc
HOTPLUG_PCI_SHPC shpchp.o shpchp_core/ctrl/pci/sysfs/hpc
HOTPLUG_PCI_POWERNV pnv-php.o pnv_php.o
HOTPLUG_PCI_RPA rpaphp.o rpaphp_core/pci/slot
HOTPLUG_PCI_RPA_DLPAR rpadlpar_io.o rpadlpar_core/sysfs
HOTPLUG_PCI_ACPI acpiphp.o acpiphp_core / glue
HOTPLUG_PCI_S390 s390_pci_hpc.o 单文件
HOTPLUG_PCI_GPIO gpio_php.o 单文件
HOTPLUG_PCI_ACPI_IBM acpiphp_ibm.o 必须在 acpiphp 之后链接(扩展 ACPI)
HOTPLUG_PCI_CPCI_ZT5550 cpcihp_zt5550.o
HOTPLUG_PCI_CPCI_GENERIC cpcihp_generic.o

注释要求CONFIG_HOTPLUG_PCI_PCIE(及同类原生驱动)在 CONFIG_HOTPLUG_PCI_ACPI 之前列出,使 原生 HPC 优先绑定,无原生时再退回 ACPI 通用实现


6. Kconfig 关联

6.1 drivers/pci/hotplug/Kconfig

  • 顶层 HOTPLUG_PCI:依赖 PCI && SYSFS
  • 各子选项:HOTPLUG_PCI_ACPISHPCCPCI、PowerNV、RPA、GPIO、s390、Compaq、IBM 等(详见源码)。
  • HOTPLUG_PCI_PCIE 不在本文件中定义,而在 drivers/pci/pcie/Kconfig(依赖 HOTPLUG_PCI && PCIEPORTBUS)。

6.2 PCIe 原生热插依赖链(摘要)

1
2
PCIEPORTBUS → 端口总线与 HP/AER/PME 等服务
HOTPLUG_PCI_PCIE → pciehp 驱动(绑定 PCIE_PORT_SERVICE_HP)

7. PCIe 原生热插:pciehp_*(重点)

7.1 模块划分

文件 职责
pciehp.h struct controller:关联 struct pcie_devicectrl->pcie->port 即端口 pci_dev)、缓存 Slot Capabilities / Slot ControlCommand Completed 同步(ctrl_lockwait_queuecmd_busy)、电源故障标志、poll_threadhotplug_slotreset_lock(复位期间屏蔽 Presence/DLLLA 抖动)等
pciehp_core.c 装配 hotplug_slot_ops(enable/disable/reset/attention/adapter…)、pci_hp_initialize / pci_hp_destroy、模块参数
pciehp_hpc.c 硬件层:读 PCI_EXP_SLTSTA / PCI_EXP_SLTCTL、处理 Presence Detect Changed、Button Press、Attention Button、Power Fault、Command Completedrequest_threaded_irq 上半部 pciehp_isr + 线程 pciehp_ist;或 pciehp_poll 内核线程
pciehp_ctrl.c 策略/状态机:与用户可见操作、延迟上电(Attention Button 约 5 秒)、工作队列协作
pciehp_pci.c pciehp_configure_device():对桥下 pci_lock_rescan_removepci_get_slot 判重 → pci_scan_slotpci_bus_add_devices;拔除侧对称调用 PCI 核心移除接口(在同模块其它路径)

7.2 模块参数

  • pciehp_poll_mode:无可靠 MSI/中断时使用 轮询
  • pciehp_poll_time:轮询周期(秒)。

7.3 与 PCIe 规范的衔接(实现层面)

  • Slot Control 写入:规范要求两次写入间隔或依赖 Command Completed;驱动用 pcie_poll_cmd / IRQ 路径清 PCI_EXP_SLTSTA_CC,避免违规访问。
  • In-band Presence Disable:部分 OEM(如 DMI 表中的 Dell)对 NVMe 槽启用 in-band presence disabled 行为;pciehp_hpc.cinband_presence_disabled_dmi_table 等变通,避免错误探测。

7.4 与 drivers/pci/pcie 的绑定

pciehp.h #include "../pcie/portdrv.h":驱动作为 pcie_port_service_driver 注册 HP 服务,probe 时拿到 struct pcie_device * 与端口 IRQ

结论:没有 PCIEPORTBUS 或未创建 HP 服务时,pciehp 不会绑定,即便硬件有物理槽位。


8. ACPI PCI 热插:acpiphp_*

文件 职责
acpiphp_core.c ACPI slot/桥 数据结构、与 pci_hotplug 核心对接的具体逻辑
acpiphp_glue.c ACPI CA 粘合acpi_device notify、bridge_listacpiphp_init_context / acpi_set_hp_context、dock fixup、acpiphp_sanitize_bus、热插事件 hotplug_event
acpiphp.h 内部结构与声明
acpiphp_ibm.c(可选) IBM ACPI 扩展

acpiphp_glue.c 文件头说明了 pci_dev 引用计数规则(桥扫描 pci_get_slot、子ordinate bus、卸载时释放),排查泄漏时可对照。


9. 其它后端一览

模块 适用硬件/场景
shpchp_* Standard Hot-Plug Controller(SHPC),常见于传统 PCI/PCI-X 桥片暴露的标准寄存器集
cpqphp_* Compaq 专有控制器,BIOS/NVRAM(可选 cpqphp_nvram
ibmphp_* IBM 专有,EBDA 等查找控制器
cpci_hotplug_* + cpcihp_* CompactPCI,PICMG 2.1 ENUM
pnv_php.c IBM POWERNV
rpaphp_* / rpadlpar_* pSeries RPADLPAR I/O 动态分区
s390_pci_hpc.c IBM Z PCI function standby/注销
gpio_php.c 设备树 GPIO:GPIO 表示连接状态;与 pcie_port 注册配合,走 gpio_hotplug_slot 封装 pci_hp_*

10. 典型调用链(插入,pciehp

  1. 硬件产生 Presence Detect Changed 或用户 power1
  2. pciehp_ist / pciehp_poll 解析 Slot Statuspciehp_ctrl 状态机允许后调用 enable 路径。
  3. pciehp_configure_devicepci_scan_slot 发现新 pci_devpci_bus_add_devices 触发 pci_driver probe
  4. udev 根据 pci_slot / MODALIAS 加载设备驱动。

拔除路径对称:disable_slot → 停止设备 → 从总线移除 → 必要时关电。


11. 调试与排障建议

现象 可查项
/sys/bus/pci/slots/ 条目 CONFIG_HOTPLUG_PCI、是否 pci_hp_add 成功、是否有任一后端 probe
有槽无 pciehp CONFIG_PCIEPORTBUSCONFIG_HOTPLUG_PCI_PCIElspci -vv 看端口是否有 Slot Cap;内核 pcie_ports= / ACPI _OSC 是否禁止原生
中断不工作 pciehp_poll_mode=1 验证;检查端口 MSI 分配
ACPI 与原生冲突 hotplug_is_nativedmesgacpiphp / pciehp 注册顺序

12. RK3588(Device Tree)场景

事实 说明
通常无 ACPI PCI hotplug acpiphp / acpi_pcihp 多数配置下不参与
原生 PCIe 槽 若 SoC/固件为下游端口声明标准 PCIe Slot,且开启 PCIEPORTBUS + HOTPLUG_PCI_PCIEpciehp 可工作
板级 GPIO M.2 卡检测脚可通过 HOTPLUG_PCI_GPIO + DTS 描述接入 gpio_php
裁剪 嵌入式产品若固定单板无带电插拔,可在 defconfig 中关闭 Compaq/IBM/SHPC/RPA/s390 等以减小体积

13. 目录源码索引(约 50 文件)

核心pci_hotplug_core.cacpi_pcihp.c(条件)、cpci_hotplug_core.ccpci_hotplug_pci.c(条件)。

PCIepciehp_core.cpciehp_ctrl.cpciehp_hpc.cpciehp_pci.cpciehp.h

ACPIacpiphp_core.cacpiphp_glue.cacpiphp.hacpiphp_ibm.c

SHPCshpchp_core.cshpchp_ctrl.cshpchp_pci.cshpchp_sysfs.cshpchp_hpc.cshpchp.h

其它cpqphp_*ibmphp_*gpio_php.cgpiophp.hpnv_php.crpaphp_*rpadlpar_*s390_pci_hpc.ccpcihp_*MakefileKconfigTODO


14. 参考与修订

日期 说明
2026-05-08 初版:pci_hotplug 框架、pciehp/ACPI/其它后端、Makefile/Kconfig、RK3588 注意事项

规范细节请以 PCI Express Base Specification(Slot Capability/Control、Command Completed)及 include/linux/pci_hotplug.h 为准。

文章互动

阅读 --

留言

0 条留言

正在加载留言…