本文对 PCIe 热插拔的概念及工作原理进行不完全总结。
更新: 2022 / 12 / 31
1992年初始版本的 PCI 规范并不支持运行时的板卡添加和移除。在20世纪90年代后期到21世纪初期,各种专有的热拔插控制器或者与厂商无关的标准热拔插控制器被构思出来,同时 Linux 通过位于 drivers/pci/hotplug 的驱动开始支持热拔插功能。然而,直到2002年 Linux 才开始支持PCI Express 的热拔插功能,但是具体的形式随时间不断变化。最初,PCI Express 热拔插主要是为服务器的热交换板卡或笔记本的 ExpressCards 设计的,如今,它已经广泛地应用于数据中心 ( 数据中心 NVMe Flash 硬盘需要运行时拔插 ) 和雷电接口。
热插拔
PCIe 热插拔,是指在系统上电运行时,允许插入或拔出 PCIe 设备。拔出时不需要平台提前下电,插入时直接生效,不需要系统重启。这对于服务器实现高可靠性而言是一个必不可少的特性。
热插拔可以分为2种,通知式热插拔 和 暴力热插拔。这两种差异主要体现在拔盘的操作上。
- 设备插入时, 内核
pciehp驱动走的都是通知式热插流程,以盘插入时在位信号的变化或者通知按钮的按下作为触发条件。通知式热拔时,需要先通过软件指令,停止业务,移除pcie设备,再进行拔盘操作。 - 暴力热拔时,没有任何通知,直接进行拔盘动作。
组成部件
为了 pcie 热插拔功能的实现,PCIe 协议定义了一系列需要实现的组件:
| 组件 | 目的 |
|---|---|
Indicator |
show the power and attention state of the slot。 标准模型中定义两个 indicators:一个Power Indicator 和一个 Attention Indicator。都会有三种状态:ON;OFF;Blinking。 |
Attention Indicator 是黄色的灯,用来指示出现了操作的问题,或者表示 hotplug slot 已经被识别到了,手动操作可以很容易定位到。ON: 表示热插拔槽位故障OFF: 表示一切正常BLINKING: 表示热插拔流程正在执行 |
|
Power Indicator 是绿色的灯,表示 slot 的 power 状态,可以用 blink 指示总线对用户的操作产生了响应。OFF: 表示槽位下电,可以进行设备的热插或热拔ON: 表示热插拔操作已完成,槽位上电,不可以进行热插或热拔BLINKING: 表示此时正在处于上电或下电槽位, 或者此时 attention button 被按下,正在等待反馈,或者表示 hot-plug 操作正在进行软件的初始化 |
|
Manually-operated Retention Latch (MRL) |
Holds adds-in cards in place |
MRL Sensor |
Allows the Port and system software to detect the MRL being openedMRL 是一种手动操作保留机制。保持插入卡在 slot 上,防止用户移除卡。系统添加了一个 MRL sensor,以便侦测每个 port 对应的 slot 的 MRL。 |
Electromechanical Interlock |
Prevents removal of add-in cards while slot is powered 一种互斥机制,确保在热插拔流程都执行完成后 PCIe 设备才可被物理移除。 |
Attention Button |
Allows user to request Hot-Plug operations 是 hotplug 中定义的一个开关按钮,一般会在 slot 上或者在卡片上,按一下表明要做一个 hotplug 动作或者 removal 动作。 |
Software User Interface |
Allows user to request Hot-Plug operations |
Slot Numbering |
Provides visual identification of slots 槽位编号,由底板号( Classic Number )和物理槽位号( Physical Slot Number ) 组成,可在用户接口上显示。 |
实现代码
通知式热插拔
热拔的流程图如下所示:

热插流程类似,不再赘述。
PCIe 热插拔功能的实现需要 pcie 热插拔控制器和 pcie 热插拔驱动的配合。
代码主要集中在 driver/pci/hotplug/pciehp_hpc.c 6 和 driver/pci/hotplug/pciehp_ctrl.c 7。
pciehp_hpc.c主要负责控制器的初始化以及检测设备在位变化、attention button pressed、电源错误等事件检测,检测到这些事件后,会上报热插拔中断。pciehp_ctrl.c代码主要是对热插拔各个events的具体处理。
pciehp初始化
PCIe热插拔是作为pcie端口服务实现的,它已在driver/pci/hotplug/pciehp_core.c8 中的pcie端口驱动程序中注册:
int __init pcie_hp_init(void)
{
int retval = 0;
retval = pcie_port_service_register(&hpdriver_portdrv);
pr_debug("pcie_port_service_register = %d\n", retval);
if (retval)
pr_debug("Failure to register service\n");
return retval;
}
之后会调用 pcie_probe 进行端口注册,
+->pciehp_probe(struct pcie_device *dev)
+-> pcie_init()
+-> pcie_init_slot()
// 该函数中会创建hotplug_slot, hotplug_slot_info, hotplug_slot_ops等热插拔驱动关键的数据结构
+-> init_slot()
+-> pci_hp_initialize()
+-> pci_create_slot()
+-> kobject_init_and_add()
// 添加sysfs对象
+-> list_add(&slot->list, &parent->slots)
// 将hotplug_slot添加到pci_hotplug_slot_list
+-> pcie_init_notification()
+-> pciehp_request_irq()
//中断申请
+-> pcie_enable_notification()
+-> pciehp_enable_slot()
// 使能hp槽位
+-> board_added()
- 注册热插拔中断服务 6
static inline int pciehp_request_irq(struct controller

本文深入探讨了PCIe热插拔在Linux系统中的实现,包括通知式和暴力热插拔的区别,以及热插拔的组成部件如指示器、手动保留锁等。文章详细解析了Linux内核中PCIe热插拔驱动的中断处理流程,介绍了如何处理电源管理、意外移除错误和整合错误处理。此外,还提到了即将引入的BAR移除功能,以优化资源分配。通过对驱动代码的分析,展示了如何在设备插入和移除时协调中断和线程,确保系统的稳定性和效率。
最低0.47元/天 解锁文章
2214

被折叠的 条评论
为什么被折叠?



