Linux 系统中的电源管理

作者:Srivatsa Vaddagiri

电源管理 (PM) 软件是电池供电系统(如 PDA 和笔记本电脑)中的关键组件,因为它有助于在系统不活动时节省电量。 举个简单的例子,当系统不活动一段时间后,可以通过关闭显示器来节省电量。 以这种方式节省电量可以延长电池寿命,因此人们可以在必须重新充电之前工作更长时间。

硬件支持对于电源管理工作至关重要,而软件则智能地运用这种支持。 硬件中可用的电源管理支持程度因设备而异。 有些设备(例如显示器)仅提供两种电源状态:开启和关闭。 其他设备(如 SA1110 CPU)可能支持更复杂的节能功能,包括频率调整。

考虑到需要将几个不交互的子系统整合到一套统一的指南下,在任何系统中实施电源管理都是一项复杂的任务。 本文解释了电源管理在 Linux (2.4.x) 中是如何工作的,以及如何在基于 APM 标准的电池供电系统中,在设备驱动程序和应用程序级别上实施电源管理。

两种电源管理标准

计算机系统的电源管理已经发展多年,并且存在多个标准。 其中两个流行的标准是高级电源管理 (APM) 和高级配置和电源接口 (ACPI)。 APM 是微软和英特尔提出的系统电源管理标准,它由一个或多个软件层组成,以支持电源管理。 它标准化了这些层之间的信息流。 在 APM 模型中,BIOS 起着关键作用。 ACPI 是两项技术中较新的一项,它是东芝、英特尔和微软为定义电源管理标准而制定的规范。 ACPI 允许更智能的电源管理,因为它更多地由操作系统而不是 BIOS 管理。 尽管这两种标准在基于 x86 的系统中更受欢迎,但在其他架构中也可以实现它们。

电源管理实施

在实施电源管理之前,重要的是要了解可用于节能的硬件支持。 电源管理软件的重要目标之一是使所有设备尽可能长时间地保持在低功耗状态。

实施电源管理的一种可能方法是首先定义一个电源状态转换图。 这定义了系统的几种电源状态,并定义了控制状态转换的规则和事件。

例如,考虑一个具有以下设备的 PDA:Intel SA1110 CPU、实时时钟、DRAM、闪存、LCD、前灯、UART、音频编解码器、触摸屏、按键和电源按钮。 Intel SA1110 CPU 支持多种节能功能,包括频率调整,其中核心时钟频率可以通过软件配置。 降低时钟频率会降低 CPU 的功耗,但代价是降低 CPU 速度。 该 CPU 还支持多种运行模式

  • 运行模式:SA1110 执行代码时的正常运行状态。 所有电源都已启用,所有时钟都在运行,并且每个片上资源都处于工作状态。

  • 空闲模式:允许软件在 CPU 不使用时停止 CPU。 在此模式下,CPU 时钟停止,从而节省一些电量。 所有其他片上资源都处于活动状态。 当中断发生时,CPU 会被重新激活。

  • 睡眠模式:提供最大的节能效果,因此可用功能级别最低。 在此模式下,大部分处理器的电源被关闭。 一些预编程的事件(例如按下电源按钮)会将 CPU 从此模式唤醒。

如您所见,软件负责将 CPU 转换为空闲模式或睡眠模式。

在这样的 PDA 中,DRAM 单元通常由 CPU 内部的内存控制器逻辑定期刷新。 然而,在睡眠状态下,CPU 的大部分被关闭,这导致 DRAM 单元没有被刷新,进而导致 DRAM 中的数据丢失。 为了避免这种损失,大多数 DRAM 支持一种称为自刷新的模式,其中 DRAM 本身负责刷新其单元。 在这种情况下,软件可以在将 CPU 转换为睡眠模式之前,通过写入一些控制寄存器来使 DRAM 进入自刷新模式,从而保留 DRAM 内容。

此 PDA 中最耗电设备可能是 CPU、DRAM 和显示器背光。 因此,应尽可能长时间地使它们保持在低功耗状态。

Power Management in Linux-Based Systems

图 1. 电源状态转换图

图 1 显示了此 PDA 可能的电源状态转换图。 以下是电源状态的简要说明

  • 运行状态:系统在重新启动时进入此默认状态。 在此状态下,功耗最大,因为所有设备都已开启或处于活动状态。

  • 待机状态:系统由于不活动而进入此状态。 LCD 和显示器背光关闭,并且 CPU 时钟速度降低以节省一些电量。

  • 睡眠状态:系统由于持续不活动而进入此状态。 通过将 CPU 置于睡眠模式来积极地节省电量,这反过来会关闭大多数设备的电源。 然而,DRAM 被置于自刷新模式,以在系统睡眠时保持机器状态(加载到内存中的系统和应用程序文本/数据)。 当预编程的事件发生时,系统从睡眠状态唤醒。 当它唤醒时,它转换到运行状态,并且机器状态被恢复。

  • 关机状态:系统在发出关机命令时进入此状态。 系统在从此状态退出时重新启动。 这意味着没有必要在 DRAM 中保留机器状态,因此可以关闭 DRAM 的电源。 关机状态然后代表所有状态中最低的功耗状态。

实时时钟在所有电源状态下都保持开启,以保留系统时间。

从该图中可以清楚地看出,检测不活动状态并将设备置于低功耗状态构成了电源管理软件的核心。

Linux 和电源管理

电源管理软件与设备驱动程序和应用程序关联地管理状态转换。 它在发生时通知所有 PM 事件,包括待机转换、睡眠转换和电池电量不足。 这允许软件在不安全的情况下否决某些状态转换。

设备驱动程序通常负责在将设备置于低功耗状态之前保存设备状态,并在系统变为活动状态时恢复设备状态。

通常,应用程序不参与电源管理状态转换。 少数直接处理某些设备的专用应用程序可能希望参与。 本节解释设备驱动程序需要做什么才能参与电源管理

  • pm_dev 结构:Linux 内核中的 PM 子系统在 pm_dev 结构中维护有关每个已注册驱动程序的一些信息。 维护此信息允许它将 PM 事件通知所有已注册的驱动程序。

  • pm_register:设备驱动程序必须首先向 PM 子系统注册自己,然后才能参与电源管理。 它们通过调用 pm_register 来完成此操作

    struct pm_dev *pm_register(pm_dev_t type, unsigned
    long id, pm_callback cbackfn);
    

    其中type是由驱动程序管理的设备类型,id是设备 ID,并且cbackfn是指向设备驱动程序中某个函数的指针。 这被称为驱动程序的回调函数。

linux/pm.h 文件定义了驱动程序可以使用的各种类型和 ID。 如果成功,pm_register 返回指向 pm_dev 类型结构的指针。 每当发生 PM 事件时,PM 子系统都会调用驱动程序的回调函数。 以下参数传递给该函数

  • dev:指向 pm_dev 结构的指针,该结构表示设备; 与 pm_register 返回的指针相同。

  • event:标识 PM 事件类型。 可能的事件是 PM_STANDBY,表示系统将进入待机状态; PM_SUSPEND,表示系统将进入挂起状态; 和 PM_RESUME,表示系统正在恢复(从待机或睡眠状态恢复)。 根据实现,可以提供更多事件。

  • data:与请求关联的数据(如果有)。

每个设备驱动程序都应该根据 PM 事件类型执行一些处理。 例如,在 PM_SUSPEND 事件中,LCD 驱动程序应该保存设备状态,然后关闭 LCD。 如果是 PM_RESUME 事件,LCD 驱动程序应该打开 LCD 并从保存的状态恢复其状态。

回调函数应返回一个整数值。 返回零值表示驱动程序同意 PM 事件。 非零值表示驱动程序不同意 PM 事件。 这可能会导致正在进行的状态转换中止。 例如,如果将 PM_SUSPEND 事件发送到 LCD 驱动程序的 PM 回调函数,并且它返回 1,则挂起操作将被中止。

所有驱动程序的回调函数都以预定义的顺序调用。 这是基于后到先得的原则,如果两个设备相互依赖,这可能会成为问题。 假设蓝牙 (BT) 设备的接口是通过 USB 主机控制器 (HC)。 蓝牙驱动程序需要此接口启动,然后才能与 BT 设备通信。 由于这种依赖关系,USB HC 驱动程序在 BT 驱动程序之前加载。 这意味着 USB HC 驱动程序在 BT 驱动程序之前向 PM 注册。

每当系统想要转换为睡眠状态时,首先向 BT 驱动程序发送 PM_SUSPEND 请求,然后向 USB 驱动程序发送 PM_SUSPEND 请求。 USB HC 驱动程序可能会关闭 BT 端口作为其 PM_SUSPEND 处理的一部分。 当系统恢复时,PM_RESUME 首先发送到 BT 驱动程序,然后发送到 USB HC 驱动程序。 在 BT 驱动程序处理此请求时,其到 BT 设备的接口不可用,因此它可能在恢复 BT 设备时遇到问题。 解决此问题的一种方法是将内核中的 PM_RESUME 顺序更改为基于先到先得的原则。

驱动程序通过调用 pm_unregister 停止参与电源管理

pm_unregister(pm_callback cbackfn);

要取消注册,它必须提供注册时使用的相同函数的指针。 一旦驱动程序取消注册自身,PM 子系统将停止使其参与进一步的 PM 事件。

Linux 还为驱动程序定义了两个接口:pm_access 和 pm_dev_idle; pm_access 应在访问硬件之前调用,pm_dev_idle 必须在设备未使用时调用。 但是,这些接口无法在所有平台上实现。

现在,我们将说明当仅设备驱动程序参与时,典型的状态转换是如何发生的。 PM 子系统将所有已向其注册的驱动程序维护在一个双向链接的循环列表中。 图 2 显示了当三个驱动程序 A、B 和 C 向其注册时,此列表的外观。 这假设驱动程序 C 首先注册,然后是 B,最后是 A。

Power Management in Linux-Based Systems

图 2. 运行状态下的系统

现在,假设系统必须从运行状态转换为待机状态。 PM 子系统向所有三个驱动程序发送 PM_STANDBY 请求,其中有两种可能的结果。 一是所有驱动程序都接受该请求,并且系统被置于待机状态。 二是某些驱动程序拒绝它。 在这种情况下,待机转换被中止,并且系统继续处于运行状态。

Power Management in Linux-Based Systems

图 3. 待机状态下的系统

图 3 显示了当所有驱动程序都接受 PM_STANDBY 请求时会发生什么。 请注意,当驱动程序接受请求时,pm_dev 结构中的 state 字段是如何更改的。

现在考虑驱动程序 A 和 B 接受 PM_STANDBY 请求,但驱动程序 C 拒绝它的情况。 图 4 显示了驱动程序 A 接受请求后的情况。 在驱动程序 A 同意后,PM_STANDBY 请求被发送到驱动程序 B。

Power Management in Linux-Based Systems

图 4. 驱动程序 A 已接受 PM_STANDBY 请求。

图 5 显示了在驱动程序 B 也接受后驱动程序的状态。 现在,设备 A 和设备 B 都被置于待机状态,而设备 C 仍处于运行状态。

Power Management in Linux-Based Systems

图 5. 驱动程序 A 和驱动程序 C 已接受 PM_STANDBY 请求。

接下来,PM_STANDBY 被发送到驱动程序 C,驱动程序 C 拒绝了它。 在这种情况下,待机转换必须中止。 由于设备 A 和设备 B 已经被置于待机状态,PM 子系统必须对它们执行撤消操作,因此它首先向驱动程序 B 发送 PM_RESUME 请求,然后向驱动程序 A 发送 PM_RESUME 请求。 在此撤消操作完成后,所有设备都恢复到其运行状态,如图 6 所示。

Power Management in Linux-Based Systems

图 6. 在驱动程序 C 拒绝 PM_STANDBY 请求后,系统恢复到运行状态。

APM

图 7 显示了 APM 模型。 此模型的重要组成部分是

  • APM BIOS:主板及其电源管理设备和组件的软件接口。 它是系统中最低级别的 PM 软件。

  • APM 驱动程序:在特定操作系统中实现 APM。

  • APM 感知设备驱动程序和应用程序:APM 驱动程序与它们交互以处理所有 PM 事件。

Power Management in Linux-Based Systems

图 7. APM 模型

APM BIOS 检测并报告各种 PM 事件,包括电池电量不足、电源状态更改、系统待机、系统恢复等。 APM 驱动程序使用轮询函数调用 APM BIOS,以收集有关 PM 事件的信息。 然后,它与 APM 感知驱动程序和应用程序关联地处理这些事件。

Linux 中的 APM 驱动程序为应用程序的使用公开了两个接口。 第一个 /proc/apm 包含有关系统电源的信息。 它指定系统是在交流电源还是电池电源上运行。 如果在电池上运行,它还会指定电池电量和电池完全耗尽的剩余时间。 第二个接口 /dev/apm-bios 允许应用程序了解和参与 PM 事件。 它还允许它们通过自行发出合适的 ioctl 调用来启动电源状态转换。 对此文件发出的读取调用将阻塞,直到下一个 PM 事件发生。 当读取调用返回时,它会携带有关即将发生的 PM 事件的信息。

某些已打开 /dev/apm_bios 的应用程序可能以 root 权限运行。 此类应用程序对于 APM 驱动程序是特殊的。 对于某些事件(例如待机或挂起转换),APM 驱动程序会将即将发生的事件通知给所有已打开 /dev/apm_bios 的应用程序。 此外,在系统实际进入待机/挂起状态之前,它会等待来自少数以 root 权限运行的应用程序的批准。 当应用程序发出合适的 ioctl 时,就会获得此批准。

通常支持以下 ioctl

  • APM_IOC_STANDBY:使系统进入待机状态。

  • APM_IOC_SUSPEND:使系统进入挂起状态。

APM 还附带两个用户空间实用程序。 apm 命令与内核中的 APM 子系统交互。 根据传递的参数,它可以显示系统电源状态,也可以用于启动系统待机/挂起转换。 apmd 守护程序报告和处理各种 PM 事件,并将所有 PM 事件记录到 /var/log/messages。 除了日志记录外,apmd 还可以为每种类型的 PM 事件采取一些特定操作。 这些操作在脚本文件(通常称为 apmd_proxy)中指定。 此脚本文件由 apmd 守护程序调用,带有一个或两个参数,指示即将发生的 PM 事件。 以下是一个示例脚本文件

case 1:2 in

"standby":*)
     #System is going to Standby state because of
     #inactivity. Reduce CPU speed.
     echo 162200 > /proc/sys/cpu/0/speed
     ;;

"resume":"standby")
     #System is resuming to Run state from Standby
     #because of activity. Increase back the CPU
     #speed.
     echo 206400 > /proc/sys/cpu/0/speed
     ;;

"suspend":*)
     #System going to suspend state. Bring down
     #network interface.
     ifconfig eth0 down
     ;;

"resume":"suspend")
     #System resuming from suspend state.
     #bring up network interface and
     #increase the CPU speed and
     ifconfig eth0 up
     echo 206400 > /proc/sys/cpu/0/speed
     ;;
电源状态转换示例

通过以涉及驱动程序和应用程序的状态转换为例,可以理解电源状态转换中涉及的一些复杂性。 假设系统有两个驱动程序 D1 和 D2 向 PM 注册,以及三个也参与 PM 的应用程序 A、B 和 C(通过打开 /dev/apm_bios 的方式)。 在这三个应用程序中,A 和 B 以超级用户权限运行,而 C 则不是。 图 8 描述了这种情况。

Power Management in Linux-Based Systems

图 8. 电源状态转换示例

现在,使用此设置,让我们考虑一个系统想要从运行状态转换为睡眠状态的情况。 在这种情况下涉及的步骤顺序从通知应用程序 A、B 和 C 即将转换为睡眠状态开始。 这允许它们采取为此转换所需的任何操作。 此外,由于 A 和 B 具有超级用户权限,我们必须等待它们同意此睡眠转换,然后才能继续进行。

当 A 和 B 完成它们在系统转换为睡眠状态之前需要执行的任何工作后,它们会向 APM 驱动程序发出同意信号。 现在,APM 驱动程序已准备好将系统置于睡眠状态。 它向 D1 和 D2 发送 PM_SUSPEND 消息。 D1 和 D2 将各自的设备置于睡眠状态,并向 APM 发出同意信号。 在 D1 和 D2 完成处理此转换后,APM 通知 CPU PM 驱动程序将 CPU 置于睡眠状态。 在此阶段,系统转换为睡眠状态完成。

结论

尽管 APM 有一些缺点,但它的简单性使其几乎可以在任何设备中实现。 诸如 ACPI 之类的其他标准以复杂性为代价,提供了更丰富的电源管理控制。 所有设备驱动程序和应用程序正确实现电源管理支持也至关重要。 如果没有这种适当的支持,单个驱动程序可能会阻止系统(例如)进入挂起状态。 一旦正确实施,电源管理软件将在延长电池寿命方面极大地惠及系统,从而提高效率。

资源

APM 规范

内核源代码中的 Documentation/pm.txt

Intel SA1110 高级开发人员手册

Srivatsa Vaddagiri (vsrivatsa@in.ibm.com) 自 1996 年以来一直在 IBM 印度公司工作。他参与了许多项目,主要专注于 UNIX 系统。 目前,他在嵌入式 Linux 部门工作,负责基于 Linux 的手持设备的电源管理支持。

Anand K. Santhanam (asanthan@in.ibm.com) 自 1999 年 7 月以来一直在 IBM 全球服务(软件实验室)印度公司工作。他是 IBM Linux 团队的成员,主要专注于设备驱动程序、ARM-Linux 和嵌入式系统中的电源管理。

Vijay Sukthankar (vksuktha@in.ibm.com) 自 1994 年以来一直在 IBM 工作。目前,他管理 Linux 能力中心,并且还管理在 IBM 从事 Linux 开源开发的团队。 他还参与 IBM 内的各个小组,以提供有关嵌入式 Linux 的服务。

Murali Iyer (mniyer@us.ibm.com) 自 1995 年以来一直在 IBM 工作,并在世界各地的各个 IBM 实验室工作过。 自 2000 年以来,他一直参与使用 Linux 设计嵌入式系统。 正在执行的一些项目包括高端手持设备和起搏器程序员。

加载 Disqus 评论