1. 电源状态
ACPI(Advanced Configuration and Power Interface)在运行中有以下几种模式:
- S0 正常。
- S1 CPU停止工作。唤醒时间:0秒。
- S2 CPU关闭。唤醒时间:0.1秒。
- S3 除了内存外的部件都停止工作。唤醒时间:0.5秒。
- S4 内存信息写入硬盘,所有部件停止工作。唤醒时间:30秒。(休眠状态)
- S5 关闭。
S1 =>Standby:
即指说系统处于低电源供应状态,在 windows or BIOS 中可设定萤幕讯号输出关闭、 硬碟停止运转进入待命状态、电源灯号处于闪烁状态。此时动一动滑鼠、按键盘任一键均可叫醒电脑。
S2 =>Power Standby:
和 S1 几乎是一样。
S3 =>Suspend to RAM:
即是把 windows 现在存在记忆体中的所有资料保存不动,然后进入「假关机」。此时除了记忆体需要电源来保持资料以外,其它的设备、装置全部停止供电。也就是说,理论上可以把 CPU, PCI, AGP device 拿掉又插回去,电脑也可能正常完成开机及运作,只要不动到记忆体和电源的部份。这时只剩下电源灯号一闪一闪的,其它和关机没什么两样。(电源供应器的风扇也停止运转喔)重新开新后,电脑只是把记忆体的资料完整性确认后,即立刻会回到你进 S3 前的画面。记得有人试过,在烧录中启动 S3 ,CDRW 还会自动启动 Just-Link ,等你回復后它又自动继续烧。(听说而以,自己没试过)。
S4 =>Suspend to Disk:
即是把 windows 记忆体中的资料完整的存在硬碟中。等开机时就直接从存这些资料的地方直接完整的读到记忆体,不需要跑一堆应用程式。使用这种模式的话,硬碟一定要腾出一个完整的连续空间。Windows 98/SE 必需要用软体去製作一个大档案或是一个磁区来提供 win98/SE 执行 S4 这功能,WinME/2000/XP 本身就有製作一个大档案来给 S4 功能用(在电源管理中有一个启动休眠,就是这个啦) 。在启动后,在 C: 下会看到一个和你电脑现有记忆体大小一样的大档案。
S5 =>Shutdown:
彻底关机掉电
2. Suspend
Linux内核支持多种类型睡眠状态,目前存在四种模式:suspend to idle(freeze)、power-on standby(standb)、suspend to ram(memory;STR)和suspend to disk(hibernate)。分别对应ACPI状态的S0、S1、S3和S4状态。
-
Suspend-To-Idle
此状态包括frozen processes+suspended devices+idle processors,具有轻量化的特点;并且相对于相对于Idle状态能节省更多的功耗,因为此时的用户空间被冻结且I/O设备进入了低功耗状态。相对于Suspend-To-RAM它具有低延时的优势。
-
Power-On Suspend
此状态简称standby状态,包括frozen processes+suspended devices+offline nonboot CPUs+suspend low-level system,对CPU的处理更近一步。所以相对于Suspend-To-Idle节省了更多的功耗,但是由于需要恢复CPU和一些底层功能也花费了更多的时间。 -
Suspend-to-RAM
挂起到内存,简称待机。计算机将目前的运行状态等数据存放在内存,关闭硬盘、外设等设备,进入等待状态。此时内存仍然需要电力维持其数据,但整机耗电很少。恢复时计算机从内存读出数据,回到挂起前的状态,恢复速度较快。对 DDR的耗电情况进行优化是S3性能的关键,大多数手持设备都是用S3待机。此状态下计算机会冻结所有的活动并将当前工作状态保存到RAM中,然后关闭屏幕进入低功耗模式,通常睡眠和唤醒需要几秒。此状态使所有的设备进入低功耗状态,仅保留RAM自刷新。所有的设备和系统状态都保存在RAM中,所有外设被挂起。 -
Suspend-to-disk
此状态是最省功耗的模式,简称休眠。相对Suspend-to-RAM能节省更多功耗的原因是数据会被写入磁盘中,RAM也可以被关闭。但是这也导致了,更多的恢复延时,在resume的时候读回到RAM,然后在进行系统和设备状态恢复工作。把运行状态等数据存放在硬盘上某个文件或者某个特定的区域,关闭硬盘、外设等设备,进入关机状态。此时计算机完全关闭,不耗电。恢复时计算机从休眠文件/分区中读出数据,回到休眠前的状态,恢复速度较慢。
在车载领域中,STR和STD是用到的最多的,尤其是性能和芯片能力足够时,STR是相对较优的低功耗方案,与STD相比STR复归速度更快,省去了像STD一样制作镜像和读取镜像的耗时。
1.3 PM Subsystem
1.3.1 PM接口
1.3.1.1 sys/power/state
代码流程可以先从接口开始看起,在内核代码/kernel/linux/v4.14/kernel/power/main.c这一文件中,提供了用户对电源控制的操作接口。
首先看接口定义:
power_attr(state);
#define power_attr(_name) \
static struct kobj_attribute _name##_attr = {
\
.attr = {
\
.name = __stringify(_name), \
.mode = 0644, \
}, \
.show = _name##_show, \
.store = _name##_store, \
}
根据以上内容,系统通过sysfs创建出.show和.store这两个接口函数。
1. state_show:
state_show函数可以通过命令台命令cat /sys/power/state来查看设备支持的电源状态。
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
#ifdef CONFIG_SUSPEND
suspend_state_t i;
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
if (pm_states[i])
s += sprintf(s,"%s ", pm_states[i]);
#endif
if (hibernation_available())
s += sprintf(s, "disk ");
if (s != buf)
/* convert the last space to a newline */
*(s-1) = '\n';
return (s - buf);
}
2. state_store:
state_store这一函数就是电源状态控制的入口函数,在控制台使用echo [*] > /sys/power/state命令来实现不同的suspend状态。
- echo freeze > /sys/power/state (PM_SUSPEND_TO_IDLE)
- echo standby> /sys/power/state (PM_SUSPEND_STANDBY)
- echo mem> /sys/power/state (PM_SUSPEND_MEM)
- echo disk> /sys/power/state (HIBERNATE)
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
suspend_state_t state;
int error;
error = pm_autosleep_lock();
if (error)
return error;
if (pm_autosleep_state() > PM_SUSPEND_ON) {
error = -EBUSY;
goto out;
}
state = decode_state(buf, n);
if (state < PM_SUSPEND_MAX) {
if (state == PM_SUSPEND_MEM)
state = mem_sleep_current;
error = pm_suspend(state);
} else if (state == PM_SUSPEND_MAX) {
error = hibernate();
} else {
error = -EINVAL;
}
out:
pm_autosleep_unlock();
return error ? error : n;
}
从函数中可以看出,在使用freeze、standby、mem命令时,其调用的处理函数都为pm_suspend()。
而在使用disk命令时,调用的处理函数为hibernate()。
1.3.1.2 sys/power/wakeup_count
这里介绍一下wakeup_count这个节点的机能实现,wakeup_count主要用于记录系统触发的wakeup event个数。
主要接口函数如下:
static ssize_t wakeup_count_show(struct kobject *kobj,
struct kobj_attribute *attr,
char *buf)
{
unsigned int val;
return pm_get_wakeup_count(&val, true) ?
sprintf(buf, "%u\n", val) : -EINTR;
}
static ssize_t wakeup_count_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
unsigned int val;
int error;
error = pm_autosleep_lock();
if (error)
return error;
if (pm_autosleep_state() > PM_SUSPEND_ON) {
error = -EBUSY;
goto out;
}
error = -EINVAL;
if (sscanf(buf, "%u", &val) == 1) {
if (pm_save_wakeup_count(val))
error = n;
else
pm_print_active_wakeup_sources();
}
out:
pm_autosleep_unlock();
return error;
}
power_attr(wakeup_count);
wakeup_count接口向上层提供了两个功能,分别是读和保存wakeup_count值。
wakeup_count将用一个32位值保存(combined_event_count),此32位值的高16位用于存放已经发生的wakeup event次数,低16位用于存放正在运行中的wakeup event个数。
当某个模块在处理事件时,此时又不想被suspend打断,那么这个模块在处理前就会使用pm_stay_awake函数来告诉内核。当使用pm_stay_awake函数以后,wakeup_count的低16位将加1,此时意味着有wakeup event在运行中。
当模块将事件处理好后,会使用pm_relax进行释放,pm_stay_awake和pm_relax都是成对使用的,pm_relax的调用意味着wakeup event处理完成,此时wakeup_count的低16位将减1,而wakeup_count的高16位将加1。即此时没有运行中的wakeup event,已经触发的wakeup event次数为1次。
当上层在使用sys/power/state接口来触发suspend之前,如果对wakeup_count进行了读取并保存,那么suspend过程中将通过pm_wakeup_pending函数来确认suspend流程中是否发生了wakeup event。
bool pm_wakeup_pending(void)
{
unsigned long flags;
bool ret

6455

被折叠的 条评论
为什么被折叠?



