系统待机唤醒功能
1 说明背景
1.1 需求
支持 GPU 进入低功耗模式,让用户选择降低设备的功耗
1.2 概念
上位词:APM, ACPI
同类词:睡眠模式, S0~S5
下位词:系统挂起, 系统唤醒, 运行时设备电源管理
1)ACPI
在计算机中,高级配置和电源接口(ACPI)提供了一个开放标准,操作系统可以使用该标准来发现和配置计算机硬件组件,执行电源管理(例如将未使用的硬件组件休眠),执行自动配置(例如即插即用和热插拔),并执行状态监控。and to perform status monitoring.
ACPI是一个标准化的接口规范,其中有对电源管理规范的部分; APM是与之相对的另一项电源管理技术。相比APM,ACPI更加智能。
2)电源管理
- CPU 在运行时根据系统负载进行动态电压和频率变换的 CPUFreq。
- CPU 在系统空闲时根据空闲的情况进行低功耗模式的 CPUIdle。
- 多核系统下 CPU 的热插拔支持。
- 系统和设备针对延迟的特别需求而提出申请的 PM QoS,它会作用于 CPUIdle 的具体策略。
- 设备驱动针对系统挂起到 RAM/DISK 的一系列入口函数。
- SoC 进入挂起状态,SDRAM 自刷新的入口。
- 设备的运行时动态电源管理,根据使用情况动态开关设备。
- 底层的时钟、稳压器、频率/电压表(OPP模块完成)支撑,各驱动子系统都可能用到。
3) S3/S4 模式
- S3:待机到内存,即内存之外把其他设备都进入低功耗模式,对应 ACPI state S3
- S4:待机到硬盘,即休眠,把电脑的当前状态保存到硬盘,几乎不消耗外部电源,对应 ACPI state S4
4)驱动支持 S3
关键流程:即将系统的状态保存于内存中,并将 SDRAM置于自刷新状态,待用户按键等操作后再重新恢复系统。
2 调研阶段
2.1 系统操作接口
// file: include/linux/pm.h
// struct device_driver {
struct dev_pm_ops {
int (*prepare)(struct device *dev);
void (*complete)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*freeze)(struct device *dev);
int (*thaw)(struct device *dev);
int (*poweroff)(struct device *dev);
int (*restore)(struct device *dev);
int (*suspend_late)(struct device *dev);
int (*resume_early)(struct device *dev);
int (*freeze_late)(struct device *dev);
int (*thaw_early)(struct device *dev);
int (*poweroff_late)(struct device *dev);
int (*restore_early)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
int (*freeze_noirq)(struct device *dev);
int (*thaw_noirq)(struct device *dev);
int (*poweroff_noirq)(struct device *dev);
int (*restore_noirq)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
};
2.2 完整系统流程
2.3 驱动接口注册
1)注册接口: 到driver的pm成员
/* amdgpu DRIVER */
static const struct dev_pm_ops amdgpu_pm_ops = {
.suspend = amdgpu_pmops_suspend, // 2
.resume = amdgpu_pmops_resume, // 3
....
};
static struct pci_driver amdgpu_kms_pci_driver = {
....
.driver.pm = &amdgpu_pm_ops, // 1
};
2)实现接口: 挂起和恢复
static int amdgpu_pmops_suspend(struct device *dev)
{
....
}
static int amdgpu_pmops_resume(struct device *dev)====
{
....
}
2.4 系统执行过程
0)挂起事件入口,执行程序
// 挂起流程
// file: kernel/power/main.c
state_store
pm_suspend(state);
enter_state(state);
suspend_devices_and_enter(state); // 包含挂起和恢复的所有执行
dpm_suspend_start(PMSG_SUSPEND); // 1
suspend_enter(state, &wakeup); // 2
// 唤醒流程
// file: drivers/input/apm-power.c
apmpower_event
system_power_event(code);
apm_queue_event(APM_USER_SUSPEND);
- 系统挂起流程,分为四个阶段(
prepare
,suspend
,suspend_late
,suspend_noirq
)。参考文档 - 设备挂起顺序,按照自下而上的顺序执行设备挂起; 按照自上而下的顺序恢复这些设备。参考文档
2.5 驱动执行过程
- 接口注册流程:函数
amdgpu_pmops_suspend
通过struct dev_pm_ops
对象amdgpu_pm_ops
完成注册到struct pci_driver
对象amdgpu_kms_pci_driver
的.driver.pm.suspend
接口。 - 设备挂起流程:函数
amdgpu_pmops_suspend
调用amdgpu_device_suspend(drm_dev, true, true);
完成amdgpu设备的挂起功能。 - 设备恢复流程:N/A
3 开发阶段: 前提条件
大前提:在对amdgpu驱动进行开发和测试之前,确保系统在无amdgpu驱动的情况下是可用的。内核文档
sudo su
# 方法一
rtcwake -s 30 -m mem # S3
rtcwake -s 30 -m disk # S4
# 方法二
echo mem > /sys/power/state # S3
echo disk > /sys/power/state # S4
References
- Advanced Configuration and Power Interface - Wikipedia
- Debugging hibernation and suspend
- PCI Power Management
- Generic PM之Suspend功能 - wowo
- Generic PM之基本概念和软件架构
- Hibernate功能
- 《Linux设备驱动开发详解:基于最新的Linux4.0内核》
- S3待机 S4休眠 - pycod