Chinaunix首页 | 论坛 | 博客
  • 博客访问: 345673
  • 博文数量: 110
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 859
  • 用 户 组: 普通用户
  • 注册时间: 2018-10-15 14:13
个人简介

搭建一个和linux开发者知识共享和学习的平台

文章分类

全部博文(110)

文章存档

2025年(9)

2024年(15)

2023年(24)

2022年(27)

2019年(8)

2018年(27)

分类: 嵌入式

2025-01-24 14:16:04

睡眠也叫做Suspend to RAM(STR),把系统的状态信息保存到内存,内存供电,其他断电,在内核中睡眠也称作Suspend

休眠(Hibernate)也叫做Suspend to Disk,把系统的状态信息保存到磁盘,系统都断电。

系统无论睡眠还是休眠,都可以被唤醒。对于睡眠来说很多外设都可以唤醒整个系统,比如键盘。对于休眠来说,就只有电源按钮能唤醒系统了。休眠一方面和睡眠比较像,都保存了系统的状态信息,一方面又和关机比较像,整个系统都断电了。


系统支持的休眠方式,可以使用想下面命令查看:
cat /sys/power/state

该节点用于将系统置于指定的电源状态(freeze,standbymemdisk),有些系统是不会全部有的,一般会有其中一种或者几种。 用户空间往该文件写入特定的电源状态字符串,将会把系统置为该模式,这几种状态的解释如下:

  • freeze: 冻结所有的进程,包括用户空间进程及内核线程,CPU进入IDLE态

  • standby: 类似mem,只是standby耗电更多一些,返回到正常工作方式时间更短一些而已

  • mem: 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢

  • disk: 这个操作会将运行时的context保存在Disk这种非易失的存储器中,然后进行掉电操作,就是STD(Suspend-to-Disk)。比如当按下电源键进行唤醒时,然后恢复,唤醒过程{BANNED}最佳慢。


串口下敲入以下命令则进入对应的休眠方式
echo "freeze" > /sys/power/state
echo "standby" > /sys/power/state
echo "mem" > /sys/power/state
echo "disk" > /sys/power/state

内核中Suspend功能有关的代码包括PM coreDevice PMPlatform PM等几大块,具体如下:

1)PM Core


kernel/power/main.c----提供用户空间接口(/sys/power/state)

kernel/power/suspend.c----Suspend功能的主逻辑

kernel/power/suspend_test.c----Suspend功能的测试逻辑

kernel/power/console.c----Suspend过程中对控制台的处理逻辑

kernel/power/process.c----Suspend过程中对进程的处理逻辑


2)Device PM

driver/xxx.c  ---提供platform driver的suspend,resume成员接口

3)Platform dependent PM

include/linux/suspend.h----定义platform dependent PM有关的操作函数集
arch/xxx/mach-xxx/xxx.c或者
arch/xxx/plat-xxx/xxx.c----平台相关的电源管理操作

用于设备驱动下电源管理ops结构体
file: include/linux/pm.h
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);//运行空闲
};

用于管理平台相关系统睡眠状态的ops结构体
file: include/linux/suspend.h
struct platform_suspend_ops {
     int (*valid)(suspend_state_t state); //该状态休眠方式是否有效
     int (*begin)(suspend_state_t state);//该状态休眠开始
     int (*prepare)(void); //休眠/唤醒准备
     int (*prepare_late)(void); //休眠/唤醒后期准备
     int (*enter)(suspend_state_t state); //该状态进入
     void (*wake)(void);   //平台唤醒
     void (*finish)(void); //平台唤醒完成
     bool (*suspend_again)(void); 
     void (*end)(void); 
     void (*recover)(void);
};

系统初始化的时候,调用 pm_init,主要做了下面的事情
pm_init (kernel/power/main.c)
 pm_states_init() (kernel/power/supend.c)  //主要是让mem和freeze出现在/sys/power/state
  pm_states[PM_SUSPEND_MEM] = pm_labels[PM_SUSPEND_MEM];
  pm_states[PM_SUSPEND_TO_IDLE] = pm_labels[PM_SUSPEND_TO_IDLE];
power_kobj = kobject_create_and_add("power"NULL);    //创建/sys/power目录
sysfs_create_groups(power_kobj, attr_groups);       //创建/sys/power/state等节点
 pm_autosleep_init()  (kernel/power/autosleep.c) //注册autosleep唤醒源

core_initcall(pm_init);

pm_suspend代码实现调用流程总结做了四件事情:

1、判断该平台是否支持该状态睡眠

2、挂起冻结线程

3、调用 pm 通知链,发送 PM_POST_SUSPEND 消息

4、休眠设备以及系统相关的操作

判断该平台是否支持该状态睡眠


需要内核使用 platform_suspend_ops 来定义各个平台的 pm 实现,然后通过 suspend_set_ops 函数设置具体平台pm到 suspend_ops 中。{BANNED}最佳终还是通过 vaild 函数来判断该平台是否支持需要睡眠的状态。

suspend_freeze_processes的代码实现中总结主要做了三件事情

1、冻结用户任务进程

2、冻结内核线程

3、冻结内核线程失败的话需要解冻用户任务线程, 唤醒到正常状态

调用pm通知链,发送 PM_POST_SUSPEND消息



suspend_devices_and_enter代码中看到主要做了三件事情

1、挂起 console

2、调用所有设备的休眠回调函数

3、使系统进入给定的睡眠状态

挂起 console



遍历链表 dpm_list 成员如果非空的话,就调用 device_prepare , 然后依次判断设备有无 pm_domain 再者有无 type->pm 再者有无 class->pm 再者有无 bus->pm 调用驱动程序电源管理里的 prepare 函数,接着判断有无 driver->pm 调用驱动程序电源管理里的 prepare

使系统进入给定的睡眠状态

suspend_enter的代码的上半部是真正进入系统休眠状态, 总结了下一共主要做了八件事情:

1、调用各平台休眠前准备工作

2、调用所有设备的{BANNED}最佳后休眠的函数

3、执行平台 suspend_ops 上的 suspend 函数

4、disable 所有设备外设的中断线,进入 noirq 阶段

5、调用平台准备 noirq 的函数

6、关非启动 cpu

7、关中断,即CPU不再响应中断

8、执行注册在 syscore_ops_list 上的 syscore_ops 的 suspend

resume_enter的代码下半部真正进入系统唤醒状态, 总结了下一共主要做了八件事情:

1、执行注册在 syscore_ops_list 上的 syscore_ops 的 resume

2、开中断,即CPU能响应中断

3、开非启动 cpu

4、执行平台 suspend_ops 上的 wake 函数

5、遍历 dpm_noirq_list 链表的节点,调用设备早期唤醒的 irq 函数

6、调用平台早期唤醒函数

7、遍历 dpm_late_early_list 链表的节点,调用设备早期唤醒函数

8、执行平台 suspend_ops 上的 finish 函数,完成唤醒工作

阅读(141) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~