Linux的电源管理架构_第1页
Linux的电源管理架构_第2页
Linux的电源管理架构_第3页
Linux的电源管理架构_第4页
Linux的电源管理架构_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Linux的电源管理架构Linux的源代码里,大部分都属于设备驱动程序的代码,因此,大多数电源管理(PM)的 代码也是存在于驱动程序当中。 很多驱动程序可能只做了少量的工作, 另外一些,例如使用 电池供电的硬件平台(移动电话等)则会在电源管理上做了大量的工作。这份文档对驱动程序如何与系统的电源管理部分交互做了一个大概的描述,尤其是关联到驱动程序核心中的模型和接口的共享,建议从事驱动程序相关领域的人通过本文档可以了解相关的背景知识。设备电源管理的两种模型驱动程序可以使用其中一种模型来使设备进入低功耗状态:1.系统睡眠模型:驱动程序作为一部分,跟随系统级别的低功耗状态,就像suspend ”(也叫

2、做suspend-to-RAM),或者对于有硬盘的系统,可以进入hibernation ”(也叫做suspend-to-disk )。这种情况下,驱动程序,总线,设备类驱动一起,通过各种特定于设备的suspend和resume方法,清晰地关闭硬件设备和各个软件子系统,然后在数据不被丢失的情况下重新激活硬件设备。有些驱动程序可以管理硬件的唤醒事件,这些事件可以让系统离开低功耗状态。这一特性可以通过相应的/sys/devices/ - /power /wakeup文件来开启和关闭(对于Ethernet驱动程 序,ethtool通过ioctl接口达到同样的目的);使能该功能可能会导致额外的功耗,但他

3、让整个系统有更多的机会进入低功耗状态。2. Runtime电源管理模型:这种模型允许设备在系统运行阶段进入低功耗状态,原则上,他可以独立于其他的电源管理活动。不过,通常设备之间不能单独进行控制(例如,父设备不能 进入suspend,除非他 的所有子设备已经进入suspend状态)。此外,依据不同的总线类型,可能必须做出一些 特别的操作来达到目的。如果设备在系统运行阶段进入了低功耗状态,在系统级别的电源状态迁移时(suspend或hibernation)就必须做出特别的处理。正因为这个原因, 不仅仅设备驱动程序本身,相应的子系统(bus type,device type,deviceclass

4、)驱动程序和电源管理核心也会被卷入到rumtime电源管理的工作中来。比如当系统睡眠时,以上的各模块必须互相合作来实现各种多样的suspend和resume方法,以便让硬件进入低功耗状态,唤醒后继续提供服务而不丢失数据。对于低功耗状态的定义,我们没有太多可以说的,因为他们通常特定于系统,甚至特定于某 个设备。如果在系统运行状态,足够多的设备进入了低功耗状态,这时的效果其实和进入了系统级别的低功耗状态非常相像。这样一些驱动程序可以利用rumtime电源管理让系统进入一种类似深度省电的状态。大多数进入suspend状态的设备会停止所有的I/O操作:不会有DMA或者IRQ请求(需要唤醒系统的除外),

5、不会有数据的读写,不再接受上层驱动的请求。这对于不同的总线和平台会有不同的要求。关于硬件唤醒事件的一些例子:由RTC发起的闹钟,网络数据包的到达,键盘或者鼠标的活动,媒体的插入或移除(PCMCIA,MMC/SD,USB,等等)。进入系统睡眠状态的接口内核为各个子系统(bus type,device type, device class )和驱动程序提供了相应的编程接口,以便它们参与它们所关心的设备的电源管理。这些接口覆盖了系统级别的睡眠和runtime级别的管理。设备电源管理操作子系统和驱动程序的设备电源管理操作,都定义在dev_pm_ops结构中:1 struct dev_pm_ops 23

6、 int (* prepare )( struct device * dev );45 void ( * complete )( struct device * dev );67 int (* suspend )( struct device * dev );89 int (* resume )( structdevice* dev );1011int (* freeze )( structdevice* dev );12int (* thaw )( struct device * dev );37 ;这个结构在include/linux/pm.h中定义,它们的作用将会在接下来进行描述。现在,

7、我们只要记住,最后三个方法是专门用于rumtime pm的,其他的则用于系统级别的电源状态迁移。某些子系统中,依然存在所谓“过时的”或“传统的”电源管理操作接口,这种方式不会使用到dev_pm_ops结构,而且只适用于系统级别的电源管理方法,这边文章里将不会对它 进行说明,如果要了解的话请直接查看内核的源代码。子系统级别(Subsystem-Level)方法131415161718192021222324252627282930313233343536intintintintintintintint(* poweroff )( struct device*dev );(* restore )(

8、 struct device * dev );(* suspend_noirq(* resume_noirq(* freeze_noirq)(struct device)(struct device* dev );* dev );)(struct device * dev );(* thaw_noirq )( struct device(* poweroff_noirq(* restore_noirq(* runtime_suspend(* runtime_resume(* runtime_idle* dev );)(struct device * dev );)(struct device

9、* dev );)(struct device * dev );)(struct device * dev );)(struct device * dev );设备进入suspend和resume的关键方法在bus_type结构、device_type结构和class结构的pm成员中,他是一个dev_pm_ops结构的指针。多数情况下,这些都是那些具体总线的体系结构(例如PCI或USB或某个设备类别和设备类)的维护者们来关注的部分。总线驱动会适当地实现这些方法以供硬件和驱动程序使用它们;因为PCI和USB有不同的工作方式。只有少数人会编写subsystem-level的驱动程序;大多数的设备驱

10、动程序是建立在各种特定总线架构的代码之上。有关这些调用,稍后会进行更详尽的描述;它们将会顺着父子形式的设备模型树,一个设备一个设备地被调用。/sys/devices/ - /power/wakeup files设备模型中的所有设备都有两个标志来控制唤醒事件(可使得设备或系统退出低功耗状态)设两个标志位由总线或者设备驱动用device_set_wakeup_capable()和device_set_wakeup_enable()来初始化,它们在include/linux/pm_wakeup.h中定义。can_wakeup”标志表示设备(或驱动)物理上支持唤醒事件,device_set_wakeu

11、p_capable()函数会影响该标 志。should_wakeup标志控制设备是否应该尝试启用他的唤醒机制。device_set_wakeup_enable()会影响该标志。大部分的驱动程序不会主动修改它们的值。大多数设备的should_wakeup的初始值都被设为false ,也有例外,比如电源键、键盘和由ethtool设置了wake-on-LAN功能的网卡。设备是否有能力发出唤醒事件是一个硬件的问题,内核只是负责持续地跟踪这些事件的发生。另外一方面,一个有唤醒能力的设备是否应该发起唤醒事件则是一个策略问题,它是由用户空间通过sysfs的属性文件(power/wakeup)进行管理的。用户

12、空间可以写入enabled ”或disabled”来设置或清除shoule_wakeup标志,相应地,读取该文件时,如果can_wakeup标志是true则返回对应的字符串,如果can_wakeup是false ,则返回一个空字符串,以此来表明设备不支持唤醒事件。(需要注意的是,尽管返回空字符串,该文件的写入依然会影响should_wakeup标志)只有当这两个标志都为true时,device_may_wakeup()函数才会返回true。当系统迁移到睡眠状态时,驱动程序应该在让设备进入低功耗状态前通过这一函数检查,确定是否启用唤醒机制。不过,在rumtime电源管理模式下,不管设备和驱动程序

13、是否都支持,也不管should_wakeup标志是否设置,唤醒事件都会被使能。/sys/devices/ - /power/control files设备模型中的每个设备都有一个标志位来控制它是否属于runtime电源管理模式。这个叫runtime_auto的标志由bus type(或其他子系统)用pm_rumtime_allow()或者是pm_rumtime_forbid()来初始化。默认值是允许rumtimepm的。用户空间可以通过向设备的sysfs文件power/control写入on ”或者auto ”来修改该标志位。写入auto”相当于调用了pm_rumtime_allow(),允许

14、设备由驱动程序进行rumtimepm。写入on ”相当于调用pm_rumtime_forbid(),标志位被清除,设备将会从低功耗状态返回全功率状态,并且阻止设备进行runtime电源管理。用户空间也可以读取该文件来检查runtime_auto的当前值。设备的runtime_auto标志不会影响系统级别电源状态的迁移。特别注意的是,尽管runtime_auto标志被清除,当系统级别的电源状态迁移到睡眠状态时,设备也会被带入低功耗状态。关于runtime电源管理架构的更多信息,请参看DocumentationZpowerZruntime_pm.txt调用驱动程序进入或退出系统睡眠状态当系统进入睡

15、眠状态,系统会要求设备驱动程序让设备进入兼容于目标系统的一种状态来挂起(suspend )设备。这通常是某种off”状态。具体情况都是特定于各系统的。另外,可唤醒的设备一般会保持部分功能以便适当的时候可以唤醒系统。当系统退出低功耗状态时,设备驱动程序被要求恢复(resume )设备让他进入全电源状态。suspend和resume动作总是一起发生的,两者都可分为多个不同的阶段。对于相对简单的驱动程序,suspend可能在suspend_noirq阶段使用上层的类代码来停止 设备并尽可能让它们进入off”状态。唤醒时,相对应的resume调用会重新初始化硬件,然后重新激活他们的IZO活动。对电源有

16、特别需求的驱动程序可能会让设备做出必要的准备,以便之后可以产生唤醒事件。保证回调的顺序当设备进入suspend或resume时,因为设备之间具备一定的桥接关系,为了确保能够正确地访问它们,suspend时会在设备数中按照自底向上的顺序进行,而resume时则是按 照自顶向下的顺序进行。设备在设备数中的顺序决定于设备注册的顺序:子设备永远不能先于父设备进行注册、探测或resume;也不能在父设备之后进行移除或挂起。具体的策略就是设备数应该和硬件的总线拓扑结构相吻合。特别是,这就意味着当父设备正在进行挂起动作(例如,已经被pm的核心选为下一个将要被挂起的设备)、或者已经挂 起的情况下,注册子设备就

17、会失败。设备驱动程序必须正确地处理这种情况。系统电源管理中的各个阶段suspend和resume是分阶段完成的。Standby、Sleep (suspend-to-RAM )和hibernation (suspend-to-disk )会使用到不同的阶段。在进入下一个阶段之前,都需要为每个设备调用属于本阶段的回调函数。不是所有的总线和设备类都会支持所有这些回调,也不是所有的驱动程序都要使用这些回调。有些阶段需要冻结进程后,解冻进程前执行。 此外,*_noirq阶段需 要在IRQ被关闭的情况下执行(除非他们被IRQ_WAKEUP标记)。多数阶段使用bus、type和class的回调(也就是定义在

18、dev-bus-pm , dev-type-pm和dev-class-pm中)。不过prepare和complete阶段是个例外,他们仅仅使用了bus的回调。当一个阶段中有多个回调要执行时,按照以下顺序调用,suspend时: , resume时:。比如, 在suspend时将会执行以下 调用顺序:dev-class-pm.suspend(dev);dev-type-pm.suspend(dev);dev-bus-pm.suspend(dev);相反,在resume阶段,移至下一个设备之前,pm核心在当前设备按以下回调进行:dev-bus-pm.resume(dev);dev-type-pm.

19、resume(dev);dev-class-pm.resume(dev);这些回调可以反过来通过dev-driver-pm来调用设备或驱动特定的方法,但这不是必需的。系统挂起(suspend )当系统进入standby或sleep状态时,需要经历以下阶段:prepare , suspend , suspend_noirq。1. prepare阶段主要是通过阻止新设备注册来防止竟态的发生;如果此时要注册子设备,PM的核心将会不知道一个设备的所有子设备已经被suspend。(相反,设备可以在任何时刻被注销。)不像suspend其他的阶段,prepare阶段设备树会自顶向下进行扫描。prepare阶

20、段只使用了bus的回调。回调返回后,该设备的下面将不可以注册新的子设备。回调方法也会让设备或驱动为将要到来的系统电源状态迁移做出准备,但它不应该让设备进入低功耗状态。2. suspend阶段由suspend回调实现,它停止设备的一切I/O操作。它同时也可以保存设备的寄存器,依据设备所属的总线类型,让设备进入合适的低功耗状态,同时可以使能唤醒事件。3. suspend_noirq阶段发生在IRQ被禁止之后,这意味着该回调运行期间,驱动程序的中断处理代码不会被调用。回调方法可以保存上一阶段没有保存的寄存器并最终让设备进入相应的低功耗状态。大多数子系统(subsystem )和驱动程序不需要实现这一

21、回调。不过,某些允许设备共享中断向量的总线类型,例如PCI,通常需要这一回调;否则,当本设备已经进入低功耗时另一 个与他共享中断的设备感知中断的发生,驱动程序将会发生错误。这些阶段结束后,驱动程序必须停止所有的I/O事务(DMA , IRQs),保存足够的状态信息以便它们能被重新初始化或回复之前的状态(按应将的需要而定),然后让设备进入低功耗状态。很多平台上,它们会关闭某些时钟;有时还会关闭电源或者是降低电压。(支持rumtime pm的驱动可能已经提前完成部分或所有的步骤。)如果device_may_wakeup(dev)返回true,设备准备好产生硬件唤醒信号以便触发一个系统唤醒事件来唤醒

22、已经进入睡眠状态的系统。例如,enable_irq_wakeup()可以让一个连接到某个开关或外部硬件的GPIO被捕捉,pci_enable_wake()则响应类似PCI PME等信号。只要这些回调中的一个返回错误,系统不会进入所述的低功耗状态,而是由pm的核心对已经suspend的设备发起resume动作进行回退。退出系统挂起(resume )当系统退出standby或sleep状态时,需要经历以下阶段:resume_noirq , resume , complete。1. resume_noirq回调方法应该执行所有在中断处理程序被调用前的必须动作。这通常意味着撤销suspend_noir

23、q阶段所做的动作。如果总线类型允许共享中断向量,例如PCI,该回调方法应该使设备和驱动能够识别自身是否是中断源,如果是,还要能正确地处理。例如,对于PCI总线,bus-pm.resume_noirq()让设备进入全电源状态(PCI中称作D0 ),并回复设备的标准配置寄存器。然后,调用设备驱动程序的-pm.resume_noirq()方法来执行特定于设备的动作。2. resume回调方法让设备回到他的工作状态,以便它能执行正常的I/O。这通常等同于执行suspend阶段的撤销工作。3. complete阶段仅仅使用bus的回调。该方法应该撤销prepare阶段所做出的动作。不 过请注意,新设备可

24、能在resume回调返回后立刻被注册,而不必等到complete阶段完成。这些阶段结束后, 驱动应该和suspend之前一样:I/O能通过DMA或IRQs执行,相应的时钟被打开。尽管在系统睡眠之前,设备因为runtime pm已经处于低功耗状态之下,在这之后设备还是应该回到全电源状态。有很多原因说明为什么要这样做,详细的讨论请参 考:Documentation/power/runtime_pm.txt。不过,到这以后,具体还是会特定于平台的。例如,一些系统支持多种run”状态,resume后的模式可能不同于suspend之前。可能是某些时钟或电源的改变,这些都会很容易影响 到驱动程序如何工作。

25、驱动程序需要能够处理在suspend回调被调用后硬件被复位的情况,例如需要彻底地重新初始化。这可能是最困难的部分,实现细节可能会受到NDA等文档和chip errata的保护。最简单的情况是硬件的状态自suspend被执行后没有改变过,单这是不能保证的(实际上,这通常都不成立)。不管物理上是否可能,驱动程序也要准备被知会系统power-down期间设备被移除。在Linux中,PCMCIA , MMC , USB, Firewire , SCSI甚至IDE都是可移除的例子。具体的关于驱动程序如何被知会,和处理这种移除事件的工作是特定于总线的,而且通常有单独的线程来处理。进入Hibernation

26、省略.退出Hibernation省略.系统设备系统设备(sysdevs )遵循稍微不同的API,它们可以在以下文件中找到:include/linux/sysdev.hdrivers/base/sys.c系统设备要在中断关闭的情况下进行suspend,并且要在其他设备被挂起之后执行,唤醒时,它们会先于其他设备被resume,当然也是在关中断的情况下。这些动作都特别的”sysdev_driver”阶段发生,该阶段仅会对系统设备起作用。因仕匕,在suspend_noirq (freeze_noirq , poweroff_noirq)阶段之后, 当启动(non-boot )的CPUs都被关闭而且剩下

27、的CPU的IRQs也被关闭的情况下,这时候就会启动sysdev_driver.suspend阶段,接下来系统进入睡眠状态(对于hibernation是系统映像被创建)。resume期间的顺序就是:sysdev_driver.resume阶段执行,开启启动用CPU的IRQ,打开其他非启动CPU,然后开始resume_noirq阶段。实际进入和退出系统级别低功耗状态的代码有时候会调用一些只有boot firmware (bios ?bootloader?)才知道的硬件操作,然后保留CPU运行某一软件(从RAM或者FLASH中)来监控系统和管理唤醒序列。设备低功耗(suspend)状态设备的低功耗状

28、态并没有标准可言。某个设备可以只处理”on ”和”off ”,但另一个设备可能支持一打不同版本的”on”(多少个引擎被激活?),加上一个可以比彻底”off”更快地回到”on”的状态。一些总线对不同的suspend状态定义了一些规则。PCI可以给出一个例子来:suspend的 序列完成后,一个非传统(non-legacy )德尔PCI设备不可以执行DMA或发出IRQs ,而且唤醒事件要通过PME#总线信号发出。还定义了几个PCI标准的设备状态,其中一些状态可以只是作为选项。相反,集成度较高的SOC处理器经常使用IRQs作为唤醒源(因此驱动要调用enable_irq_wake(),而且可以用DMA的完成中断作为唤醒事件(有时DMA能保持激活,只是CPU和一些外设进入睡眠)。这里有些细节可以是特定于平台的。在某些睡眠状态下,系统可以有部分设备保持激活,例如系统轻度睡眠时,LCD显示器会使用DMA继续进行刷 新,frame buffer甚至可能有DSP或者另外的非Linux的CPU来刷新,而运行

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论