Linux电源管理<系统休眠唤醒之 reboot>

PM-RPM Linux电源管理

如果能在保证系统运行的基础上,尽量节省对能量的消耗,就会大大提升该系统的生存竞争力

通俗的说就是: 只有在让系统跑的时候,我们才会给他上电,这就是电源管理的核心思想。

  1. 实时的关闭暂时不使用的部分(可称做“工作状态到非工作状态的转移”)。 例如手机在口袋时,屏幕没必要亮
  2. 当需要重新使用那些已关闭部分时(可称作"非工作状态到工作状态的转移"), 不能有太长时间的等待,且转移过程不能消耗太多的能量。

一般系统可以通过降低运行时钟,有空闲(少做事情),有休眠可以保证能量的节省消耗,比如单片机就有对应的低速模式,空闲模式和掉电模式,

对于linux而言休眠唤醒的大致流程可分为如下:

休眠:

  1. 暂停app(用户app, 内核线程)
  2. 暂停各类设备
  3. 停止cpu

唤醒:

  1. 启动cpu
  2. 启动各类设备
  3. 启动app

Linux电源管理分为系统睡眠模型和Runtime电源管理模型

系统休眠模型:把整个系统陷入休眠

- On(on) S0 - Working

- Standby (standby) S1 - CPU and RAM are powered but not executed 类似空闲模式

- Suspend to RAM(mem) S3 - RAM is powered and the running content is saved to RAM

- Suspend to Disk,Hibernation(disk) S4 - All content is saved to Disk and power down
Hibernation(冬眠,会关闭整个系统的供电,如果想醒来只能通过按power键)

STR/STD: 称为睡眠,并不会关闭所有的供电,通常会保留某些重要设备的供电(如键盘),那样,这些设备就可以唤醒系统

win: 睡眠–> suspend to ram , 休眠–>suspend to disk

ubuntu: suspend --> standby , hibernate – > suspend to disk

S3 aka STR(suspend to ram),挂起到内存,简称待机。计算机将目前的运行状态等数据存放在内存,关闭硬盘、外设等设备,进入等待状态。此时内存仍然需要电力维持其数据,但整机耗电很少。恢复时计算机从内存读出数据,回到挂起前的状态,恢复速度较快。对DDR的耗电情况进行优化是S3性能的关键,大多数手持设备都是用S3待机。

S4 aka STD(suspend to disk),挂起到硬盘,简称休眠。把运行状态等数据存放在硬盘上某个文件或者某个特定的区域,关闭硬盘、外设等设备,进入关机状态。此时计算机完全关闭,不耗电。恢复时计算机从休眠文件/分区中读出数据,回到休眠前的状态,恢复速度较慢。

Runtime 电源管理模型

在上面的On状态下如何省电

  1. 可以降低运行时钟
  2. 关闭无用的设备

对于Linux电源管理,我们主要重点关注如下四个方面:

从功能上分为:

  1. linux电源管理框架
  2. 具体设备的电源管理(驱动)

从策略来看:

  1. APP决定如何进行电源管理

从设计来看:

  1. 如何设计硬件的供电系统,如何去写软件
linux系统suspend的实现
启动suspend to ram:

echo  ram/disk > /sys/power/state

_______________________________________________________________________________________________

state_store (kernel/power/main.c)pm_suspend  (kernel/power/suspend.c)enter_state  (kernel/power/suspend.c)suspend_prepare  (kernel/power/suspend.c)pm_prepare_console  (kernel/power/console.c)

​				__pm_notifier_call_chain   //通知所有关心“休眠消息”的驱动程序

​				suspend_freeze_processes  //冻结app和内核线程

   	 	suspend_devices_and_enter   //让设备进入休眠状态

​				platform_suspend_begin  //如果平台相关的代码有整个begin函数,就调用这个, 这里4.88内核只有acpi支持freeze_ops暂不讨论

​				suspend_console   //停止控制台

​				dpm_suspend_start   (drviers/base/power/main.c)

​					dpm_prepare

​						对于dpm_list的每一个设备,都调用device_prepare, 对于该设备,调用它的

​						dev->pm_domain->ops.prepare;	或

​						dev->type->pm->prepare;   或

​						dev->class->pm->prepare;   或

​						dev->bus->pm->prepare;   或

​						dev->driver->pm->prepare;

​					dpm_suspend

​						对于dpm_prepare_list的每一个设备,都调用device_suspend, 对于该设备,调用它的

​						dev->pm_domain->ops.suspend;	或

​						dev->type->pm->suspend;   或

​						dev->class->pm->suspend;   或

​						dev->bus->pm->suspend;   或

​						dev->driver->pm->suspend;

​				suspend_enter

​					platform_suspend_prepare 如果有提供prepare函数,就调用

​					dpm_suspend_late

​							对于dpm_suspend_list的每一个设备,都调用device_suspend, 对于该设备,调用它的

​							dev->pm_domain->ops.suspend_late;	或

​							dev->type->pm->suspend_late;   或

​							dev->class->pm->suspend_late;   或

​							dev->bus->pm->suspend_late;   或

​							dev->driver->pm->suspend_late;

​					dpm_suspend_noirq

​						对于dpm_late_early_list的每一个设备,都调用device_suspend, 对于该设备,调用它的

​							dev->pm_domain->ops.suspend_noirq;	或

​							dev->type->pm->suspend_noirq;   或

​							dev->class->pm->suspend_noirq;   或

​							dev->bus->pm->suspend_noirq;   或

​							dev->driver->pm->suspend_noirq;

​					platform_suspend_prepare_noirq

​					disable_nonboot_cpus  : 只有一个主cpu, 把其他的cpu关掉

​					arch_suspend_disable_irqs  关闭中断

​					syscore_suspend   关闭核心模块

​					suspend_ops->enter(state);   真正的进入休眠

​						...... 需要设置唤醒源

​						pm_cpu_prepare  ---> s3c2410_pm_prepare

​						S3C2410_GSTATUS3 = s3c_cpu_resume

​						cpu_suspend: --->最后执行s3c2440_pm_suspend

​						......

​						以上是休眠过程:

==================================================

​						下面开始唤醒:

​						按键,导致uboot运行,读取S3C2410_GSTATUS3 ,执行s3c_cpu_resume

​						......

​						s3c_pm_restore_core

​					syscore_resume  开启核心模块

​					arch_suspend_enable_irqs   开中断

​					enable_nonboot_cpus   开启cpu

​					platform_resume_noirq  --》 调用suspend_ops->wake

​					dpm_resume_noirq

​							对于dpm_noirq_list链表中的每一个device, 都执行

​							dev->pm_domain->ops.suspend_noirq;	或

​							dev->type->pm->resume_noirq;   或

​							dev->class->pm->resume_noirq;   或

​							dev->bus->pm->resume_noirq;   或

​							dev->driver->pm->resume_noirq;

​					dpm_resume_early

​							对于dpm_late_early_list链表中的每一个device, 都执行

​							dev->pm_domain->ops.resume_early;	或

​							dev->type->pm->resume_early;   或

​							dev->class->pm->resume_early;   或

​							dev->bus->pm->resume_early;   或

​							dev->driver->pm->resume_early;

​					platform_resume_finish

​			dpm_resume_end

​			resume_console

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

驱动程序里相关的电源管理函数的调用过程:

休眠: prepare->suspend->suspend_late->suspend_noirq

唤醒: resume_noirq->resume_early->resume->complete

  • linux电源管理的组成

电源管理在linux kernel中是一个庞大的子系统,涉及到供电(Power Supply), 充电(Charger), 时钟(Clock), 频率(Frequency), 电压(Voltage), 睡眠/唤醒(Suspend/Resume)等方方面面.

在这里插入图片描述

在对图片中的这些组件(也可以称作Framework)进行描述之前,先在这里了解一下基本概念:

注二: Framework是一个中间层的软件,提供软件开发的流程,其目的有三: 一是屏蔽具体的实现细节,固定对上的接口,这样可以方便上层软件的开发和维护。 二是尽可能抽象公共逻辑,并在Framework内实现, 以提高重用性,减少开发量; 三是向下层提供一系列回调函数, 下层软件可能面对差别较大的现实,但只要填充这些回调函数,即可完成所有逻辑,减小了开发难度。

  • Power supply, 是一个供用户空间程序监控系统的供电状态(电池供电,usb供电,AC供电等等)的class。 通俗的讲,它是一个battery & charger驱动的Framework。
  • Regulator Framework, Voltage/Current Regulator驱动的Framework。 该驱动用于调节Cpu等模块的电压和电流值
  • Dynamic Tick/Clock event, 在传统的Linux Kernel中,系统Tick是固定周期的(比如10ms)一个,因此每隔一个Tick, 就会产生一个Timer中断。 这会唤醒处于idle或者sleep状态的cpu, 而很多时候这种唤醒是没有意义的。 因此新的kernel就产生了Dynamic Tick的概念, Tick不再是周期性的, 而是根据系统的中定时器的情况,不规律的产生,这样可以减少很多无用的Timer中断
  • CPU idle, 用于控制CPU idle状态的frame work
  • Generic PM传统意义上的Power Management, 如power off, Suspend to RAM, Suspend to Disk, Hibernate等
  • Runtime Pm and wacklock, 运行时的Power Management,不再需要用户程序的干涉, 由内核统一调度,实时的关闭或打开设备, 以便在使用性能和省电性能之间找到最佳的平衡
    • Runtime PM是linux kernel亲生的运行时电源管理机制, Wakelock是由Android 提出的机制。 这两种机制的目的是一样的, 因此只需要支持一种即可。
  • Cpu Freq/device Freq, 用于实现CPU以及device频率调整的Framework
  • OPP(Operating Performance Point)是指可以使SOCs或者device正常工作的电压和频率结合。内核提供这一个Layer, 是为了在众多的电压和频率组合中,筛选出一个相对固定的组合,从而使事情变得简单一些。
  • PM QOS, 所谓的PM QOS, 是指在指定的运行状态下(不同电压, 频率,不同模式之间切换)的工作质量, 包括latency, timeout, throught三个参数, 单位分别为:us, us和kb/s。 通过QOS参数可以分析,改善系统的性能。
Geniric PM在Linux操作系统的表现形式

Linux操作系统中,和Generic PM有关的操作如下面图片:

在这里插入图片描述

共有三部分组成:

第一部分系统关机, 重启等操作的界面,包含Hibernate, Restart, Shutdown三个操作选项, 2、3部分是“电源管理属性”设置,所谓的电源管理属性,可以配置系统在不同供电模式下(如AC Power, Battery等)处于Inactive状态多久后,系统关闭Display, 或者进入Sleep状态。

本文将会围绕上面提到的各个名词,讲述它们的意义,在内核中的实现方式。 开始之前,先解释一下这些词汇的含义:

shutdown: 很好理解,就是关机的意思,同时意味着不再使用计算机
Restart : 就是重启系统的意思,重启的过程不再使用计算机
Hibernate: 在不需要使用计算机时,将它当前的所有现场(执行的程序,显示器显示的图像,正在播放的声音等)保存到一些断电不会丢失的存储器中(如硬盘中),然后将计算机关闭。 重新开启后, 系统会从存储器中将关闭前的现场读取出来并恢复,此时从使用者的角度来看,计算机好像没有被关闭过一样。
Sleep: 在计算机中,Hibernate需要把现场保存到断电不丢失的存储器中,并在醒来的时候都回来,这些可能需要较长时间(因为断电不丢失存储器的访问速度都比较慢)。 如果想快点, 就把现场保存到内存中就可以了,这就是Sleep, 不过这是要付出代价的,内存要保持供电, 这就要消耗能量, 鱼与熊掌不可兼得。

Auto Sleep:查看上述图片第三个部分,可以设置系统处于“Inactive状态多久后, 自动进入Sleep状态”。 

Auto put display to Sleep: 原理类似, 只是操作的对象是Display.

Generic PM和Runtime PM的本质区别, 在使用者的主观意愿上,是否需要暂停使用计算机(哪怕短短的一段时间)。

这也是Generic PM在传统计算机操作系统中被广泛使用的原因, 因为那个时候对计算机的使用大多是主动方式。而对当前的移动互联来说,就非常不合时宜了,因为人们需要移动设备实时在线,实时接受被动事件(如来电), 也就不可能主观的暂停使用(哪怕短短的一段时间), 这种最终需求的差异,会导致在软件设计上有很大的差别,正因为如此,Runtime PM的出现和尽快成熟,才显得格外重要。

Generic PM的软件架构

在介绍完Generic PM的基本概念后,我们来看一下它在Linux内核中的整体实现, 并抽象出简单的软件架构,以便在后续的文章中, 对Generic PM的主要组成部分进行更为细致的分析。
在这里插入图片描述

根据上面的描述, Generic PM主要处理关机, 重启,冬眠(Hibernate),睡眠(Sleep, 在kernel中也称作Suspend), 在内核中,大致可以分为三个软件层次。

API接口: 用于向用户空间提供接口,其中关机和重启的接口形式是系统调用, Hibenate和Suspend的接口形式是sysfs.

PM core: 位于kernel/power目录下, 主要处理和硬件无关的核心逻辑

PM Driver: 分为两部分, 一是体系无关的Driver, 提供Driver框架(Framework)。 另一部分是具体的体系结构相关的Driver, 这也是电源管理驱动开发索要涉及的内容。

另外, 电源管理是一个系统级的模块,因而会涉及到设备模型,进程管理等等方方面面的内容、
Kernel支持的reboot方式

reboot是重启的意思,所以用它实现Restart是合理的,关机是一种特殊的restrat,因为你早晚也会开机,只不过持续的时间有点长而已。内核根据不同的方式,将reboot分为如下几种方式:

/*
 * Commands accepted by the _reboot() system call.
 *
 * RESTART     Restart system using default command and mode.
 * HALT        Stop OS and give system control to ROM monitor, if any.
 * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
 * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
 * POWER_OFF   Stop OS and remove all power from system, if possible.
 * RESTART2    Restart system using given command string.
 * SW_SUSPEND  Suspend system using software suspend if compiled in.
 * KEXEC       Restart system using a previously loaded Linux kernel
 */

#define	LINUX_REBOOT_CMD_RESTART	0x01234567  
#define	LINUX_REBOOT_CMD_HALT		0xCDEF0123
#define	LINUX_REBOOT_CMD_CAD_ON		0x89ABCDEF
#define	LINUX_REBOOT_CMD_CAD_OFF	0x00000000
#define	LINUX_REBOOT_CMD_POWER_OFF	0x4321FEDC
#define	LINUX_REBOOT_CMD_RESTART2	0xA1B2C3D4
#define	LINUX_REBOOT_CMD_SW_SUSPEND	0xD000FCE2
#define	LINUX_REBOOT_CMD_KEXEC		0x45584543

RESTART: 正常的重启,也是我们平时使用的重启。执行该动作后,系统会重新启动
HALT: 停止操作系统,然后把控制权交给其他代码(如果有的话)。 具体的表现形式依赖于系统的具体实现
CAD_ON/CAD_OFF : 允许/禁止通过Ctrl+Alt+Del组合按键出发重启(RESTART)动作。
注: ctrl+alt+del组合按键的响应是由具体的Driver实现的
POWER_OFF:正常的关机。 执行该动作后,系统会停止操作系统, 并去除所有的供电
RESTART2: 重启的另一种方式。 可以在重启时携带一个字符串类型的cmd, 该cmd会在重启前,发送给任意一个关心重启事件的进程。 同时会传递给最终执行重启动作的machine相关的代码内核并没有规定该cmd的形式, 完全由具体的machine自行决定。
SW_SUSPEND: 即前一篇文章中描述的Hibernate操作,会在下一篇文章描述,
KEXEC: 重启并执行已经加载好的其他的KERNEL image(需要CONFIG_KEXEC的支持), 暂不涉及
Reboot相关的操作流程:

在linux操作系统中, 可以通过reboot, halt, poweroff等命令,发起reboot, 具体的操作流程如下:

在这里插入图片描述

  • 一般的Linux操作系统,在用户空间都提供了一些工具集合(如常在嵌入式系统中使用的Busybox), 这些工具集合包含了reboot, halt和poweroff三个和reboot相关的命令。读者可以参考man帮助文档,了解这些命令的解释和使用说明
  • 用户空间程序通过reboot进入系统调用,进入内核空间
  • 内核空间根据执行路径的不同,提供了kernel_restart, kernel_halt和kernel_poweroff三个处理函数,响应用户空间的reboot请求
  • 这三个处理函数的处理流程大致相同, 主要包括: 向关心reboot过程的进程发送notify事件; 调用driver核心模块提供的 接口,关闭所有的外部设备; 调用drivers syscore模块提供的接口, 关闭system core; 调用Architecture相关的处理函数,进行后续的处理;最后调用machine相关的接口,实现真正意义上的reboot
  • 另外,借助tty模块提供的Sysreq机制, 内核提供了其他途径的关机方法,如某些按键组合,向/proc文件写入命令
Reboot过程的内部动作和代码分析
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
		void __user *, arg)

该函数的参数解释如下:

reboot: 系统调用的名称
magic1/magic2: 两个int类型的"魔力数", 用于防止误操作。 具体在“include/uapi/linux/reboot.h”中定义,感兴趣的同学可以去看看(话说这些数字还是蛮有意思的,例如Linus同学及其家人的生日就在里面,猜出来的可以在文章下面留言)。
cmd: 上述的reboot方式
arg: 额外参数

1)判断调用者的用户权限,如果不是超级用户(superuser), 则直接返回错误(这也是我们在用用户空间执行reboot, halt和poweroff等命令时,必须是root用户的原因)

2)判断传入的magic number是否匹配,如果不匹配则直接返回错误。这样可以尽可能的防止误动作发生

3)调用reboot_pid_ns接口,检查是否需要由该接口处理reboot请求。 这是一个有关pid namespace的新特性, 也是linux内核重要的知识点。

4) 如果是POWER_OFF命令,且没有注册power off的machine处理函数(pm_power_off),把该命令转换成HALT命令

5)根据具体的cmd命令,执行具体的处理,包括

如果是RESTART或者RESTART2命令,调用kernel_restart

如果是CAD_ON或CAD_OFF命令,更新C_A_D的值,表示是否允许通过Ctrl+Alt+Del组合键重启 系统。

如果是HALT命令,调用kernel_halt

如果是POWER_OFF命令,调用kernel_power_off

如果是KEXEC命令,调用kernel_kexec接口

如果是SW_SUSPEND, 调用hibernate接口

6) 返回上述的处理结果,系统调用结束

kernel_restart, kernel_halt和kernel_power_off

这三个接口也位于“kernel/reboot.c”, 实现比较类似, 具体动作包括:

1)调用kernel_xxx_prepare函数,进行restart/halt/power_off前的准备工作,包括调用blocking_notifier_call_chain接口,向关心reboot事件的进程,发送SYS_RESTART、SYS_HALT或者SYS_POWER_OFF事件。对RESTART来说,还要将cmd参数一并发送出去。将下i同状态设置为相应的状态(SYS_RESTART、SYS_HALT或者SYS_POWER_OFF)。调用usermodehelper_disable接口,禁止User mode helper。  调用device_shutdown关闭所有设备。
2)如果是poweroff, 且存在PM相关的power off prepare函数(pm_power_off_prepare), 则调用该回调函数
3)调用migrate_to_reboot_cpu接口,将当前的进程(task)转移到一个CPU上; 注: 对于多CPU的机器,无论哪个cpu触发了当前的系统调用,代码都可以运行在任意的cpu上。这个接口将代码分派到特定的cpu上,并禁止调度器分派代码到其他的CPU上。 也就是说,这个接口被执行后,只有一个cpu在运行,用于完成之后的reboot动作。
4)调用system_shutdown接口,将系统核心器件关闭(例如中断等)
5)调用printk以及kmsg_dump, 向这个世界发出最后的声音(打印日志)
6)最后由machine-core的代码,接管后续的处理


device_shutdown

设别模型中和device_shutdown有关的逻辑包括:

  • 每个设备(struct device)都会保存该设备的驱动(struct devcie_driver)指针,以及该设备所在总线(struct bus_type)的指针
  • 设备驱动中有一个名称为“shutdown"的回调函数,用于在device_shutdown时,关闭该设备
  • 总线中也有一个名称为”shutdown"的回调函数,用于在devvice_shutdown时关闭该设备
  • 系统中的设备,都存在于“/sys/devices”目录下, 而该目录由名称为“devices_kset”的kset表示。kset中会使用一个链表保存其下的所有的kobject(也即”/sys/devices“目录下的所有设备)。最终结果就是以”devcie_kset"为root节点, 将内核中所有的设备(以相应的kobject为代表),组织成一个树状结构。

介绍完 以上的背景知识,我们来看device_shutdown的实现,就非常容易了。该接口位于”/driver/base/core.c“中,执行的逻辑如下:

oid device_shutdown(void)
{
	struct device *dev, *parent;

	spin_lock(&devices_kset->list_lock);
	/*
	 * Walk the devices list backward, shutting down each in turn.
	 * Beware that device unplug events may also start pulling
	 * devices offline, even as the system is shutting down.
	 */
	while (!list_empty(&devices_kset->list)) {
		//遍历device_kset的链表,取出所有的设备
		dev = list_entry(devices_kset->list.prev, struct device,
				kobj.entry);

		/*
		 * hold reference count of device's parent to
		 * prevent it from being freed because parent's
		 * lock is to be held
		 */
		parent = get_device(dev->parent);
		get_device(dev);
		/*
		 * Make sure the device is off the kset list, in the
		 * event that dev->*->shutdown() doesn't remove it.
		 */
		 //将该设备从链表中删除
		list_del_init(&dev->kobj.entry);
		spin_unlock(&devices_kset->list_lock);

		/* hold lock to avoid race with probe/release */
		if (parent)
			device_lock(parent);
		device_lock(dev);

		/* Don't allow any more runtime suspends */
		//调用pm_runtime_get_noresume和pm_runtime_barrier接口,停止所有的Runtime相关的电源管理动作(后面会详细描述有关Runtime PM的逻辑)
		pm_runtime_get_noresume(dev);
		pm_runtime_barrier(dev);

	//依次调取class->shutdown函数,如果该设备的class提供了shutdown函数,有限调用class的shutdown函数,关闭设备, 如果没有依次调用bus的shutdown函数,最后时driver中的shutdown函数关闭设备
		if (dev->class && dev->class->shutdown) {
			if (initcall_debug)
				dev_info(dev, "shutdown\n");
			dev->class->shutdown(dev);
		} else if (dev->bus && dev->bus->shutdown) {
			if (initcall_debug)
				dev_info(dev, "shutdown\n");
			dev->bus->shutdown(dev);
		} else if (dev->driver && dev->driver->shutdown) {
			if (initcall_debug)
				dev_info(dev, "shutdown\n");
			dev->driver->shutdown(dev);
		}

		device_unlock(dev);
		if (parent)
			device_unlock(parent);
		
		put_device(dev);
		put_device(parent);

		spin_lock(&devices_kset->list_lock);
	}
	spin_unlock(&devices_kset->list_lock);
}
直到处理完所有的函数

system_core_shutdown

system core的shutdown和deviceshutdown类似,也是从一个链表中,遍历所有的system core, 并调用它的shutdown接口。

machine_restart, machine_halt和machine_power_off

虽然都是以machine为前缀命名,这三个接口却是Architecture相关的处理函数,如ARM。 以ARM 为例, 它们在”arch/arm/kernel/process.c”中实现,具体如下

/*
 * Restart requires that the secondary CPUs stop performing any activity
 * while the primary CPU resets the system. Systems with a single CPU can
 * use soft_restart() as their machine descriptor's .restart hook, since that
 * will cause the only available CPU to reset. Systems with multiple CPUs must
 * provide a HW restart implementation, to ensure that all CPUs reset at once.
 * This is required so that any code running after reset on the primary CPU
 * doesn't have to co-ordinate with other CPUs to ensure they aren't still
 * executing pre-reset code, and using RAM that the primary CPU's code wishes
 * to use. Implementing such co-ordination would be essentially impossible.
 */
 对于多cpu的机器来说,Restart之前必须保证其他的CPU处于非活动状态,由其中的一个主CPU负责Restart动作。并且必须实现一个基于硬件的Restart的操作,以保证所有的CPU同步Restart,这是涉及的重点。
 对于单cpu来说就简单了,直接用软件reset方式实现Restart
void machine_restart(char *cmd)
{
	local_irq_disable();
	smp_send_stop();  //确保其他CPU处于非活动状态

	if (arm_pm_restart) //如果定义了这个函数
		arm_pm_restart(reboot_mode, cmd); 这是一个回调函数,具体代码:  EXPORT_SYMBOL_GPL(arm_pm_restart);
	else
		do_kernel_restart(cmd);

	/* Give a grace period for failure to restart of 1s */
	mdelay(1000);  //等待1s  如果没有返回,就restart成功,否则错误,打印错误信息

	/* Whoops - the platform was unable to reboot. Tell the user! */
	printk("Reboot failed -- System halted\n");
	while (1);
}
machine_halt

ARM的halt很简单, 就是先将其他的CPU停息来,并禁止当前的CPU中断后,死循环。

void machine_halt(void)
{
	local_irq_disable();
	smp_send_stop();
	while (1);
}
machine_power_off

power off动作和restart类似,即停止其它CPU,调用回调函数。power off的回调函数和restart类似,就不再说明了。

电源驱动需要实现的内容

由以上的分析可知,在Reboot的过程中,大部分的逻辑是否内核处理的,具体的driver需要关注两点即可

  1. 实现各自的shutdown接口,以正确关闭对应的设备
  2. 实现machine-dependent接口,以确保底层的Machine可以正确的restart或者poweroff (这个我没注意到,接下来继续关注)
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux中,reboot是一个系统调用,用于重新启动计算机。它可以通过命令行或者在代码中调用。reboot命令有几个选项可以使用,比如-d选项可以在重启系统时不将操作写入日志文件,-f选项可以强制重启操作系统,-n选项可以在重启操作系统前不同步硬盘/存储介质等。\[1\]在用户空间,一般的Linux操作系统提供了一些工具集合,如reboot、halt和poweroff命令,它们都与重启相关。内核空间根据执行路径的不同,提供了kernel_restart、kernel_halt和kernel_poweroff三个处理函数,响应用户空间的reboot请求。这些处理函数的处理流程大致相同,包括向关心reboot过程的进程发送notify事件、关闭所有的外部设备、关闭system core等。最后,调用machine相关的接口实现真正意义上的reboot。此外,内核还提供了其他途径的关机方法,如通过按键组合或向/proc文件写入命令。\[2\]\[3\] #### 引用[.reference_title] - *1* [Linux 命令(223)—— reboot 命令](https://blog.csdn.net/K346K346/article/details/128373667)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Linux电源管理系统休眠唤醒reboot](https://blog.csdn.net/qq_39575672/article/details/129708512)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值