ACPI 中文文档ACPI 中文文档
首页
第 1 章
第 2 章
第 3 章
第 4 章
第 5 章
第 6 章
第 7 章
第 8 章
第 9 章
第 10 章
第 11 章
第 12 章
第 13 章
第 14 章
第 15 章
第 16 章
第 17 章
第 18 章
第 19 章
第 20 章
第 21 章
附录 A
首页
第 1 章
第 2 章
第 3 章
第 4 章
第 5 章
第 6 章
第 7 章
第 8 章
第 9 章
第 10 章
第 11 章
第 12 章
第 13 章
第 14 章
第 15 章
第 16 章
第 17 章
第 18 章
第 19 章
第 20 章
第 21 章
附录 A
  • 第 8 章

    • 总览
    • 8.1. 处理器电源状态
    • 8.2. 刷新缓存
    • 8.3. 电源、性能和节流状态依赖关系
    • 8.4. 声明处理器
      • 8.4.1. _PDC(处理器驱动程序能力)
      • 8.4.2. 处理器电源状态控制
      • 8.4.3. 处理器层次结构
      • 8.4.4. 更低功耗空闲状态
        • 8.4.4.1. 分层空闲状态
        • 8.4.4.2. 空闲状态协调
        • 8.4.4.3. _LPI(低功耗空闲状态)
        • 8.4.4.4. _RDI(空闲的资源依赖)
        • 8.4.4.5. 兼容性
      • 8.4.5. 处理器节流控制
      • 8.4.6. 处理器性能控制
      • 8.4.7. 协作式处理器性能控制
        • 8.4.7.1. _CPC(连续性能控制)
          • 8.4.7.1.1. 性能能力/阈值
          • 8.4.7.1.2. 性能控制
          • 8.4.7.1.3. 性能反馈
          • 8.4.7.1.4. CPPC 启用寄存器
          • 8.4.7.1.5. 自主选择启用寄存器
          • 8.4.7.1.6. 自主活动窗口寄存器
          • 8.4.7.1.7. 能量性能偏好寄存器
          • 8.4.7.1.8. OSPM 控制策略
          • 8.4.7.1.9. 使用 PCC 寄存器
          • 8.4.7.1.10. 与其他由 ACPI 定义的对象和通知的关系
          • 8.4.7.1.11. _CPC 实现示例
      • 8.4.8. _PPE(平台错误轮询)
    • 8.5. 处理器聚合器设备

8.4.4.2. 空闲状态协调

在分层空闲状态中,多个处理器会影响任何非叶子层级节点的空闲状态。以我们的“处理器层级中的电源状态”示例系统为例,要使集群 0 进入低功耗状态,Core 0 和 Core 1 都必须空闲。此外,Core 0 和 Core 1 在进入空闲时所做的电源状态选择,也会影响 Cluster 0 可使用的状态。这要求在两个处理器之间协调空闲状态请求。ACPI 支持两种不同的协调方案(详细内容见后续小节):

  • 平台协调

  • OS 发起。

OS 和平台可以使用 _OSC 方法就支持 OS 发起空闲或平台协调空闲进行握手,如 平台范围的 OSPM 能力 中所述。请注意,进入 OS 发起模式可能需要特定于体系结构的命令,在这种情况下,请参阅特定于体系结构的文档。(关于 PSCI 文档,请参见 http://uefi.org/acpi 中标题为“PCSI 规范”的部分;关于 ARM FFH 文档,请参见 http://uefi.org/acpi 中标题为“ARM FFH 规范”的部分。)

8.4.4.2.1. 平台协调

在平台协调方案中,平台负责跨处理器协调空闲状态。OSPM 从每个处理器对层级的所有级别发出请求,这意味着每个处理器都通过为其自身、其父级、其父级的父级等请求一个局部电源状态来进行表决。(在某些情况下,特定层级级别的表决可能是隐式的——有关更多详细信息,请参见下文关于自动提升的讨论。)在为更高级别选择空闲状态时,处理器上的 OSPM 可以选择让更高级别节点保持在运行状态——这仍然是对该节点的一次表决,平台必须予以尊重。OSPM 表达的表决规定了平台可为处理器以及受该表决影响的任何父节点选择的局部电源状态约束。具体而言,该表决表示平台不得进入:

  1. 比请求状态更深(功耗更低)的局部状态。

  2. 唤醒延迟高于请求状态的局部电源状态。

  3. 具有而请求状态不具有的电源资源依赖关系的局部电源状态。

平台会查看所有底层核心对每个层级节点的表决,并选择满足所有表决相关全部约束的最深局部状态。通常,这只意味着采用某个核心所表决的最浅状态,因为较浅状态具有更低的唤醒延迟、更低的最小驻留时间以及更少的电源资源依赖关系。然而,这并不总是成立,因为状态深度和延迟并不总是同步增加。为了提高效率,平台通常不应进入最小驻留时间高于请求状态的电源状态。然而,这并不是严格的功能性要求。如果平台认为基于具体状态和情形这是最高效的选择,则可以决定解析到具有更高最小驻留时间的状态。

使用上述“处理器层级中的电源状态”示例,一个简单流程如下所示:

  • Core0 进入空闲 - OS 请求 Core0 断电,Cluster0 保持

  • 平台接收 Core0 请求 - 将 Core0 置于断电状态

  • Core1 进入空闲 - OS 请求 Core1 断电,Cluster0 断电

  • 平台接收 Core1 请求 - 将 Core1 置于断电状态,并对 Cluster0 采用最浅表决,从而将其置于保持状态

如果 OSPM 想要请求超出集群级别的电源状态,那么 Core0 和 Core1 还会在系统级别对空闲状态进行表决,而平台将通过上述方法,结合它们的表决以及系统层级下任何其他处理器的表决,解析出最终状态选择。

如上所述,某些平台支持一种称为自动提升的机制,在这种机制中,对更高级别状态的表决可以是隐式的而不是显式的。在此方案中,平台向 OSPM 提供命令,以请求处理器层级较低级别的空闲状态,而这会自动隐含对层级中相应更高级别的特定空闲状态请求。没有显式请求进入更高级别状态的命令,只有基于较低级别状态的隐式请求。

例如,如果“处理器层级中的电源状态”所示平台对 Cluster0 时钟门控状态使用自动提升,则 Core0 和 Core1 都不能显式请求它。然而,来自 Core0 或 Core1 任一方的核心级时钟门控请求将隐含一个 Cluster0 时钟门控请求。因此,如果两个核心都请求核心时钟门控(或更深状态),平台将自动对 Cluster0 应用时钟门控。有关 ACPI 如何支持自动提升的更多细节,可参见进入方法和组合。

8.4.4.2.2. OS 发起

在 OS 发起协调方案中,OSPM 仅在最后一个底层处理器进入睡眠时,才为特定层级节点请求空闲状态。显然,处理器始终会为其自身选择一个空闲状态,但对于像集群这样的更高层级节点,只有当集群中的最后一个处理器进入空闲时,才会选择其空闲状态。平台在决定特定节点的空闲状态时,只考虑该节点最近一次的请求。

OS 发起协调的主要动机是:

  1. 避免 OSPM 为实际上不会被使用的更高层级空闲状态评估选择所带来的开销,因为其他处理器仍然处于唤醒状态

  2. 允许 OSPM 基于最新信息做出更高层级空闲状态选择,即只采用特定节点最近一次的请求,而忽略过去已进入睡眠的处理器所发出的请求(这些请求可能基于现已过时的信息)

使用上述示例时,一个简单流程如下所示。

表 8.6 OS 发起流程

步骤OS 的电源状态视图平台的电源状态视图
0:Core 0 和 1 均处于唤醒并正在运行代码Core0: 运行中 Core1: 运行中 Cluster0: 运行中Core0: 运行中 Core1: 运行中 Cluster0: 运行中
1Core0 上的 OS 请求 Core0 断电Core0: 断电 Core1: 运行中 Cluster0: 运行中Core0: 运行中 Core1: 运行中 Cluster0: 运行中
2平台观察到请求并将 Core0 置于断电状态Core0: 断电 Core1: 运行中 Cluster0: 运行中Core0: 断电 Core1: 运行中 Cluster0: 运行中
3Core1 上的 OS 请求 Core1 断电 和 Cluster0 断电Core0: 断电 Core1: 断电 Cluster0: 断电Core0: 断电 Core1: 运行中 Cluster0: 运行中
4平台观察到对 Core1 和 Cluster0 的请求并对其进行处理Core0: 断电 Core1: 断电 Cluster0: 断电Core0: 断电 Core1: 断电 Cluster0: 断电

请注意,Core1 正在做出一个会影响 Core0 和 Core1 的集群决策,因此 OSPM 在请求集群状态时,应考虑两个核心的预期睡眠持续时间、唤醒延迟要求、设备依赖关系等,而不只是 Core1。

平台仍然负责确保功能正确性。例如,如果 Core0 重新唤醒,则在上述示例中由 Core1 请求的集群状态应当退出,或者应中止进入该状态。OSPM 没有责任保证最后一个关闭的核心也是第一个启动的核心,也没有责任保证某个核心不会恰好在另一个核心请求更高层级睡眠状态时唤醒。

8.4.4.2.2.1. OS 发起请求语义

在 OS 发起协调中,来自不同核心的请求顺序极其重要,因为平台会根据最新的请求采取动作。如果平台没有按照 OS 预期的顺序处理请求,那么它可能会使平台进入错误的状态。请考虑我们在“处理器层级中的电源状态”示例系统中的这种场景,如下表所示。

表 8.7 在没有依赖性检查的情况下,OS 发起请求中的错误平台状态示例

步骤OS 的电源状态视图平台的电源状态视图
0:Core0 处于断电状态,Core1 正在运行Core0: 断电 Core1: 运行中 Cluster0: 运行中Core0: 断电 Core1: 运行中 Cluster0: 运行中
1Core1 进入空闲 – OSPM 请求 Core1 断电 和 Cluster0 保持Core0: 断电 Core1: 断电 Cluster0: 保持Core0: 断电 Core1: 运行中 Cluster0: 运行中
2Core0 收到一个中断并在平台中唤醒Core0: 断电 Core1: 断电 Cluster0: 保持Core0: 运行中 Core1: 运行中 Cluster0: 运行中
3Core0 进入 OSPM 并开始处理中断Core0: 运行中 Core1: 断电 Cluster0: 运行中Core0: 运行中 Core1: 运行中 Cluster0: 运行中
4Core0 进入空闲且 OSPM 请求 Core0 断电,Cluster0 断电Core0: 断电 Core1: 断电 Cluster0: 断电Core0: 运行中 Core1: 运行中 Cluster0: 运行中
5Core0 的空闲请求“超过”Core1 的请求。平台将 Core0 置于断电状态,但忽略集群请求,因为 Core1 仍在运行Core0: 断电 Core1: 断电 Cluster0: 断电Core0: 断电 Core1: 运行中 Cluster0: 运行中
6平台观察到 Core1 的请求。平台将 Core1 置于断电状态,并将 Cluster0 置于保持状态。Core0: 断电 Core1: 断电 Cluster0: 断电!!(见下方注释)Core0: 断电 Core1: 断电 Cluster0: 保持!!(见下方注释)

注释

在上表最后一行中,Cluster0 的值不匹配。

这里的关键问题是两个核心请求之间的竞争条件;无法保证它们以 OS 发出请求时相同的顺序到达平台。预计这种情况并不常见,但由于各种潜在原因,Core0 的请求可能会“超过”Core1 的请求——较低频率、不同的缓存行为、处理某些 OS 不可见事件等。该事件序列导致平台错误地依据来自 Core1 的过时 Cluster0 请求采取动作,而不是依据来自 Core0 的最新请求。最终结果是,直到下一次唤醒之前,Cluster0 都会保持在错误的状态。

为解决此类竞争条件并确保平台与 OS 对请求排序具有一致的视图,增强了 OS 发起的空闲状态请求语义,以包含分层依赖性检查。当平台接收到请求时,它负责检查发出请求的核心是否确实是在所请求域中最后一个进入关闭状态的核心;如果不是,则拒绝该请求。请注意,即使 OSPM 和平台的行为都正确,由于各种竞争情况,它们对系统状态的看法也不一定总是一致。例如,平台可能会在 OSPM 之前看到某个核心被唤醒,因此认为该核心正在运行,而 OSPM 仍然认为它处于休眠状态。为了进行依赖性检查,平台一旦看到某个核心的请求,就可以开始将该核心视为处于低功耗状态(以便能够相对于其他 OS 请求进行正确排序)。在某个核心从空闲状态唤醒后,平台必须在将控制权返回给 OS 之前开始将该核心视为正在运行。

有了这种依赖性检查,上述示例将变为如下所示:

表 8.8 带依赖性检查的 OS 发起请求语义

步骤:OS 对电源状态的视图平台对电源状态的视图
0-4:与上文相同Core0:关闭 Core1:关闭 Cluster0:关闭Core0:运行中 Core1:运行中 Cluster0:运行中
5Core0 的空闲请求“越过”了 Core1 的请求。平台拒绝 Core0 的请求,因为该请求包含 Cluster0,而 Core1 仍然处于唤醒状态。Core0:关闭 Core1:关闭 Cluster0:关闭Core0:运行中 Core1:运行中 Cluster0:运行中
6平台观察到 Core1 的请求。平台拒绝 Core1 的请求,因为该请求包含 Cluster0,而 Core0 仍然处于唤醒状态。Core0:关闭 Core1:关闭 Cluster0:关闭Core0:运行中 Core1:运行中 Cluster0:运行中
7OS 在 Core0 上恢复执行Core0:运行中 Core1:关闭 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中
8OS 在 Core1 上恢复执行Core0:运行中 Core1:运行中 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中

一旦控制权返回给 OS,它就可以按其认为合适的方式进行处理——很可能只是重新评估两个核心上的空闲状态。当请求乱序到达时,因拒绝该命令并迫使 OS 重新评估而会引入一些开销,但这种情况预期很少发生。由 OS 发送的请求在绝大多数情况下应当会按相同顺序被平台看到,而在这种情况下,空闲命令将正常继续。

即使某个层级节点下的所有 CPU 都已休眠,OS 也可能选择让该特定层级节点保持运行。这会引发另一个潜在的边界情况——见下文。

表 8.9 不带层级参数的 OS 发起请求中平台状态错误的示例

步骤OS 对电源状态的视图平台对电源状态的视图
0:Core0 处于关闭状态,Core1 正在运行Core0:关闭 Core1:运行中 Cluster0:运行中Core0:关闭 Core1:运行中 Cluster0:运行中
1Core1 进入空闲——OSPM OS 请求 Core1 关闭和 Cluster0 保持态Core0:关闭 Core1:关闭 Cluster0:保持态Core0:关闭 Core1:运行中 Cluster0:运行中
2Core0 接收到一个中断并唤醒进入平台Core0:关闭 Core1:关闭 Cluster0:保持态Core0:运行中 Core1:运行中 Cluster0:运行中
3Core0 进入 OSPM 并开始处理中断Core0:运行中 Core1:关闭 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中
4Core0 进入空闲,OSPM 请求 Core0 关闭,并请求 Cluster0 保持运行Core0:关闭 Core1:关闭 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中
5Core0 的空闲请求“越过”了 Core1 的请求。平台将 Core0 置为关闭状态。即使 OS 提出了让集群运行的请求,平台也不知道应当拒绝 Core0 的请求,因为其中不包含 Cluster 空闲状态Core0:关闭 Core1:关闭 Cluster0:运行中Core0:关闭 Core1:运行中 Cluster0:运行中
6平台观察到 Core1 的请求。平台将 Core1 置为关闭状态,并将 Cluster0 置为保持态。Core0:关闭 Core1:关闭 Cluster0:运行中!! (见下方注释)Core0:关闭 Core1:关闭 Cluster0:保持态!! (见下方注释)

注释

在上表的最后一行中,Cluster0 的值不匹配。

根本问题在于,平台无法根据哪些层级被置于低功耗模式来推断一个请求针对的是哪个层级。为缓解这一问题,每个空闲状态命令除了正常的空闲状态标识符之外,还必须包含一个层级参数,用于指定 OS 正在为其发出请求的最高层级节点。即使 OS 不希望某个更高层级的层级节点进入空闲状态,它也应指明该核心是否是该节点下最后一个进入关闭状态的核心。这使得平台能够理解 OS 对层级状态的视图,并确保请求的排序,即使 OS 请求某个特定节点保持运行也是如此。

下表说明了这一增强。

表 8.10 带层级参数的 OS 发起请求语义

步骤OS 对电源状态的视图平台对电源状态的视图
0:Core0 处于关闭状态,Core1 正在运行Core0:关闭 Core1:运行中 Cluster0:运行中Core0:关闭 Core1:运行中 Cluster0:运行中
1Core1 进入空闲——OSPM OS 请求 Core1 关闭和 Cluster0 保持态,并将自身标识为 Cluster0 中最后一个进入关闭状态的核心Core0:关闭 Core1:关闭 Cluster0:保持态Core0:关闭 Core1:运行中 Cluster0:运行中
2Core0 接收到一个中断并唤醒进入平台Core0:关闭 Core1:关闭 Cluster0:保持态Core0:运行中 Core1:运行中 Cluster0:运行中
3Core0 进入 OSPM 并开始处理中断Core0:运行中 Core1:关闭 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中
4Core0 进入空闲,OSPM 请求 Core0 关闭,并请求 Cluster0 保持运行,并将自身标识为 Cluster0 中最后一个进入关闭状态的核心Core0:关闭 Core1:关闭 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中
5Core0 的空闲请求“越过”了 Core1 的请求。平台拒绝 Core0 的请求,因为这是一个针对 Cluster0 的请求,而 Core1 仍然处于唤醒状态。Core0:关闭 Core1:关闭 Cluster0:关闭Core0:运行中 Core1:运行中 Cluster0:运行中
6平台观察到 Core1 的请求。平台拒绝 Core1 的请求,因为这是一个针对 Cluster0 的请求,而 Core0 仍然处于唤醒状态。Core0:关闭 Core1:关闭 Cluster0:关闭Core0:运行中 Core1:运行中 Cluster0:运行中
7OS 在 Core0 上恢复执行Core0:运行中 Core1:关闭 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中
8OS 在 Core1 上恢复执行Core0:运行中 Core1:运行中 Cluster0:运行中Core0:运行中 Core1:运行中 Cluster0:运行中

与前文相同,一旦控制权返回给 OS,它就可以按其认为合适的方式进行处理——很可能只是再次在两个核心上请求空闲状态。

Prev
8.4.4.1. 分层空闲状态
Next
8.4.4.3. _LPI(低功耗空闲状态)