ACPI相关(5)- PCI热插拔(三)

PCIE热插拔

PCI_E设备和PCI设备通过一种称作无意外(no surprises)方式实现热插拔。用户不允许在未告知系统软件的情况下插入或者移除一个PCI_E设备。用户告知软件将要插入或者移除一个设备之后,软件将进行相关操作,之后告知用户是否可以进行安全的进行这个操作(通过相应的指示器)。然后用户才可以进行接下来的操作。

同时PCI_E设备也可以通过突然意外(surprise removal)的方式移除设备。它通过两根探测引脚(PRSNT1#,PRSNT2#)来实现,这两个引脚比其余的引脚更短,那么在用户移除设备的时候这两根信号会首先断开,系统会迅速的检测到,并迅速做出反应,从而安全移除设备。

在上面简单的介绍之后我们开始介绍实现热插拔必备的软件和硬件部分:

1、介绍软件部分。

下表将详细介绍实现热插拔必须的软件,以及它们的层次结构。

(1)User Interface 用户接口 --- 操作系统提供给用户调用,来请求关闭一个设备或者打开一个刚刚插入的设备。

(2)Hot-Plug Service --- 一个用来处理操作系统发起的请求的服务程序,主要包括例如提供插槽的标识符、打开或者关闭设备、打开或者关闭指示器、返回当前某个插槽的状态(ON or OFF)。

(3)Standardized Hot-Plug System Driver --- 由主板提供,接受来自Hot-Plug Service的请求,控制热插拔控制器(Hot Plug Controller)完成响应请求 。

(4)Device Driver --- 对于一些比较特殊的设备,完成热插拔需要设备的驱动设备来协作。比如,当一个设备移除之后,要将设备的驱动程序设备为静默状态,不再工作。

2、热插拔必须的硬件部分。

(1)Hot-Plug Controller 热插拔控制器 --- 用来接收处理Hot-Plug System Driver发出的指令,一个控制器连接一个支持热插拔的端口(port),PCI_E协议为控制器定义了标准软件接口。

(2)Card Slot Power Switching Logic --- 在热插拔控制器的控制下完成PCI_E设备的上电与断电。

(3)Card Reset Logic --- 在热插拔控制器的控制下对与PCI_E设备连接的PERST#复位信号置1或者置0。

(4)Power Indicator电源指示灯  --- 每一个插槽分配一个指示器,由热插拔控制器控制,指示当前插槽是否有电。

(5)Attention Button --- 每一个插槽分配一个按钮,当用户请求一个热插拔操作时,按压这个按钮。

(6)Attention Indicator   ---  每一个插槽分配一个指示器。指示器用来引起操作者的注意,表明存在一个热插拔事件,或者热插拔失败,由热插拔控制器控制。

(7)Card Present Detect Pins --- 总共有两种卡存在信号,PRSENT1#,PRSNT2#。作用上面我们已经介绍过了。

接下来介绍PCI_E设备热插拔实现框架,了解上述各个部分是如何连接,相互协作的。同时与PCI设备的热插拔进行对比。

3、热插拔框架

1、PCI设备的热插拔框架

PCI是共享总线结构,即一条总线上连接多个设备,在实现热插拔过程就需要额外的逻辑电路,系统存在一个总的Hot-Plug Controller在控制器里面存在各个插槽对应的控制器,控制器在Hot-Plug System Driver的控制下完成热插拔过程。

2、PCIE热插拔框架

而PCI_E是点对点(Peer To Peer)拓扑结构,同时原生支持热插拔功能,这就决定它的系统框架不同于PCI。热插拔控制器分散存在于每个根聚合点(Root complex)或者开关(Switch)中,每个端口(Port)对应一个控制器,不再需要一个单独额外的控制器。用户通过调用用户接口来一层一层实现最后的热插拔功能。

下面我们开始介绍PCI_E设备的实现热插拔的具体过程。热插拔过程可以分为这几个过程(以移除为例):

(1) 用户要移除某个设备,通过物理方式(例如按下按钮)或者软件方式告知操作系统。

(2)操作系统接收到请求之后进行一些必要的操作(例如完成现在正在进行的写操作,并禁止接收新的操作),然后通过物理(例如指示灯)或者软件的方式告知用户你的请求是否可以满足。

(3)如果第二步操作系统告知用户可以进行请求的操作的话,Hot-Plug System Driver将插槽(slot)关闭。通过控制根聚合点(Root complex)或者开关(Switch)中相应的寄存器完成插槽状态的转换。具体的寄存器介绍稍后介绍。

(4)用户移除相应的设备。

首先介绍打开或者关闭插槽的过程。

插槽开状态(On)特点

1. 插槽已经上电。

2. 参考时钟REFCLK已经打开。

3. 插槽连接状态处在活跃状态(active),或者由于电源管理(Active State Power Management)处于待命状态(L0s or L1)。

4. 复位信号PERST#置0。

插槽关状态(Off)特点

1. 插槽断电

2. 参考时钟REFCLK已经关闭。

3. 连接状态处于静默状态(inactive)。相应信号线处于高组态。

4. 复位信号PERST#置1。

硬件上关闭和打开插槽的具体流程。

关闭插槽过程:

1. 将链路链接关闭。端口在物理层(Physical Later)将相关信号设置为高阻态。

2. 将插槽的复位信号PERST#置1。

3. 关闭插槽的参考时钟REFCLK 。

4. 将插槽断电。

打开插槽过程:

1. 将插槽上电。

2. 打开插槽的参考时钟REFCLK。

3. 将复位信号PERST#置0。

一旦插槽上电,参考时钟打开,复位信号置0之后,链接两端将会进行链路训练和初始化,之后就可以收发TLP了。

3、设备移除和设备插入过程:

移除设备:

移除方式可以以物理方式和软件方式两种方式进行。

当以物理方式时:

(1)当通过物理方式告知系统将要移除设备。操作者需要按下插槽中Attention Button。热插拔控制器侦测到这个事件之后,给根聚合点传递一个中断。

(2)Hot Plug Service调用Hot-Plug System Driver,读取现在插槽的状态。之后Hot Plug Service向Hot-Plug System Driver发送一个请求,要求Hot-Plug Controller控制Power Indicator从常亮转向闪烁。操作者可以在五秒内再次按下Attention Button中止移除。

(3)当第二步读取卡槽状态,卡移除请求验证成功,并且热插拔软件允许该操作之后,Power Indicator将持续闪烁。当设备正在进行一些非常重要的操作时,热插拔软件可能不允许该操作。如果软件不允许该操作时,软件将会拒绝该操作,并让Hot-PlugController将Power Indicator停止闪烁,保持常亮。

(4)如果该操作被允许,Hot Plug Service命令Device Driver静默,完成已经接收的操作,并不在进行接受或发出任何请求。

(5)软件操作链接两侧端口的Link Control Register关闭两侧设备的数据通道。

(6)软件通过Hot-Plug Controller将插槽关闭。

(7)在断电成功之后,软件通过Hot-Plug Controller将Power Indicator电源指示器关闭,预示着插槽已断电,此时操作者知道设备此时可以安全的移除设备了。

(8)操作者将卡扣(Mechanical Retention Latch,将设备固定在主板上的设备,可选设备,上面有一个传感器,检测卡扣是否发开)打开,将所有连接线(如备用电源线)断开此时卡移除掉。此步骤与硬件有关,可选。

(9)操作系统将分配给设备的内存空间(Memory Space),IO空间(IO Space),中断线回收再利用。

当以软件方式移除时与物理方式基本相同,但是前两步替换为以下步骤:

操作者发出一个与设备相连的物理插槽号(Physical Slot Number)的移除请求。然后软件显示一个信息要求操作者确认,此时Power Indicator开始由常亮转向闪烁。

插入设备:

插入也分为物理方式和软件方式,设备插入过程是移除的一个反过程,我们这里假设插入的插槽已经断电。

(1)操作者将设备插入,关上卡扣。如果卡扣存在传感器的话,Hot-Plug Controller将会感知到卡扣已经关闭,这是控制器将会将备用信号和备用电源连接到插槽。

(2)操作者通过按压Attention Button来通知Hot-Plug Seriver。同时引起状态寄存器相应位置位,并引发中断事件,发往根聚合点。然后,软件读取插槽状态,辨识请求。

(3)Hot-Plug Service向Hot-Plug System Driver发出请求要求Hot Plug Controller闪烁插槽的Power Indicator,提示现在不能再移除设备了。操作者可以在闪烁开始5秒内再次按压Attention Button来取消插入请求。

(4)当设备允许请求时,Power Indicator将保持闪烁。可能因为设备安全因素禁止插入某些插槽,热插拔软件将不允许该操作。如果软件不允许该操作时,软件将会拒绝该操作,并让Hot-Plug Controller将Power Indicator熄灭。同时建议系统用消息或者日志的方式记录禁止的原因。

(5)Hot-Plug Service向Hot-Plug System Driver发送命令,将相应卡槽打开。

(6)一旦插槽打开,软件命令将Power Indicator打开。

(7)一旦链路训练完成,操作系统开始进行设备枚举,分配Bus Number,Device Number,Function Number,并配置相应配置空间(configuration space)。

(8)操作系统根据设备信息加载相应的驱动程序。

(9)操作系统调用驱动程序执行设备的初始化代码,设置配置空间相应的命令寄存器,使能设备,完成初始化。

4、PCI_E建议的用户接口和相应寄存器介绍。

软件之间的接口。协议没有详细的定义这些接口,但是它定义了一些基础的类型和它的内容。Hot-Plug Service和Hot-Plug System Driver之间的接口如下:

(1)Query Hot-Plug system Driver

输入:none 输出: Hot-Plug System Driver控制的逻辑插槽ID

功能:询问Hot-Plug System Driver控制的的插槽,并返回其逻辑插槽ID。

(2)Set Slot Status

输入:逻辑插槽ID、新的状态、新的Attention Indicator状态、新的Power Indicator状态

输出:请求完成状态

功能:用来控制slot和与之相关的Indicator。

(3)Query Slot Status

输入:逻辑插槽ID 输出:插槽状态 设备电源需求

功能:返回插槽状态,Hot-Plug System Driver返回相比相应信息。

热插拔控制器的可编程接口。PCI_E协议已经在配置空间中定义了相关寄存器。存在有相关寄存器来控制热插拔控制器,进而实现热插拔。

Slot Capabilities Register 这个寄存器主要表明设备存在哪些指示器,传感器。存在在插槽和设备的配置空间中。硬件必须要初始化这个寄存器以表明设备实现哪些硬件了。软件通过读该寄存器来获取硬件信息。下图该寄存器示意图。

Slot Control 该寄存器作为软件接口,可以控制一系列热插拔事件。比如那个事件的发生可以引起中断。

Slot Status and Event Management 热插拔控制器监控一系列事件,将这些事件报告给Hot-Plug System Driver 。软件通过读取这个寄存器来判断那个事件引起中断。寄存器中改变的位必须通过软件清零,以探测之后发生的事件。

4、内核流程分析

pciehp_probe分析:

(1)首先判断是否为热插拔服务且热插拔桥是否存在二级总线(桥下是否链接设备)。调用pcie_init函数初始化struct controller *ctrl:

struct controller *ctrl结构申请内存,读取桥设备的Slot Capabilities寄存器值,根据hotplug_user_indicators判断是否存在按钮指示灯以及电源指示灯。并初始化cap相应位,判断是否为intel的雷电接口,有则使能No Command Completed Support。

读取pcie能力寄存器link寄存器,判断相应位初始化link_active_reporting。初始化Slot Status寄存器。

调用pcie_init_slot,为struct slot *slot申请内存,获取slot状态,将结构初始化给ctrl结构。

判断slot能力寄存器Power Controller Present是否存在,如存在则读取slot stat寄存器判断slot中是否有设备,读取slot ctrl寄存器相应电源状态位,获取电源状态。

如果slot中没有设备,且slot处于上电状态,则关闭slot通知事件。且将slot下电。

(2)将ctrl结构赋值给dev的priv_data。调用init_slot初始化相应的slot:

为热插拔slot结构struct hotplug_slot *hotplug结构、热插拔槽信息结构struct hotplug_slot_info *info以及热插拔槽上的操作集合struct hotplug_slot_ops *ops申请内存,初始化热插拔操作函数:

ops->enable_slot = enable_slot;

        ops->disable_slot = disable_slot;

        ops->get_power_status = get_power_status;

        ops->get_adapter_status = get_adapter_status;

        ops->reset_slot = reset_slot;

根据slot能力寄存器是否支持MRL Sensor以及是否支持按钮指示灯,初始化相应ops:

if (MRL_SENS(ctrl))

                ops->get_latch_status = get_latch_status;

        if (ATTN_LED(ctrl)) {

                ops->get_attention_status = get_attention_status;

                ops->set_attention_status = set_attention_status;

        } else if (ctrl->pcie->port->hotplug_user_indicators) {

                ops->get_attention_status = pciehp_get_raw_indicator_status;

                ops->set_attention_status = pciehp_set_raw_indicator_status;

        }

初始化slot->hotplug_slot。

调用__pci_hp_initialize函数,根据上述获取的信息,为相应的物理槽创建相应的数据结构,并把创建的结构赋值给slot相应结构。

===============================

。。。。。分析相应slot的ops 。。。。。。

===============================

(2)初始化完上述的数据结构以后,调用pcie_init_notification使能相应的事件通知:

首先调用pciehp_request_irqe获取中断事件,如果pciehp_poll_mode为真,则开启内核线程来轮询热插拔事件。(Legcy mode)

调用request_threaded_irq函数申请中断,如下为这个函数的说明。

/* Installs the interrupt handler */

        retval = request_threaded_irq(irq, pciehp_isr, pciehp_ist,

                                      IRQF_SHARED, MY_NAME, ctrl);

int request_threaded_irq(unsigned int irqirq_handler_t handlerirq_handler_t thread_fn, unsigned long irqflagsconst char *devname, void *dev_id

IRQF_SHARED 共享中断时,dev_id不能为空,因为释放irq时要区分哪个共享中断
irq:中断号
handler:发生中断时首先要执行的硬中断处理函数,这个函数可以通过返回 IRQ_WAKE_THREADED唤醒中断线程,也可返回IRQ_HANDLE不执行中断线程
thread_fn : 中断线程,类似于中断下半部
后三个参数与request_irq中的一致

pciehp_isr中断处理函数:

(1) 检查设备当前状态是否处于D3_cold状态. D3hot(通常只称作“D3”)是设备的“软关闭”状态,在此状态下,总线扫描可以检测到设备,并且发送给设备的命令可能会导致它再次打开电源, 而在D3cold中,将切断所有电源,只保留少量电源以驱动设备的唤醒逻辑。

因此,在这里检测到如果处于D3cold状态,直接退出。

(2) 如果设备存在父设备,在该设备resume前要先resume父设备

若希望保持端口可访问,方法是在其父端口上保存一个运行时PM ref。如果父端口的IRQ线程被挂起,则将父线程的恢复延迟到IRQ线程。在此之前屏蔽中断。

(3) 读pcie slot status确认events状态。hotplug controller 监控各种events并把这些events上报给hotplug system driver.

(4) 这里需要关注这些events即可。Attention button pressed (Attention按键按下), power fault detected (电源错误), presence detect changed (在位状态变化), command completed (命令完成), data link layer state changed (链路状态改变).

读取设备的slot stat寄存器,根据slot stat寄存器各位获取当前设备的事件是哪类事件,如为电源错误事件,则将相应位清零,防止事件继续上报中断。如为命令完成通知事件,不会延迟到IRQ线程,因为它可能正在等待它们的到来。

所以整个isr流程主要的处理就是决定哪些events可以通过system interrupt上报给系统,然后唤醒内核线程,处理线程函数pciehp_ist

pciehp_ist中断处理线程(下半部)

首先调用pci_config_pm_runtime_get函数,增加父设备及设备引用计数,调用pm_runtime_barrier,很多RPM请求都是异步的,这些请求会挂到一个名称为“pm_wq”的工作队列上,这个函数的目的,就是清空这个队列,另外如果有resume请求,同步等待resume完成。如果设备处于D3cold状态,则需要恢复D3cold中的设备,因为配置寄存器仍然可以访问挂起的设备,但不能访问D3cold中的设备。

当中断发生时,热插拔端口是不可访问的,IRQ处理程序用来通知IRQ线程,要求IRQ线程在运行时将其父设备恢复到D0以访问热插拔端口之后重新运行IRQ处理程序。

synchronize_irq()用于等待PENDING状态的中断处理函数结束(中断处理包括硬中断的处理以及中断线程的处理)。

原子的获取ctrl->pending_events,开始判断事件类型:

a、当为Attention Button Pressed事件,

调用pciehp_handle_button_press函数,根据当前slot状态,设置相应的指示灯。

如果检测到当前槽位状态为POWEON, 就说明此时产生了一个hot-remove, 将状态设置为BLINKINGOFF, 表示pcie controller会等待5s后将该槽位下电。

如果检测到当前槽位状态为POWEOFF, 就说明此时需要热插,将状态设置为BLINKINGON, 表示pcie controller会等待5s后将该槽位上电。

如果检测到当前槽位状态已经处于BLINKINGON/OFF state, 说明此时需要取消上次的热插或热拔操作,将槽位的状态恢复成ON/OFF state.

b、当为Power Fault事件。

将power_fault_detected标志先置为1,表示电源异常不会重复处理,打开Attention指示灯,并将电源指示灯熄灭。

c、当为disable slot事件

DISABLE_SLOT主要用于响应用户通过sysfs或者attention button禁用槽位的请求,此事件的优先级要高于在位信号状态或者链路状态改变

pciehp_handle_disable_request

d、当发生在位信号改变或链路状态发生改变事件

如果pcie slot槽位处于上电状态,却产生了在位状态改变的event, 说明产生了暴力热拔操作, 此时直接将槽位下电。

如果链路状态正常并且pcie卡处于在位状态,进行热插的处理。调用pciehp_enable_slot->__pciehp_enable_slot函数,首先获取Slot Status的值。查看Presence Detect State位是否改变。查看是否存在MRL传感器以及读取slot ctrl寄存器获取电源控制状态。

如上述都满足,则调用board_added函数,首先判断是否存在电源控制能力寄存器,如存在调用pciehp_power_on_slot函数,写slot ctrl相应的位控制槽上电。写link ctrl Link Disable写0.

控制电源灯闪烁,检测link训练状态,且将link速率记录在bus->cur_bus_speed中。查看是否有电源错误。

调用pciehp_configure_device函数,首先检测槽中是否存在设备。存在则返回。

调用pci_scan_slot扫描pcie设备,调用如下代码完成热插拔桥的重新枚举和资源分配。

        for_each_pci_bridge(dev, parent)

        pci_hp_add_bridge(dev);

        pci_assign_unassigned_bridge_resources(bridge);

        pcie_bus_configure_settings(parent);

        pci_bus_add_devices(parent);

@available_buses:桥下设备可用的总线总数。在分配了最小的总线空间之后,剩余的总线将在支持hotplug的桥之间平均分配。

下面为一个热拔出的实现流程,热插和热拔流程类似

调用pcie_enable_notification函数,设置热插拔控制器相关寄存器位。始终启用link事件:link上和linkh不上分别作为热插拔和拔出处理。仅当“提示”按钮不存在时启用“presence信号检测”。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值