Home  >  Article  >  System Tutorial  >  In-depth discussion of the implementation principles and related technologies of Linux Kernel suspend/resume process

In-depth discussion of the implementation principles and related technologies of Linux Kernel suspend/resume process

WBOY
WBOYforward
2024-02-13 15:45:25614browse

In the Linux kernel, the suspend/resume process is a very important process. It can realize system sleep and wake-up, and improve the system's energy efficiency and response speed. In this article, we will delve into the implementation principles and related technologies of the Linux Kernel suspend/resume process.

深入探讨Linux Kernel suspend/resume 过程的实现原理和相关技术

Hibernation/wakeup is a very important part in embedded Linux. Embedded devices enter sleep state as much as possible to extend battery life. This article will introduce in detail how sleep/wakeup works in Linux

Reference article: Author: zhangjiejing Date: 2010-04-07, http://www.thinksrc.com

My linux kernel version: 3.0.31

A brief introduction to hibernation

In Linux, hibernation is mainly divided into three main steps:

1. Freeze user-mode processes and kernel-mode tasks

2. Call the suspend callback function of the registered device

3. The order is according to the registration order

Hibernate core devices and put the CPU into hibernation. Freezing processes means that the kernel sets the status of all processes in the process list to stopped and saves the context of all processes. When these processes are unfrozen, they do not know If it has been frozen, it simply continues to execute. How to make Linux enter hibernation? Users can control the system to enter hibernation by reading and writing the sys file /sys /power/state. For example,

# echo mem > /sys/power/state

Command the system to enter hibernation. You can also use

# cat /sys/power/state

To find out which sleep modes the kernel supports.

Linux Suspend process

Related documents:

You can get the source code by visiting the Linux kernel website. The following is the path to the file:

kernel/kernel/power/main.c

kernel/kernel/power/suspend.c

kernel/driver/base/power/main.c

Let’s take a detailed look at how Linux sleeps/wakes up. Let ‘s going to see how these happens.

Users' reading and writing of /sys/power/state will call state_store() in main.c. Users can write strings defined in const char * const pm_state[], such as "mem", "standby" ”.Of course it is generally controlled by the suspend and resume buttons

Then state_store() will call enter_state(), which will first check some state parameters and then synchronize the file system. The following is the code:

1. /** 
2.  \* enter_state - Do common work of entering low-power state. 
3.  \* @state:   pm_state structure for state we're entering. 
4.  \* 
5.  \* Make sure we're the only ones trying to enter a sleep state. Fail 
6.  \* if someone has beat us to it, since we don't want anything weird to 
7.  \* happen when we wake up. 
8.  \* Then, do the setup for suspend, enter the state, and cleaup (after 
9.  \* we've woken up). 
10.  */ 
11. int enter_state(suspend_state_t state) 
12. { 
13.   int error; 
14.  
15.   if (!valid_state(state)) 
16. ​    return -ENODEV; 
17.  
18.   if (!mutex_trylock(&pm_mutex)) 
19. ​    return -EBUSY; 
20.  
21.   printk(KERN_INFO "PM: Syncing filesystems ... "); 
22.   sys_sync(); 
23.   printk("done.\n"); 
24.  
25.   pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 
26.   error = suspend_prepare(); 
27.   if (error) 
28. ​    goto Unlock; 
29.  
30.   if (suspend_test(TEST_FREEZER)) 
31. ​    goto Finish; 
32.  
33.   pr_debug("PM: Entering %s sleep\n", pm_states[state]); 
34.   pm_restrict_gfp_mask(); 
35.   error = suspend_devices_and_enter(state); 
36.   pm_restore_gfp_mask(); 
37.  
38.  Finish: 
39.   pr_debug("PM: Finishing wakeup.\n"); 
40.   suspend_finish(); 
41.  Unlock: 
42.   mutex_unlock(&pm_mutex); 
43.   return error; 
44. } 

 

Prepare, freeze process

After entering suspend_prepare(), it will allocate a virtual terminal to suspend to output information, then broadcast a Notify that the system wants to enter suspend, close the user-mode helper process, and then call suspend_freeze_processes() in sequence to freeze all process, the current status of all processes will be saved here. There may be some processes that refuse to enter the frozen state. When such processes exist, freezing will fail. This function will give up the frozen process and unfreeze all the processes that were just frozen. process.

1. /** 
2.  \* suspend_prepare - Do prep work before entering low-power state. 
3.  \* 
4.  \* This is common code that is called for each state that we're entering. 
5.  \* Run suspend notifiers, allocate a console and stop all processes. 
6.  */ 
7. static int suspend_prepare(void) 
8. { 
9.   int error; 
10.  
11.   if (!suspend_ops || !suspend_ops-**>**enter) 
12. ​    return -EPERM; 
13.  
14.   pm_prepare_console(); 
15.  
16.   error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); 
17.   if (error) 
18. ​    goto Finish; 
19.  
20.   error = usermodehelper_disable(); 
21.   if (error) 
22. ​    goto Finish; 
23.  
24.   error = suspend_freeze_processes(); 
25.   if (!error) 
26. ​    return 0; 
27.  
28.   suspend_thaw_processes(); 
29.   usermodehelper_enable(); 
30.  Finish: 
31.   pm_notifier_call_chain(PM_POST_SUSPEND); 
32.   pm_restore_console(); 
33.   return error; 
34. } 

Put peripherals to sleep

Now, all processes (including workqueue/kthread) have stopped. Kernel mode characters may hold some semaphores when stopped, so if you unlock the semaphore in the peripheral at this time, it may A deadlock occurs, so you must be very careful when locking/unlocking in the peripheral's suspend() function. It is recommended not to wait for the lock in suspend() when designing. And because when suspending, some Logs cannot be output. , so once a problem occurs, it is very difficult to debug.

Then the kernel will try to release some memory here.

Finally, suspend_devices_and_enter() will be called to put all peripherals to sleep. In this function, if the platform registers suspend_pos (usually defined and registered in the board-level definition), suspend_ops->begin() will be called here. , then device_suspend()->dpm_suspend() in driver/base/power/main.c will be called, and they will call the driver's suspend() callback in turn to sleep all devices.

When all devices go to sleep, suspend_ops->prepare() will be called. This function usually does some preparation work to put the board into sleep. Next, in Linux, the non-starting CPU in a multi-core CPU will be Turn it off. As you can see from the comments, it is to prevent these other CPUs from causing race condion. From now on, only one CPU will be running.

suspend_ops is a board-level power management operation, usually registered in the file arch/xxx/mach-xxx/pm.c.

Next, suspend_enter() will be called. This function will close the arch irq, call device_power_down(), and it will call the suspend_late() function. This function is the last function called when the system actually enters sleep. It is usually called in this function. Make a final check. If the check is OK, then sleep all system devices and buses, and call suspend_pos->enter() to put the CPU into a power-saving state. At this time, it is already sleeping. The execution of the code is Stopped here

1. /** 
2.  \* suspend_devices_and_enter - suspend devices and enter the desired system 
3.  \*         sleep state. 
4.  \* @state:    state to enter 
5.  */ 
6. int suspend_devices_and_enter(suspend_state_t state) 
7. { 
8.   int error; 
9.  
10.   if (!suspend_ops) 
11. ​    return -ENOSYS; 
12.  
13.   trace_machine_suspend(state); 
14.   if (suspend_ops-**>**begin) { 
15. ​    error = suspend_ops-**>**begin(state); 
16. ​    if (error) 
17. ​      goto Close; 
18.   } 
19.   suspend_console(); 
20.   suspend_test_start(); 
21.   error = dpm_suspend_start(PMSG_SUSPEND); 
22.   if (error) { 
23. ​    printk(KERN_ERR "PM: Some devices failed to suspend\n"); 
24. ​    goto Recover_platform; 
25.   } 
26.   suspend_test_finish("suspend devices"); 
27.   if (suspend_test(TEST_DEVICES)) 
28. ​    goto Recover_platform; 
29.  
30.   error = suspend_enter(state); 
31.  
32.  Resume_devices: 
33.   suspend_test_start(); 
34.   dpm_resume_end(PMSG_RESUME); 
35.   suspend_test_finish("resume devices"); 
36.   resume_console(); 
37.  Close: 
38.   if (suspend_ops-**>**end) 
39. ​    suspend_ops-**>**end(); 
40.   trace_machine_suspend(PWR_EVENT_EXIT); 
41.   return error; 
42.  
43.  Recover_platform: 
44.   if (suspend_ops-**>**recover) 
45. ​    suspend_ops-**>**recover(); 
46.   goto Resume_devices; 
47. } 

RESUME

如果在休眠中系统被中断或者其他事件唤醒, 接下来的代码就会开始执行, 这个 唤醒的顺序是和休眠的循序相反的,所以系统设备和总线会首先唤醒,使能系统中 断, 使能休眠时候停止掉的非启动CPU, 以及调用suspend_ops->finish(), 而且 在suspend_devices_and_enter()函数中也会继续唤醒每个设备,使能虚拟终端, 最后调用 suspend_ops->end().

在返回到enter_state()函数中的, 当 suspend_devices_and_enter() 返回以后, 外设已经唤醒了, 但是进程和任务都还是冻结状态, 这里会调用suspend_finish()来解冻这些进程和任务, 而且发出Notify来表示系统已经从suspend状态退出, 唤醒终端.

到这里, 所有的休眠和唤醒就已经完毕了, 系统继续运行了.

总之,suspend/resume过程是Linux内核中不可或缺的一部分。它可以实现系统的休眠和唤醒,提高系统的能效和响应速度。希望本文能够帮助读者更好地理解Linux Kernel suspend/resume 过程的实现原理和相关技术。

The above is the detailed content of In-depth discussion of the implementation principles and related technologies of Linux Kernel suspend/resume process. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:lxlinux.net. If there is any infringement, please contact admin@php.cn delete