| 论坛注册| 加入收藏 | 设为首页| RSS
Google
您当前的位置:首页 > Linux频道 > Linux开发区 > 内核研究

Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制

时间:2007-10-23 10:01:56  来源:Linux联盟收集整理  作者:
PCI热插拔技术,可以有效避免由更换外设引起的服务器系统停机,对于提高服务器系统可用性和可扩展性意义重大。本文讨论了PCI Express热插拔所涉及的软件因素,并基于此,剖析了Linux 2.6.10内核下PCI Express 插槽热插拔子系统的关键实现机制。

一 相关技术与研究9J7Linux联盟

1997年,PCI SIG制定了第一个PCI热插拔规范,其中定义了支持热插拔所必需的平台、板卡和软件元素。PCI SIG推出了标准热插拔控制器规范(SHPC SPEC),其中明确了热插拔的标准使用模式和严格的寄存器组要求,并且允许操作系统提供商在平台特定的软件之外提供热插拔支持,逐步完成了热插拔标准制定工作,进入技术的全面推广阶段。 2002年以后,Intel把热插拔作为一种天然属性赋予新推出的PCI Express规范,PCI Express热插拔总结了五年来工业标准的经验,具有如下特点:9J7Linux联盟

  • 基于SHPC模式并对其进行了功能扩展;
  • PCI Express从设计上就把热插拔寄存器集成进入了其标准的性能寄存器组(而在SHPC 1.0中,热插拔寄存器是附加的);
  • 提供给操作系统一个统一的热插拔硬件寄存器接口,赋予了操作系统进行原生热插拔(绕过了传统基于BIOS的热插拔方法)的能力;
  • 通过在基本的体系机构层次定义热插拔必须的硬件要求,完善了一种标准的使用模式;
  • 提供了规格参数来保证OEM产品的低成本而高平台可靠性。

具有完整功能的PCI Express热插拔系统在平台硬件和固件支持之外,还必须有操作系统以及设备驱动程序的支持。9J7Linux联盟

在各大芯片厂商纷纷推出支持PCI热插拔的产品的同时,Microsoft,Novell,SCO等公司在他们相关的操作系统中也都包括了支持热插拔的技术, Novell NetWare 4.11&5和SCO UnixWare 7以及更新版本支持完整PCI热插拔(热替换和热添加)。Microsoft Windows NT 4.0利用Compaq 服务器支持盘(SSD) for NT 4.0,提供了PCI热替换支持,进入2000年后,Microsoft Windows 2000也内建了对PCI热插拔技术的全面软件支持。对于GNU/Linux,从2001年1月份的内核2.4版本开始,PCI 热插拔开始成为其标准特性之一,到2.6 版本,热插拔功能已经被整合进入核心设备模型。现在,几乎所有的Linux发行版本,包括RedHat, Debian和 United Linux,都对PCI 热插拔提供了良好支持,并分别有所扩展。BSD分支在这方面起步较晚,OpenBSD在2004年三月份的3.6版本中才出现了不含设备驱动的设备热插拔参考框架,而FreeBSD 到5.3版本为止,尚未提供对PCI 热插拔的支持。9J7Linux联盟

作为2002年出现的规范,各个通用操作系统对PCI Express的支持才刚刚起步。在微软公司的 Windows 2000, Windows XP, and Windows Server 2003中,PCI Express设备被当作PCI设备进行热插拔,其他PCI Express的高级功能可以由固件激活。在Windows Longhorn中,才提供对PCI Express高级特性的原生支持。GNU/Linux在内核版本2.6.9中开始专门提供对于PCI Express 热插拔的支持,中间历经软件架构的改动,逐渐发展为以内核版本2.6.10以及内核版本2.6.12下两种不同的PCI Express热插拔驱动架构。本文主要讨论2.6.10所采用的PCI Express热插拔驱动架构,并在最后给出2.6.12的新特性。9J7Linux联盟

9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
回页首
9J7Linux联盟
9J7Linux联盟

三 PCI Express 热插拔的软件支持9J7Linux联盟

根据规范,一个完整的 Native PCI Express 热插拔系统需要几方面的相互配合,分别为硬件元素、固件元素和软件元素。硬件元素是指主板总线系统的电气特性方面的支持,包括热插拔控制器(Hot-Plug Controller)、卡槽电源切换逻辑(Card Slot Power Switching Logic)、板卡重置逻辑(Card Reset Logic)、电源指示灯(Power Indicator)、提示按钮(Attention Button)和板卡存在检测引脚(Card Present Detect Pins)等等;固件元素是指主板BIOS必须对热插拔提供的支持,要实现Native PCI Express热插拔,固件必须提供OSHP方法或ACPI _OSC方法之一;软件元素是指操作系统操综合使用PCI Express 热插拔所必须提供的功能组件。9J7Linux联盟

软件元素9J7Linux联盟

为了操纵平台的硬件元素,提供PCI Express热插拔服务,我们必须实现表1所示的主要热插拔软件元素。9J7Linux联盟

9J7Linux联盟
9J7Linux联盟

PCI Express服务模型9J7Linux联盟

PCIE热插拔(PCIEHP)子系统中的标准热插拔系统驱动程序通过检查PCI Express性能数据结构中的插槽性能寄存器(Slot Capabilities register),来获取硬件的热插拔部件信息。这些寄存器所能反映的信息如下:9J7Linux联盟

  1. 插槽是否支持热插拔
  2. 设备是否支持不通知软件的突然拔出操作
  3. 提示灯、控制器等硬件元素是否存在

一旦软件完成了PCI Express设备热插拔功能的开启和配置工作,热插拔行为(例如移出或插入请求,电源故障)就可以向系统热插拔处理机制提交系统中断和电源管理事件。这种热插拔处理机制由操作系统独立提供,图1展示了PCI Express Native热插拔的服务模型,并展示了它与传统的基于ACPI的模型之间的区别。9J7Linux联盟

9J7Linux联盟
图1 PCI Express热插拔服务模型比较9J7Linux联盟
图1 PCI Express热插拔服务模型比较 9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
回页首
9J7Linux联盟
9J7Linux联盟

四Linux 2.6.10 PCIE 热插拔子系统代码分析9J7Linux联盟

热插拔框架9J7Linux联盟

为了提供PCI Express热插拔服务,Linux 2.6.10 PCIE热插拔(PCIEHP)子系统必须实现用户操作界面、热插拔服务程序和标准热插拔系统驱动等热插拔软件元素,并使软件的行为符合热插拔标准使用模式[4]。另外,一些特定的热插拔功能必须与支持热插拔的设备驱动结合在一起发挥作用。9J7Linux联盟

PCIEHP核内部分的主体是一个核心线程,其控制逻辑以模块的方式加载入内核,负责监控PCI Express总线上的热插拔事件,并做相关处理;核外部分是一个用户空间的脚本,从内核中调用,并根据内核传回的信息执行后续处理过程。9J7Linux联盟

1 热插拔驱动程序生命周期 9J7Linux联盟

从PCIEHP子系统启动,到子系统被卸载期间,PCIEHP完全接管系统中PCI Express插槽热插拔事件。9J7Linux联盟

PCIEHP子系统启动时,首先要开启用户态守护进程。然后初始化通知机制,开启PCI Express热插拔事件处理核心线程,为操作系统中各总线数据结构分别预初始化一个热插拔插槽列表。接着,根据内核编译时是否指定ACPI式资源管理,初始化设备资源管理方式。最后,根据设备标识,在系统中注册PCI Express热插拔驱动程序,并将其绑定到总线上所有可能挂载热插拔插槽的PCIE桥接设备,然后初始化对应的热插拔控制器,分配资源,开启定时的中断轮询机制。9J7Linux联盟

卸载PCIEHP子系统,首先释放热插拔控制器全局列表中每个控制器所占用的资源,释放热插拔插槽全局列表中每个插槽所占用的资源,终止通知机制的运行,结束PCI Express热插拔事件处理核心线程;接着,根据内核编译时是否指定ACPI式资源管理,释放相关设备占用的系统资源;然后,注销PCI Express热插拔驱动程序;在处理完当前热插拔事件后,终止核外守护进程。9J7Linux联盟

在PCIEHP加载后,为了在热插拔执行过程中追踪其状态变化,我们把热插拔插槽的状态抽象如下:9J7Linux联盟

  • 静态 (STATIC STATE ),9J7Linux联盟
    正常工作或者空闲的时段,
  • 开启前闪烁提示态(BLINKINGON STATE)9J7Linux联盟
    发出开启请求到确认之前的时段
  • 关闭前闪烁提示态 (BLINKINGOFF STATE)9J7Linux联盟
    发出关闭请求到确认之前的时段
  • 开启态 (POWERON STATE)9J7Linux联盟
    执行开启操作的时段
  • 关闭态(POWEROFF STATE)9J7Linux联盟
    执行关闭操作的时段

各个插槽状态之间的转换关系如图2所示:9J7Linux联盟

9J7Linux联盟
图2 插槽状态转换图9J7Linux联盟
图2 插槽状态转换图 9J7Linux联盟

2 用户控制脚本/sbin/hotplug和核内外通信机制 9J7Linux联盟

在内核热插拔处理完毕后,它会在核内调用一个用户态脚本hotplug,这个脚本将根据内核提供的信息进行后续处理工作。它是设备热插拔通告的用户空间部分,它接收内核传出的热插拔操作类型和环境变量,处理设备挂载和卸载操作。通常,hotplug会根据设备类型调用一个策略脚本,针对设备和系统当前参数进行后续的配置工作。例如,对于网卡,可能会调用脚本指定IP地址,网关和域名服务器等等,对于存储设备,可能会调用mount命令来加载它到文件系统内。9J7Linux联盟

内核传送给hotplug的信息包含热插拔操作类型(例如PCI),并且在一个环境变量中提供本次操作相关信息:9J7Linux联盟

  • 行为种类:添加或删除
  • 对象设备所属PCI 类、子类和编程接口
  • 对象制造商标志和设备标志
  • 对象总线地址、插槽地址和功能函数编号

核外的后续配置工作涉及如下文件:9J7Linux联盟

/etc/hotplug/pci.rc
/ect/hotplug/pci.Agent
/etc/rc.d/init.d/hotplug

在内核中,由kernel/kmod.c中的函数9J7Linux联盟

int call_usermodehelper (char *path, char **argv, char **envp, int wait)来开启用户态脚本/sbin/hotplug。在参数表中,path表示了所启动的核外应用程序的路径,argv是应用程序的参数表,envp是环境变量列表,wait则指出了是否同步等待应用程序执行完毕再返回执行结果的状态。9J7Linux联盟

3 PCIE 热插拔模块构成 9J7Linux联盟

为了使用PCI Express Native Hotplug,我们必须在编译的时候开启对应的功能模块。9J7Linux联盟

在内核配置中,PCIE Hotplug对应的开关为HOTPLUG_PCI_PCIE,它依赖于HOTPLUG_PCI。如果你的主板支持PCI Express Native Hotplug,可以选择Y;如果你只是想把这个驱动作为模块来编译,那么选择M,此模块叫做pciehp,在源代码\dirver\pci\hotplug\Kconfig文件中,你可以看到:9J7Linux联盟

config HOTPLUG_PCI_PCIE
	tristate "PCI Express Hotplug driver"
	depends on HOTPLUG_PCI
9J7Linux联盟

完整的pciehp模块功能涉及到如下几个文件pci_hotplug_core.c, pciehp_core.c,pciehp_ctrl.c,pciehp_pci.c pciehp_hpc.c,另外根据是否开启了ACPI,包含pciehprm_acpi.c 或者pciehprm_nonacpi.c,在源代码\dirver\pci\hotplug\Makefile文件中,你可以看到:9J7Linux联盟

pci_hotplug-objs	:=	pci_hotplug_core.o
pciehp-objs		:=	pciehp_core.o	\
				pciehp_ctrl.o	\
				pciehp_pci.o	\
				pciehp_hpc.o
ifdef CONFIG_ACPI_BUS
	pciehp-objs += pciehprm_acpi.o
else
	pciehp-objs += pciehprm_nonacpi.o
endif
9J7Linux联盟

代码的主要任务就是在所有支持热插拔的PCIE桥上加载热插拔驱动程序,监控热插拔事件,并根据类型,如是热插入事件、热拔出事件还是电源故障等分别予以处理。9J7Linux联盟

热插拔驱动的加载9J7Linux联盟

热插拔驱动程序的加载所进行的主要工作是开启并初始化PCIE热插拔的内核线程,这部分代码位于/driver/pci/hotplug/pciehp_core.c中。入口函数为:9J7Linux联盟

static int __init pcied_init(void)
#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
	pciehp_poll_mode = 1;
#endif
	retval = pcie_start_thread();
	if (retval)
		goto error_hpc_init;
	retval = pciehprm_init(PCI);
	if (!retval) {
		retval = pci_register_driver(&pcie_driver);
		dbg("pci_register_driver = %d\n", retval);
		info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
	}
	
9J7Linux联盟

pcied_init中所涉及的关键函数分析如下:9J7Linux联盟

retval = pcie_start_thread(); 9J7Linux联盟

初始化并开启通知机制:9J7Linux联盟

pciehp_event_start_thread()启动事件监控处理线程9J7Linux联盟
然后初始化slot列表,系统中每个bus给一个slot列表。9J7Linux联盟
struct pci_func *pciehp_slot_list[256]; 都设为NULL9J7Linux联盟

retval = pciehprm_init(PCI); 9J7Linux联盟

原型:int pciehprm_init(enum php_ctlr_type ctlr_type)9J7Linux联盟

初始化资源(区别两种情况:acpi和非acpi的)在非acpi的初始化方式下,调用空函数legacy_pciehprm_init_pci();在pcihprm_nonacpi.h中,定义了irq_info,irq_routing_table两个结构。在acpi初始化方式下,通过pciehprm_acpi_scan_pci()在acpi树下遍历搜寻PCI设备。不论acpi和非acpi的,都要求php_ctlr_type为PCI。9J7Linux联盟

retval = pci_register_driver(&pcie_driver); 9J7Linux联盟

注册并初始化PCI桥热插拔驱动程序模块。9J7Linux联盟

把设备驱动加入已注册设备驱动列表,即使在期间没有相应设备出现驱动程序仍然保持有效。9J7Linux联盟

	int count = 0;
	/* initialize common driver fields */
	
9J7Linux联盟

用来泛化之,可以把drv->driver看作为drv的基类信息9J7Linux联盟

	drv->driver.name = drv->name;
	drv->driver.bus = &pci_bus_type;
	drv->driver.probe = pci_device_probe;
	drv->driver.remove = pci_device_remove;
	drv->driver.kobj.ktype = &pci_driver_kobj_type;
	pci_init_dynids(&drv->dynids);
	count = driver_register(&drv->driver);
	
9J7Linux联盟

注意:这里是如何从基类drv->driver一般设备的驱动向子类drv这个pci设备的驱动逆向关联的--使用CONTAINER宏9J7Linux联盟

pcie_driver为PCIE驱动程序对象,定义在 pciehp_core.c中 9J7Linux联盟

	static struct pci_driver pcie_driver = {
	//驱动名称定义为"pciehp"
.name=	PCIE_MODULE_NAME, 
// id_table指定探测函数probe所应用的范围,这里在表中指定9J7Linux联盟
为所有的PCI桥设备 .id_table = pcied_pci_tbl, //probe为指定的设备探测函数 .probe = pcie_probe, }; static struct pci_device_id pcied_pci_tbl[] = { { //此处选择所有PCI桥 .class = ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), .class_mask = ~0, .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, },
9J7Linux联盟

设备探测pcie_probe: 9J7Linux联盟

static int pcie_probe
(struct pci_dev *pdev, const struct pci_device_id *ent)
in pcie-core.c
9J7Linux联盟

已经确定了pdev就是pcie_driver 所匹配的PCI桥设备,而且它在pcie_driver中所对应的设备特征号是*ent,就可以对其进行进一步的初始化和探测。9J7Linux联盟

具体行为如下:9J7Linux联盟

  • 绑定热插拔插槽
  • 设置了控制器及其状态
  • 注册中断处理函数
  • 读写配置头,然后分配资源,最后对插槽检测,挂接

热插拔事件的监控处理线程9J7Linux联盟

热插拔驱动程序对于热插拔事件的轮询和通知采用异步机制,对热插拔功能部件的操纵是通过读写相关寄存器组进行的。主要功能函数关系请参见图3:9J7Linux联盟

9J7Linux联盟
图3 插槽热插拔事件处理函数关系9J7Linux联盟
图3 插槽热插拔事件处理函数关系 9J7Linux联盟

图3中主要函数的功能介绍如下:9J7Linux联盟

A插槽事件监控线程 9J7Linux联盟

作为热插拔活动最直接的信息,插槽事件由硬件操作并置位相关寄存器组,系统软件可以通过定时轮询或者中断方式获取事件信息,执行对应的事件预处理函数。插槽事件如下:9J7Linux联盟

  • 热插拔命令到达
  • 插槽锁状态改变
  • 适配卡存在状态改变
  • 电源出现故障

php_ctlr->int_poll_timer.function = &int_poll_timeout 其中php_ctlr是热插拔控制器状态php_ctlr_state_s类型,它定义于pciehp_hpc.h中,记录当前热插拔控制器重要状态,被用作HPC(controller)的控制器句柄;热插拔控制器controller位于文件pciehp.h中,描述了PCIE热插拔控制器的特征;9J7Linux联盟

定时轮询函数原型如下:9J7Linux联盟

static void int_poll_timeout(unsigned long lphp_ctlr)9J7Linux联盟
其中调用pcie_isr( 0, (void *)php_ctlr, NULL );9J7Linux联盟
当最后一个参数是NULL时,采用polling机制。9J7Linux联盟
static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);9J7Linux联盟
轮询机制通过定期(2second,使用一个计时器)读取ctrller对应的状态寄存器,来获取事件,然后调用ctrl状态参量对应的事件处理函数。也就是按钮、电源、MRL等等事件处理函数,并分别调用event_semaphore来激活event_thread.9J7Linux联盟

B事件预处理函数 9J7Linux联盟

在插槽事件监控线程截获插槽事件后,它根据事件类型调用这组处理函数,执行完毕后,填写对应控制器上所挂接的事件队列,并激活睡眠等待的处理线程。可以激活睡眠中的处理线程的函数包括如下几个:9J7Linux联盟

pciehp_handle_attention_button :处理按钮事件9J7Linux联盟
pciehp_handle_switch_change:处理开关状态改变事件9J7Linux联盟
pciehp_handle_presence_change:处理存在性状态变化事件9J7Linux联盟
pciehp_handle_power_fault:处理电源故障事件9J7Linux联盟
pushbutton_helper_thread:按钮动作处理线程9J7Linux联盟

C热插拔事件处理核心线程event_thread 9J7Linux联盟

event_thread的处理过程如下:9J7Linux联盟
在一个无限循环中,阻塞等待插槽事件发生9J7Linux联盟
当线程被某一事件唤醒后,9J7Linux联盟
如果 热插拔请求已通过延时确认9J7Linux联盟
进入热插拔请求处理函数9J7Linux联盟
否则9J7Linux联盟
轮询热插拔控制器队列:9J7Linux联盟
把控制器作为参数传给插槽事件处理函数9J7Linux联盟
其中9J7Linux联盟

if (pushbutton_pending)
			pciehp_pushbutton_thread(pushbutton_pending);
		else if (surprise_rm_pending)
			pciehp_surprise_rm_thread(surprise_rm_pending);
9J7Linux联盟

前一个处理按钮事件,后一个处理突然拔出事件。9J7Linux联盟

参数pushbutton_pending是由如下函数提供的:9J7Linux联盟

static void pushbutton_helper_thread(unsigned long data)
{
         pushbutton_pending = data;
         up(&event_semaphore);
9J7Linux联盟

而这个函数又被作为定时task事件的行动部分,赋值给9J7Linux联盟

static void interrupt_event_handler(struct controller *ctrl)中的9J7Linux联盟
p_slot->task_event.function:9J7Linux联盟
函数:9J7Linux联盟
p_slot->task_event.function 9J7Linux联盟
= (void (*)(unsigned long)) pushbutton_helper_thread;9J7Linux联盟
参数:9J7Linux联盟
p_slot->task_event.data 9J7Linux联盟
= (unsigned long) p_slot;9J7Linux联盟

D插槽事件处理函数interrupt_event_handler 9J7Linux联盟

根据控制器信息,获取控制器对应插槽事件9J7Linux联盟
尚有事件等待处理,则执行以下内容:9J7Linux联盟

逐一查看控制器所挂接事件队列的每个成员(根据事件类型):9J7Linux联盟

1. 请求取消9J7Linux联盟
取消前五秒内触发的一次热插拔请求9J7Linux联盟

2. 请求触发9J7Linux联盟
触发一次热插拔操作:导致一个五秒钟的延时,如果五秒内请求没有被拒绝,则确认前一个热插拔请求9J7Linux联盟

3. 电源故障9J7Linux联盟
弹出提示信息9J7Linux联盟

4. 其他9J7Linux联盟
读取插槽的功能寄存器,更新状态信息。9J7Linux联盟

E热插拔请求处理函数pciehp_pushbutton_thread 9J7Linux联盟

一个定期运行的程序,处理当前插槽上阻塞的请求,根据请求类型:对插槽中的设备进行热移出(F)或者热添加操作(G)。9J7Linux联盟

F插槽热拔出设备pciehp_disable_slot 9J7Linux联盟

保证所除去的不是视频控制器9J7Linux联盟
卸载所除去的适配卡占用的系统资源,更新总线结构,关闭电源9J7Linux联盟
通知用户态守护进程9J7Linux联盟
更新插槽状态9J7Linux联盟

G插槽热添加设备pciehp_enable_slot 9J7Linux联盟

1. 执行适配卡添加的一系列相关操作: 失败恢复预处理,存在性检验、打开电源,检查link training状态,获取设备基本信息,配置设备,为设备建立相关数据结构,挂接到上级总线等。9J7Linux联盟

2. 为新添加的设备查找并挂接驱动程序。9J7Linux联盟

3. 特别地,对于桥接设备,把它挂接到上级总线后,还要继续对其下级总线进行扫描和挂接。9J7Linux联盟

4. 通知用户态守护进程。9J7Linux联盟

5. 更新插槽状态。9J7Linux联盟

9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
回页首
9J7Linux联盟
9J7Linux联盟

五 PCIE板卡热插拔的标准过程9J7Linux联盟

热插拔PCI板卡可以使用提示按钮或用户界面来进行,下面我们介绍使用用户界面来启动热插入和热拔出的操作过程,以及Fedora C4T2下所采用的方式。 9J7Linux联盟

设备的热插入9J7Linux联盟

1. 操作员安装卡,闭合插槽保护锁,保护锁感应器通知热插拔控制器把连接信号接通到插槽。9J7Linux联盟

2. 然后,操作员通知热插拔服务程序:卡已经被安装并可以激活。软件提示用户对此进行确认。9J7Linux联盟

3. 在操作员请求连接后,热插拔服务程序向控制着热插拔控制器的热插拔系统驱动程序下达命令,闪烁插槽的电源指示灯,提示操作员此时不可以拔动适配卡。9J7Linux联盟

4. 在热插拔软件对此请求进行确认期间内,电源指示灯继续闪烁。注意此时软件可能会拒绝这个安装请求(例如,安全策略此刻禁止插槽被激活)。另外,如果请求没有生效,软件拒绝请求并对热插拔控制器发出命令关闭电源指示灯。规范建议软件通过一条消息通知操作员请求被拒绝的原因。9J7Linux联盟

5. 如果请求被确认,热插拔服务程序对热插拔系统驱动发出请求,为插槽加电。9J7Linux联盟

6. 加电后,软件发出命令完全打开电源指示灯。 9J7Linux联盟

7. 当link training完成后,操作系统指示平台配置程序赋予适配卡必需的资源,来配置适配卡的功能。9J7Linux联盟

8. 操作系统为PCI Express设备中的功能寻找恰当的驱动程序,并加载之。9J7Linux联盟

9. 接着系统调用驱动程序的初始化入口,并执行驱动的初始化代码。这些代码完成设备的设置,并填写设备的PCI 配置命令寄存器的相关标志位来激活设备。9J7Linux联盟

热移出设备9J7Linux联盟

1. 操作员通过指定适配卡所在物理插槽号码来初始化移出请求。9J7Linux联盟

2. 软件弹出窗口要求操作员确认请求。注意,此时电源指示灯保持开启状态。9J7Linux联盟

3. 操作员确认请求后,热插拔服务程序向热插拔系统驱动发出请求,要求热插拔控制器闪烁电源指示灯。注意此时软件可能会拒绝这个移出请求(例如,适配卡目前正被关键系统功能所使用)。另外,如果请求没有被确认,软件将拒绝请求并对热插拔控制器发出命令,重新开启电源指示灯。规范建议软件通过一条消息通知操作员请求被拒绝的原因。9J7Linux联盟

4. 如果请求被确认,热插拔服务程序将命令适配卡的设备驱动保持静默,也就是说驱动一方面必须停止向适配卡发出请求,另一方面必须完成或者终止所有已经发出的请求,并禁止适配卡产生新的事务(包括中断)。9J7Linux联盟

5. 软件发出命令,通过在插槽所连接的根端口或交换端口中的链接控制寄存器禁掉适配卡的链接。这使得链接两侧的端口均被禁止。9J7Linux联盟

6. 软件指示热插拔控制器禁掉插槽。9J7Linux联盟

7. 成功切断电源后,软件发出关闭电源指示灯命令。指示灯熄灭后,操作员可以开始安全地从插槽移出适配卡。打开插槽安全锁,热插拔控制器从插槽上撤除所有的信号(例如SMBus 和Vaux),此时卡可以被移出。9J7Linux联盟

8. 操作系统释放内存空间,I/O空间,中断线等曾经属于该设备的系统资源。9J7Linux联盟

Fedora下所采用热插拔实现的方式9J7Linux联盟

如果在最近一次编译中选择了PCI Express 热插拔功能,而且驱动是以模块方式存在,那么,可以在命令行下键入以下内容:9J7Linux联盟

modprobe pciehp9J7Linux联盟

如果驱动成功,则可以在/sys/bus/pci/slots/下面发现以可热插拔插槽编号命名的目录,进入相关目录,可以进行下一步操作。9J7Linux联盟

echo 1 >power开启某个插槽上的电源 ,进行热插入9J7Linux联盟

echo 0 >power关闭某个插槽上的电源,执行热拔出9J7Linux联盟

若不能加载pciehp驱动,一般是由于硬件不支持或者固件缺少OSHP方法或ACPI _OSC方法之一。9J7Linux联盟

9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
回页首
9J7Linux联盟
9J7Linux联盟

六 linux2.6.12中PCIE驱动模型的变化9J7Linux联盟

在linux2.6.10中,Linux驱动程序模型要求物理设备被单独的驱动程序独占访问。 PCI Express端口是一个拥有许多独立功能的PCI-PCI桥设备,作为一个简洁的方案,每个功能要分别实现其自己的驱动程序,但是这样造成了多个驱动程序在唯一的PCI-PCI桥设备中出现竞争的状况。也就是说,虽然PCI Express提供了如Power Management (PME)、 Advanced Error Reporting (AER)、 Hot-Plug (HP) 和Virtual Channel (VC) access等多种功能,但是如果某个PCI Express端口的native hotplug 驱动程序加载后,它就会独占这个PCI-PCI桥的端口,内核就不能再于其上加载其他功能的驱动程序了。为解决这个问题,在Linux内核版本2.6.12中,PCI Express的热插拔又有所改变,提出了PCI Express 端口总线驱动程序(PCI Express Port Bus Driver)的概念。9J7Linux联盟

在实现上,PCI Express 端口总线驱动程序管理主板上的所有PCI Express 端口,并且把所有提供的服务请求发送到对应的服务驱动程序上。其优点概括如下:9J7Linux联盟

  • 允许多个服务驱动程序在一个PCI-PCI桥端口设备上同步运行。
  • 允许各个服务驱动程序相互不受干扰地独立实现。
  • 允许一个服务驱动程序在多个PCI-PCI桥端口设备上运行。
  • 管理PCI-PCI桥端口设备资源并分发它们到发出请求的服务驱动程序。

例如,在注册热插拔驱动程序时,不再使用pci_register_driver直接向系统注册,而是使用int pcie_port_service_register(struct pcie_port_service_driver *new) 向端口总线驱动程序注册;在注销热插拔驱动程序时,不再使用pci_unregister_driver直接向系统注销,而是使用void pcie_port_service_unregister(struct pcie_port_service_driver *new)来向端口总线驱动程序注销;而端口总线驱动程序是直接注册注销到系统的。9J7Linux联盟

目前,PCI Express 端口总线驱动程序模型还在发展演变中。9J7Linux联盟

9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
9J7Linux联盟
回页首
9J7Linux联盟
9J7Linux联盟

七 评估与总结9J7Linux联盟

根据可用性理论,系统的可用度可以使用下列公式来计算:9J7Linux联盟

9J7Linux联盟
9J7Linux联盟

在高负荷运转的服务器上,商用可靠性的元件的故障更换并非小概率事件,对于更换故障元件和升级配件这样的事件,没有热插拔支持的系统必须停机断电进行处理,而具备热插拔支持的系统则仅仅需要很少的软件切换和拔插时间开销。从上面的公式我们可以看出,MTTR值越小,系统的可用性就越高。我们定义了一个比例因子V,V= MTTRnoHP/MTTRHP,根据业界经验,V的取值一般在10-100之间。描述可用性的一种常用的方法是使用"9"。如三个 9 表示 99.9% 的可用性,它表示一年大约有 8.5 小时的服务中断期。四个 9 (99.99%) 是更高一级的可用性,表示一年大约有 1 小时的服务中断期。根据可用度公式计算,在单个元件可靠度不变的情况下,Linux操作系统对PCI Express热插拔的支持,可以使服务器系统的外设相关可用性跃升一个等级(1个9),同时,PCI Express热插拔技术使得在线更换和升级PCI Express外设板卡成为可能,这使系统获得了良好的可扩展性。9J7Linux联盟

综上所述,本文讨论了PCI Express热插拔所涉及的软件因素,分析了linux2.6.10的PCI Express插槽热插拔功能PCIEHP子系统,并对热插拔支持在提高服务器系统外设相关可用性的作用进行了定量的分析。为了继续提高操作系统可用性和可扩展性支持能力,Linux PCI Express hotplug以下方面还有待发展:继续完善热插拔架构的开放性,以提供完整统一的接口供驱动开发人员编写其他设备的热插拔支持模块;在插槽热插拔之外,提供对Server IO Module(SIOM)热插拔的支持;完善热替换和热升级技术。这些问题都是非常具有挑战性的。 9J7Linux联盟

9J7Linux联盟
9J7Linux联盟

参考资料 9J7Linux联盟

  1. PCI Express Base Specification Revision 1.0
  2. Linux Device Driver III edition O'Reilly出版社 2005
  3. The Compaq PCI Hotplug Driver for Linux
  4. PCI Express System Architecture Addison-Wesley 出版社 Sep 04, 2003
  5. The PCI Express Port Bus Driver Guide HOWTO Tom L Nguyen tom.l.nguyen@intel.com
  6. Introduction to PCI Express A Hardware and Software Developer's Guide Adam H. Wilen Justin
  7. P. Schade Ron Thornburg
  8. www.sourceforge.org
  9. www.openbsd.org
  10. www.kernel.org
来顶一下
近回首页
返回首页
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表
相关文章
    无相关信息
栏目更新
栏目热门