RK3588 kernel-6.1 — drivers/pci/hotplug 目录详细分析
1. 文档范围
| 项目 | 说明 |
|---|---|
| 源码路径 | rk3588/kernel-6.1/drivers/pci/hotplug |
| 关联路径 | include/linux/pci_hotplug.h、drivers/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 |
读状态;写 0 → disable_slot,1 → enable_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_ACPI 下 pci_hotplug.h 提供 pciehp_is_native / shpchp_is_native;hotplug_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_ACPI、SHPC、CPCI、PowerNV、RPA、GPIO、s390、Compaq、IBM 等(详见源码)。 HOTPLUG_PCI_PCIE不在本文件中定义,而在drivers/pci/pcie/Kconfig(依赖HOTPLUG_PCI && PCIEPORTBUS)。
6.2 PCIe 原生热插依赖链(摘要)
1 | PCIEPORTBUS → 端口总线与 HP/AER/PME 等服务 |
7. PCIe 原生热插:pciehp_*(重点)
7.1 模块划分
| 文件 | 职责 |
|---|---|
pciehp.h |
struct controller:关联 struct pcie_device(ctrl->pcie->port 即端口 pci_dev)、缓存 Slot Capabilities / Slot Control、Command Completed 同步(ctrl_lock、wait_queue、cmd_busy)、电源故障标志、poll_thread、hotplug_slot、reset_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 Completed;request_threaded_irq 上半部 pciehp_isr + 线程 pciehp_ist;或 pciehp_poll 内核线程 |
pciehp_ctrl.c |
策略/状态机:与用户可见操作、延迟上电(Attention Button 约 5 秒)、工作队列协作 |
pciehp_pci.c |
pciehp_configure_device():对桥下 pci_lock_rescan_remove → pci_get_slot 判重 → pci_scan_slot → pci_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.c含inband_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_list、acpiphp_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 RPA 与 DLPAR 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)
- 硬件产生 Presence Detect Changed 或用户
power写 1。 pciehp_ist/pciehp_poll解析 Slot Status,pciehp_ctrl状态机允许后调用enable路径。pciehp_configure_device:pci_scan_slot发现新pci_dev,pci_bus_add_devices触发pci_driverprobe。- udev 根据
pci_slot/MODALIAS加载设备驱动。
拔除路径对称:disable_slot → 停止设备 → 从总线移除 → 必要时关电。
11. 调试与排障建议
| 现象 | 可查项 |
|---|---|
无 /sys/bus/pci/slots/ 条目 |
CONFIG_HOTPLUG_PCI、是否 pci_hp_add 成功、是否有任一后端 probe |
| 有槽无 pciehp | CONFIG_PCIEPORTBUS、CONFIG_HOTPLUG_PCI_PCIE;lspci -vv 看端口是否有 Slot Cap;内核 pcie_ports= / ACPI _OSC 是否禁止原生 |
| 中断不工作 | pciehp_poll_mode=1 验证;检查端口 MSI 分配 |
| ACPI 与原生冲突 | hotplug_is_native、dmesg 中 acpiphp / pciehp 注册顺序 |
12. RK3588(Device Tree)场景
| 事实 | 说明 |
|---|---|
| 通常无 ACPI PCI hotplug | acpiphp / acpi_pcihp 多数配置下不参与 |
| 原生 PCIe 槽 | 若 SoC/固件为下游端口声明标准 PCIe Slot,且开启 PCIEPORTBUS + HOTPLUG_PCI_PCIE,pciehp 可工作 |
| 板级 GPIO | M.2 卡检测脚可通过 HOTPLUG_PCI_GPIO + DTS 描述接入 gpio_php |
| 裁剪 | 嵌入式产品若固定单板无带电插拔,可在 defconfig 中关闭 Compaq/IBM/SHPC/RPA/s390 等以减小体积 |
13. 目录源码索引(约 50 文件)
核心:pci_hotplug_core.c、acpi_pcihp.c(条件)、cpci_hotplug_core.c、cpci_hotplug_pci.c(条件)。
PCIe:pciehp_core.c、pciehp_ctrl.c、pciehp_hpc.c、pciehp_pci.c、pciehp.h。
ACPI:acpiphp_core.c、acpiphp_glue.c、acpiphp.h、acpiphp_ibm.c。
SHPC:shpchp_core.c、shpchp_ctrl.c、shpchp_pci.c、shpchp_sysfs.c、shpchp_hpc.c、shpchp.h。
其它:cpqphp_*、ibmphp_*、gpio_php.c、gpiophp.h、pnv_php.c、rpaphp_*、rpadlpar_*、s390_pci_hpc.c、cpcihp_*、Makefile、Kconfig、TODO。
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 为准。