找回密码
 注册
关于网站域名变更的通知
查看: 544|回复: 1
打印 上一主题 下一主题

 Linux电源管理详解

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2019-7-9 09:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
Linux电源管理详解
2 n3 i  K1 C$ l/ Z7 R  I

# D% q0 d" B$ `7 R/ W5 g" H, X+ w; p; |( T2 [4 Z' [
1.概述

' ?1 Q/ o* T* O7 q; [9 X% |9 U3 @$ b6 M& C$ D' A) L$ q
  虽然Linux可以在任何一台386以上的PC上运行,目前大多数人使用的都是新型的,带有各种外设的桌面PC或者笔记本电脑,这样,电源管理功能 (PM)就逐渐变得越来越重要。在笔记本电脑上电源管理可以节能,延长电池寿命,而在桌面PC上它可以降低幅射,降温,延长外设使用寿命。现在的操作系统大都内置了电源管理支持,例如 Windows 和 Linux。
; }8 r( t- l- N) d# a0 m
3 c$ Q% O# O7 W' Z! o( ]- S: g2.PC机实现电源管理的方法
" c. X; ~3 j& o/ t4 s2 {6 a2 D" ]1 o) e) J2 {6 C! a! b5 \- u
  要实现电源管理,最重要的有两点:第一是需要设备本身支持节电功能,比如硬盘,可以通过指令暂时关闭;第二是需要操作系统支持电源管理,这样就可以在空闲一段时间之后调用驱动的电源管理功能关闭设备。
: z$ L- I2 }" y- Y: y' G
# U3 H9 H% L9 Y' I" K/ G两种电源管理标准:APM和ACPI
1 N. E. a* I9 D2 j3 }$ O% V; E9 b
6 c7 s# z6 P! h7 f# g/ Q: ^  传统的APM(Advanced Power Management)是一种基于bios的电源管理标准,目前的最新版本是1.2,它提供了CPU和设备电源管理的功能,但是由于这种电源管理方式主要 是由bios实现,所以有些缺陷,比如对bios的过度依赖,新老bios之间的不兼容性,以及无法判断电源管理命令是由用户发起的还是由bios发起 的,对某些新硬件如USB和1394的不支持性。   为了弥补APM的缺陷,新的电源管理ACPI应运而生,这就是ACPI(Advanced Configuration and Power InteRFace),它主要是将电源管理的主要执行者由bios转换成为操作系统,这样可以提供更大的灵活性以及可扩展性。
: {1 a$ u5 j8 d) U& e$ K
: V4 A+ u4 G# N  目前的PC机主板一般同时支持APM和ACPI两种标准。 % _4 m% V( r, Z  x* w' x

/ w! Z% i- k$ k! [7 P# Y: ~3.Linux对电源管理的支持
3 `0 o4 o6 Z- y! c; }9 A7 U( J  g0 |& h  E* o
内核模块 ' Q. e* M" ^- H! ^* x. `. E

  ?$ Z" g* e( G3 R; R  针对APM和ACPI两种不同的标准,Linux内核提供了两个不同的模块来实现电源管理功能,这就是apm和acpi。需要注意,apm和acpi是互相冲突的两个模块,用户在同一时间内只能加载其中之一,如果当他们在加载的时候发现二者之一已经加载,就会自动退出。  ^8 |/ [5 t8 Y3 h- k
  z. P2 I6 t$ ^( d9 b6 e* A
  在官方发布的内核中APM是较为成熟的电源管理方式,可以完成在Windows下ACPI所能完成的大部分功能。由于官方内核中ACPI的功能比较有限, 目前还处于开发版状态。所以当前的大多数distribution,如红帽子默认就使用了apm作为电源管理方式。但是值得注意的是Linux中的 ACPI实际上是由一个单独的项目小组模块进行维护的,当前内核ACPI的版本实际上已经远远落后于最新的版本。由于Linux稳定版中对任何新特性的加 入都非常谨慎小心,所以我们也许只能等到2.6.x版本的Linux诞生后才能看到ACPI的稳定全功能版了。不过我们也可以自己对内核打最新的ACPI 补丁来获得这些功能。 % ^: u( P8 g- P2 ^) Y; j: j

. J; z9 u* @* f+ c$ |1 O  这里是ACPI的主页:http://sf.net/projects/acpi/( @  K2 \, h% E4 X8 A7 a4 w0 t

& @) M3 b! n7 ~  k1 _  下面对电源管理的介绍以APM为主。 1 r# f$ M8 [5 {9 V& i
0 S0 @9 X9 |6 T2 ]# @4 X5 K
用户态Daemon , w& b8 G9 p7 \' V9 A
. }/ K5 a! P, `3 c: n
  为了让Linux内核中的电源管理功能够更好的被利用,我们还需要用户态daemon程序的配合。针对APM和ACPI,分别有apmd和acpid两个 不同软件。他们实现的功能比较类似,都是允许用户预先定义某些策略,然后跟踪电源状态,执行特定的操作。在apmd软件包中还有一个工具apm,用户可以 用它使机器主动进入standby和suspend状态,还可以查询bios的apm版本号。在使用acpi时直接对proc文件系统进行操作即可完成同 样的功能。 % _5 E7 F& f* J' h' p

' Z* ?+ Z7 z6 ~! ]% A4.Linux下驱动的电源管理机制
* _4 E" V0 @( [* I& H2 q6 z; e+ Z  G
  在Linux下不必为驱动分别编写与APM和ACPI相对应的代码,Linux与Windows类似,为驱动提供了统一的电源管理接口。驱动只要实现了这些接口,就可以实现电源管理的功能。操作系统在它认为合适的时候就会通知驱动完成这些操作。0 t' J' e. ^) t2 k& H; C! g9 w0 e
6 P' O4 K# n+ u1 I
  实现设备电源管理接口主要需要实现以下5点: $ [% t# l  R- _! r' u0 S! l0 U
1 m+ e* F$ _) \3 k
  1.使用pm_register对设备的每个实例(instance)进行注册;
; B, N& I# O0 B3 X
4 e$ t3 ^! F+ q; q  2.在对硬件进行操作之前调用pm_access(这样会保证设备已被唤醒并且处于ready状态); 1 m$ u  F& b# i3 i, @
. }/ `, I  \" Y( Z6 U- b. ^# J3 x
  3.用户自己的pm_callback函数在系统进入suspend状态(ACPI D1-D3),或者从suspend状态恢复(ACPI D0)的时候会被调用;
  b' F$ ^# ?% c6 W1 j, m* g1 Q% K9 \( T, L
  4.当设备不在被使用的时候调用pm_dev_idle函数,这个操作是可选的,可以增强设备idle状态的监测能力; * r8 L6 h0 k# S- T
3 T2 e8 [4 d# A' R6 k
  5.当被unload的时候,使用pm_unregister来取消设备的注册。 & w# R! Z  s7 K6 V

1 q# A1 u1 B9 ?6 Z% f& [5 L5.对APM进行编程
/ O; E: z* r1 B3 L6 L9 b/ A5 \
  下面介绍在实模式中和在Linux下使用APM功能的编程方法: 0 o9 M( i3 x* ^  Z  ^! P
. S( R6 q' y! Z' {- {/ X% r& Y2 E
  由于APM是由bios提供的,我们可以直接在实模式(如DOS下)调用int 15软中断来进行电源管理操作。 4 ?* D1 e$ J. r/ t

3 N/ r8 ]; q1 U+ q, V  在实模式下APM的standby、suspend和poweroff功能分别可以通过下面的汇编语言实现: " W2 Q5 o8 }) ~5 F6 Q! \% A5 A4 w2 o

6 E4 B7 {+ ]8 F0 Z$ L5 V1 x4 sstandby:0 a2 W- L( C% J8 F# _4 [) r' I
mov ax, 5307H4 B  U3 m( X* I0 P0 ?) R
mov bx, 1
) l' Q+ [6 @7 `% A+ x. p" x; ?4 c# e/ wmov cx, 19 o- y1 m& [) u6 H6 k3 p
int 15H7 f. g1 B) I0 C7 }
$ u! X: m* C' \" K: `0 i+ z
suspend:
5 K( L: o/ C; d$ U! R# @  c) p改成 mov cx,2
- r& g1 a7 W2 D$ _) g) t" ?# j) y& t2 C
poweroff:
# f7 N: K+ ^; u3 m' Q& }  l" D改成 mov cx,3
$ Q! P. U  u, ?8 m9 V  R' V- `
5 k5 a) p8 M! G( V. B: _7 l6 U) U( f
/ O9 \1 k/ L# c
  需要注意的一件事是在Linux内核中没有使用和实模式的一样的方法来调用int 15H中断,而是直接调用了bios的保护模式接口。所以我们如果修改了bios中的apm相关代码并且没有处理好保护模式接口的问题,可以出现这样的情况:在实模式DOS下使用apm功能一切正常,但是在Linux下调用apm功能发生内核一般保护性错误。
* R: M8 L6 e8 h6 r
9 t- y- U+ O7 D. ?7 |9 b5 H8 k  在Linux下我们可以通过对apm_bios设备的操作来完成同样的功能。 ' s' B& A/ [( P5 H
! R; l& J# M6 M4 Z2 t
  下面的代码可以实现APM的suspend功能,等价于apm -s
* F: ]4 x# Z9 ]/ b1 i
0 l9 w7 K) J! D1 r#include <stdio.h>
4 R; h; k+ {' y3 d. p7 m  w* e3 p#include <unistd.h>3 t, h4 H, o1 s) C% M4 y" Q
#include <stdlib.h>
+ D5 b2 B. z) x+ h#include <asm/fcntl.h>
) j9 w7 ^* [3 E; `# A#include <linux/types.h>5 h& N8 [% J* N, F3 j
#include <sys/types.h>
6 K; |  m2 M' P' Y2 y#include "apm.h"7 B/ h5 [5 N! s- e
, m3 [+ a) v8 h7 [- E3 g; ]
int main()6 v3 J+ }3 L9 d) P& ^& O
{
+ p& v) |5 E  h/ @    int fd, res;& ^% l. {  ^$ B$ x
    fd = open("/dev/apm_bios", O_RDWR);! z7 _: e/ v! ~6 d, @& _
    if (fd < 0) {4 h; Y6 ?$ [+ [) J
          printf("open /dev/apm_bios error!\n");
' g5 i3 B: L# M' }          exit(-1);
, D0 G/ J1 n3 V0 r, F- |8 l$ k    }
& P8 E$ X& g) G  N    sync();% m4 k9 h# a# j: e2 K
    res = ioctl(fd, APM_IOC_SUSPEND, NULL);, p: ~, R' E2 Q9 q
    if (res != 0) {
4 N2 [, `; o/ i4 a5 u          printf("ioctl error!\n");
) J+ o$ v4 C9 k' q          close(fd);1 k4 P2 `, q8 O" w# P/ C
          exit(-1);
% g( E( O- I9 c% h    }- ^! k) U/ L# e) q3 G; h' a7 r
    close(fd);5 M. ]* Q- J6 H* I$ g+ S+ g
    return 0;
! |, H) [% s5 L9 h; M}
& p: u8 N) Y' `7 S8 ]0 I) U1 h. f6 c( C5 W5 U2 A
' \6 _6 F4 R$ F6 Y+ v# r

7 V! d( e3 \% s# {5 C; }  如果我们把上面程序中的SUSPEND改成STANDBY,我们就同样实现了apm -S的功能。 # m" `$ @# a( l8 s& J

+ R3 P/ U7 p' d4 \  在Linux下POWEROFF操作有其独特的流程,最后根据内核中apm或者acpi的存在情况来执行相应不同的流程来关闭电源。请参见Linux内核源码,我写的《linux关机重启流程分析》中也有一定的介绍。+ x. w2 I4 l( n6 g/ b9 y1 C- r
: B/ e% T/ |/ N; T6 H' q2 h

7 \9 C% E+ ?& O0 R0 t6 A6.常见问题(FAQ) 5 q/ n7 L$ ^7 P" g& ?% q
( L  K; t4 P0 @$ f/ h7 C
  1)我的系统不能被suspend,这是怎么回事呢? . O2 A+ R9 @# k/ X: K, T( g2 |
; t0 N  F0 w/ u  k
  系统在suspend之前会向所有的驱动发消息,如果这个时候某个傲慢的驱动返回了一个-EBUSY,那么这次suspend的企图就被这个驱动否决了, 你只有过一会再试,如果这个驱动总是否决(真是蛮横,不过它也许有自己的苦衷也说不定),你就永远都无法suspend了。
; J5 r0 Z0 ~) {5 W/ `- {2 y. g% h5 b* _7 }) X8 G
  2)我按下系统的POWEROFF开关,在ATX的主板上,系统就会自动关机了,这个处理流程是什么样子的呢? , [$ y  B3 P. c* i. v: C

0 q( h* A$ k9 @) L0 e. I, m" o  在内核APM模块中建立了一个核心态线程不停的监测系统状态,用户的关机动作在这里被截获后处理。详细的流程可以参见本人的《linux关机重启流程分析》。
3 _# E3 k+ S! U( [& o. U
/ K7 ?1 x( G4 u4 f& o  3)Linux中电源管理的文档在哪里? + q5 Q3 u; a: l7 a) i

( H! C: y, l3 N  在Linux/document.tion目录下的pm.txt中详细定义了Linux驱动电源管理接口实现方式,并且有详细的例子,apm和acpi的实现流程需要参见Linux源码的实现。
) \; W, I8 o9 y% Y- W& o& x: b" L" f* F+ Q4 R8 D" i
7.总结
' o6 z* h7 X* C9 a! B% I# K
$ m  q/ b! Q" k" M  ?8 x, N+ t  Linux中的电源管理是发展中的代码。从目前的趋势来看ACPI终将取代APM。现在使用APM则是较为成熟和稳妥的方案。我们如果现在编写驱动应该严格遵守文档中的pm.txt所规定的接口,这样可以使我们的驱动有较强电源管理的适应性和稳定性。% v$ H$ ?4 `. E$ G6 P
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-8-12 04:52 , Processed in 0.125000 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表