1
User Space通常需要操作到PM的一些AP或tools简介
1.
/sbin/init,
init program。我们可以通过执行
init N进入某种
run level。
N=
0:关机(
Embedded
Device中常不支持),
N=
6 reboot。
2.
/sbin/reboot reboot。还有
sbin/halt等
3.
/sbin/shutdown关机。
4.
如果AP自己有建立一个watch dog,那么AP检测到异常时可以reboot。
5.
其它。
2
PM Application Interface介绍
1.
/sys/power/state。Linux Kernel目前支持三种low power的state,分别是:Standby,
STR(suspend-to-ram),
STD(suspend-to-disk)。不同的低功耗状态有着不同的功耗以及系统唤醒延迟时间,
standby的功耗大但是延迟时间短,
User几乎可以没有感知的。
STR功耗小(
U3目前在
1mA左右),不过唤醒延迟稍长,就系统而言也是很快的,但是这个只是
User感知到的时间的很小一部分,
AP可能会需要更多的时间。
STD功耗最小,不过唤醒时间很长,这种方式对应我们
windows
PC上用的
hibernation,
Embedded Device中一般不支持
STD。
2.
system call:
sys_reboot
讨论:
1.
我们说STD唤醒时间很长是跟STR比较,如果跟冷启动比较是否更长呢?这个就不一定了,要看flash的速度。所以不妨可以考虑使用STD替换冷启动。从而加速User感知到的冷启动速度。
3
PM系统端几个重要功能的浅析
3.1
System reboot
User执行
reboot或
init 6时最终会由
system call:
sys_reboot来进行
device的重新启动。
Clib提供了一个
C function:
reboot()
来
invoke sys_reboot。大家可以
man 2 reboot来查看,其参数接口定义跟
sys_reboot完全一致。
下面我们就从sys_reboot出发来分析:(其proto type为:asmlinkage long sys_reboot(int magic1, int
magic2, unsigned int cmd, void __user * arg),对reboot其cmd为:LINUX_REBOOT_CMD_RESTART)
1.
kernel_restart==>kernel_restart_prepare进行
restart的准备工作。它主要就是通过
A.
device_shutdown关闭各个
device。对于
embedded system,一般
device driver都是基于
virtual platform bus来实现的,
platform
bus并没有实现
shutdown接口,而我们的
platform drivers通常没有也实现
shutdown接口,因为一般
Embedded Device中没有冷关机的需求,如果有,在需要关心
shutdown的
platform驱动中实现这个接口就好了。
B.
sysdev_shutdown()关闭所谓的
system device。所谓
system device一般是指一些系统基本的
device,如我们在
Linux
驱动开发中常用的内存分配方法浅析中分析
clocksource就是一个
system device。其它如
CPU,
Interrupt controller等。
System
device或
driver都是挂在
system bus上。
System bus在
7.2中简单分析过。这些
devices并没有实现在
virtual
platform bus上。
2.
machine_restart()真正进行
reboot。
A.
machine_restart是一个
platform相关的一个
funciton,
ARM platform下实现在
/arch/arm/kernel/process.c:
machine_restart==>arm_machine_restart==>arch_reset,
B.
arch_reset是我们要实现的,跟具体的
SOC有关的
function,具体项目中一般实现在
/include/asm-arm/arch-xxxx/system.h中:
arch_reset,通常进行
SOC
芯片级的
reset,它会
reset除了
watch dog
之外的几乎所有
SOC hardware寄存器。当然这个以具体的
SOC manual为准了。
另外还有一个restart的方式是不进行hardware register等的reset,即所谓的soft restart,其过程简介如下:
C.
arch_reset==>cpu_reset(0);,
D.
cpu_reset定义在:
/include/asm-arm/cpu-single.h:
#define cpu_reset __cpu_fn(CPU_NAME,_reset)
E.
展开这些macro后得到:cpu_reset其实就是cpu_arm926_reset,
F.
cpu_arm926_reset的实现详见:arch/arm/mm/proc-arm926.S中:jump
to address 0。跳到0地址,在ARM上自然就是reset了
讨论
2.
Linux Kernel software watchdog在其timeout时会:watchdog_fire==>emergency_restart==>machine_emergency_restart==>machine_restart直接进行emergency
restart。
3.2
Deep sleep
User或
User Application向
/sys/power/state file写入“
mem”可以让
U3进入
deep
sleep state,也就是我们常说的热关机。在
shell interactive command line下可以简单如此操作:
echo mem > /sys/power/state。
/sys/power/state file在
pm_init()中建立,这部分在第六章中详细分析过,这里不在罗嗦。这里我们需要知道的是向
/sys/power/state file写其实就是调用
state_store().。下面就从
state_store出发来进行一步分析。
state_store==>enter_state:
1.
调用suspend_prepare进行进入sleep前的准备工作,pm_prepare_console():suspend virtual console。之后通过freeze_processes
- tell processes to enter the refrigerator(注:简而言之,它对每个process设置TIF_FREEZE
flag,之后Linux在处理signal的时候:arch/arm/kernel/entry-common.S中:work_pending==>do_notify_resume==>do_signal
==>try_to_freeze==>refrigerator:enter into refrigerator。)
2.
suspend_devices_and_enter==>suspend_console:suspend console(printk)
3.
suspend_devices_and_enter==>device_suspend:
suspend devices。对
platform bus下的设备
device_suspend==>suspend_device==>error
= dev->bus->suspend(dev, state); 即
platform_suspend最后调用到我们在
platform_driver中实现的
suspend function(这里我就不展开列出所有的
function调用序列,大家自行分析补充吧),
这里是各自device
driver的designer要重点考虑的事情。(注:device_suspend只会suspend已经由device_pm_add加入到PM中,这个在device_add==>device_pm_add就已经帮忙做了)
4.
suspend_devices_and_enter==>suspend_entererror = pm_ops->enter(state);进入
sleep。此处的
enter
function定义在:
arch/arm/mach-xxxx/pm.c中的
ad6900_pm_enter,接下来:
xxxx_pm_enter==>xxxx_cpu_suspend()(
arch/arm/mach-xxxx/suspend.S中)
讨论:
3.
讨论一下xxxx_cpu_suspend有哪些东西要做:close
all clock except RTC clock、enter SDRAM self refresh mode、enter
SOC sleep mode。这些主要看具体SOC的spec了。
4.
PM driver实现了一个很好的结构、并提供了各个不同device driver的接口,PM
driver本身并不需要关注各个driver具体的suspend动作。PM
driver的designer本身也不可能、也不需要知晓所有device的细节。定好结构,然后让大家协同一致的工作应该是所有的领域都想达到的目标。
3.3
系统idle
系统idle简单的说就是当Linux Kernel发现没有任何processes可以调度的时候,CPU会进入idle
state以达到降低power consumption的目的。
我们先看一下start_kernel==>rest_init,当没有processes可以调度的时候,执行cpu_idle(),cpu_idle()实现在arch/arm/kernel/process.c中,它就是我们通常所说的process
0或idle process。它其实就是一个dead loop,有任何process可执行,就调度执行之,没有就执行default_idle:default_idle==>arch_idle==>cpu_do_idle,即processor._do_idle(),同样由/include/asm-arm/cpu-single.h可知:cpu_arm926_do_idle,arm停止工作,并等待hardware
interrupt到来唤醒。
讨论:
5.
cpu_arm926_do_idle
的source code如下:
ENTRY(cpu_arm926_do_idle)
mov
r0, #0
mrc p15, 0, r1, c1, c0, 0 @ Read control register
mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer
bic r2, r1, #1 << 12
mcr p15, 0, r2, c1, c0, 0 @ Disable I cache
mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
mcr p15, 0, r1, c1, c0, 0 @ Restore ICache enable
mov pc, lr
要理解这些指令,需要看看ARM926的spec。ARM
Architecture Manual只是不同ARM chip公共的一些信息。