ACPI共有六种状态,分别是S0到S5,它们代表的含义分别是:
S0--实际上这就是我们平常的工作状态,所有设备全开,功耗一般会超过80W;
S1--也称为POS(Power on Suspend),这时除了通过CPU时钟控制器将CPU关闭之外,其他的部件仍然正常工作,这时的功耗一般在30W以下。In this state, no system context is lost (CPU or chip set) and hardware maintains all system context.
S2--这时CPU处于停止运作状态,总线时钟也被关闭,但其余的设备仍然运转。This state is similar to the S1 sleeping state except that the CPU and system cache context is lost
S3--这就是我们熟悉的STR(Suspend to RAM),这时的功耗不超过10W。all system context is lost except system memory. CPU, cache, and chip set context are lost in this state.
S4--也称为STD(Suspend to Disk),这时系统主电源关闭,硬盘存储S4前数据信息,所以S4是比S3更省电状态。It is assumed that the hardware platform has powered off all devices. Platform context is maintained.
S5--这种状态是最干脆的,就是连电源在内的所有设备全部关闭,即关机(shutdown),功耗为0。
linux支持3种ACPI的节电模式:
1. S1 - POS standby, power on standby 显示屏断电,主机通电
2. S3 - STR standby, (supend to ram) 挂起到内存,键盘不能唤醒,需要从电源键唤醒
3. S4 -hibernate (supend to disk)挂起到硬盘,需要从硬盘恢复
可以简化为 sleep 分为standby 和mem, hibernate即disk分为shutdown和platform(shutdown将系统状态保存到磁盘,BIOS关闭计算机;platform同时点亮挂起指示灯)
For device driver, linux takes S1/S3 exactly the same. The difference is in linux kernel, but NOT the driver. The kernel does different things for S1 and S3.
cat /sys/power/state 检查内核支持哪些节电模式,有standby,mem,disk等
linux 设备模型中一条就是为了电源管理和系统管理,能让系统以特定的顺便遍历硬件。
linux中休眠主要做三件事情:冻结用户进程和内核任务;调用注册的设备的suspend回调函数;休眠核心设备和CPU
# echo standby > /sys/power/state
用户对于/sys/power/state 的读写会调用到main.c中的state_store(),
1. 同步文件系统
2. 关掉用户态的helper进程,并调用suspend_freeze_processes()冻结所有的进程
3. 调用suspend_devices_and_enter()休眠所有的外设。在这个函数中, 先对于dpm_list(device_add中调用device_pm_add时添加)中的每个设备调用dpm_prepare;然后在dpm_suspend()中对于dpm_list中所有的设备调用device_suspend()。device_suspend依次调用class->pm, type->pm, bus->pm。譬如pci总线,bus->pm是pci_bus_type的pci_pm_suspend。这个函数判定如果legacy pci的话(即在pci_driver中指定了suspend、suspend_late、resume、resume_early等)则调用pci_legacy_suspend,会由dev找到pci_dev,然后找到pci_drvier,调用其suspend(即在register_pci_driver中的参数);如果非legacy&(!pm),则pci_disable_enabled_device(写入非master);如果非legacy并且driver->pm不为NULL,则调用driver->pm接口(并不调用driver->suspend)。
4. 调用dpm_suspend_enter。禁止所有的irq,对于dmp_list中的设备依照反序调用bus->pm->suspend_noirq,禁用没启用的CPU,sysdev_suspend,suspend_ops->enter(state)(要么acpi_suspend_ops_old,要么acpi_suspend_ops)。
resume 的过程刚好是反向过程。
因为所做的项目用到了多处kernel thread,在处理driver的时候要特别注意。默认情况下,所有的kernel thread并不能freeze(用户态的都可以),只有显示调用了set_freezable的才可以(去掉PF_NOFREEZE标志,但是不能重新设置PF_NOFREEZE标志)。kernel thread通过调用try_to_freeze进入睡眠(或者通过调用wait_event_freezable来调用try_to_freeze),如果try_to_freeze返回error,则整个hibernation过程失败。