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

linux休眠-电源管理过程梳理 阿帅 2024-01-25 15:19:06 729

概述

由于嵌入式设备自身的特点,设备运行功耗问题一直是产品设计首先要考虑的问题,尤其对于非长电设备。
本文主要讲述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
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
阿帅
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
阿帅
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区