linux休眠-电源管理过程梳理

概述

由于嵌入式设备自身的特点,设备运行功耗问题一直是产品设计首先要考虑的问题,尤其对于非长电设备。
本文主要讲述linux内核(2.6+),设备、系统休眠过程,理解的内核休眠过程,才能够更好的增加产品外设休眠逻辑和硬件平台休眠模块。

其主要分为以下几个方面:
1、soc电源管理,位于平台代码中,一般由厂家提供
2、外设电源管理,位于外设驱动中,按需增加接口
3、linux电源管理核心框架

以下分别进行描述

注册平台电源管理接口

一般位于arch/soc/pm*.c中,通过suspend_set_ops注册

static const struct platform_suspend_ops xxxx_pm_ops = {
	.valid		= xxxx_pm_valid,
	.begin		= xxxx_pm_begin,
	.enter		= xxxx_pm_enter,
	.end		= xxxx_pm_end,
	.prepare	= xxxx_suspend_prepare,
	.finish		= xxxx_suspend_finish,
};
static int __init pm_init(void)
{
	suspend_set_ops(&xxxx_pm_ops);
	return 0;
}

suspend_set_ops过程如下:

kernel/power/suspend.c
	suspend_set_ops(const struct platform_suspend_ops *ops)
	    // 将ops赋给全局suspend_ops,用于获取平台pm_ops回调接口
		suspend_ops = ops;
		// 初始化内核支持的休眠模式,即cat /sys/power/state得到的内容
		pm_states[i] = pm_labels[j++];

注册外设驱动电源管理接口

外设驱动通过struct device_driver.pm将外设电源管理接口注册到内核中,具体如下:
1、外设驱动中实现struct device_driver.pm接口

static const struct dev_pm_ops xxxx_sdmmc_pm_ops = {
    .suspend    = xxxx_sdmmc_suspend,
    .resume        = xxxx_sdmmc_resume,
};

2、注册设备

device_register
    //初始化device结构体
	device_initialize
		device_pm_init(dev);
			// 初始化struct device.power结构体
			device_pm_sleep_init
			    // 创建了dev->power.entry列表
			    device_pm_sleep_init
	device_add
		device_pm_add(dev);
			// 将上面创建的dev->power.entry加入到dpm_list中,即将该device加入电源管理
			list_add_tail(&dev->power.entry, &dpm_list);	

dpm_list是内核中用于设备电源管理的链表,如果该列表中存在某个外设,则调用外设的pm相关接口,进行休眠操作

linux内核休眠整体过程

上面讲到将各个pm注册到内核的过程,那么何时调用,如何执行上述pm接口呢?
以echo mem > /sys/power/state,休眠设备为例,具体过程如下:

kernel/power/main.c
	state_store
	    //解析传入的"mem"
		decode_state(buf, n);
		// 挂起系统
		pm_suspend
			enter_state
			    // 同步磁盘
				sys_sync
				suspend_prepare
					// 挂起进程和内核线程
					suspend_freeze_processes
				suspend_devices_and_enter
					// 进入平台代码中pm.c注册的ops.begin中
					platform_suspend_begin
					// 挂起控制台
					suspend_console
					// 挂起外设
					dpm_suspend_start
						// 执行device_driver.pm.prepare,即设备挂起前的准备工作
						dpm_prepare
							//判断device是否加入dpm_list中了
							while (!list_empty(&dpm_list)) {
								struct device *dev = to_device(dpm_list.next);
									return container_of(entry, struct device, power.entry);
							//如果加入了,则执行device.driver.pm.prepare						
							device_prepare
								callback = dev->driver->pm->prepare;
								if (callback)
									ret = callback(dev);		
						// 挂起外设						
						dpm_suspend	
							//遍历所有设备
							while (!list_empty(&dpm_prepared_list)) {
							device_suspend
								__device_suspend
									//根据state得到driver.pm.suspend
									callback = pm_op(dev->driver->pm, state);
									// 调用driver.pm.suspend
									dpm_run_callback(callback, dev, state, info);
							//打印“PM: suspend of devices complete after” ,标志所有device suspend结束
							dpm_show_time(starttime, state, NULL);
					//函数在设备挂起之后调用,用于挂起系统
					suspend_enter
						// 执行平台pm.prepare
						platform_suspend_prepare
						// 执行设备的suspend_late,然后又将这些设备加入到dpm_late_early_list链表中。如果出现失败,则跳到platform_finish做恢复工作。
						dpm_suspend_late
						// 执行平台的prepare_late,做最后的准备工作
						platform_suspend_prepare_noirq(state);
						// 关闭非boot cpu(first cpu)
						disable_nonboot_cpus
						// 关中断
						arch_suspend_disable_irqs
						// 执行所有系统的suspend接口
						syscore_suspend
						// 执行平台的pm.enter接口
						suspend_ops->enter
  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值