PSCI是在ARMv8后提出的新的电源管理框架。主要的工作是将原来在Kernel中完成的电源操作,通过SMC Call的方式,下移到ATF中。
使用PSCI,需要在DTS中配置PSCI节点,并指定PSCI的版本(ATF支持的PSCI操作的版本),PSCI的方法(HVC/SMC)。
之后PSCI框架会在系统初始化时,根据DTS的配置,完成CPU PSCI操作的绑定。
绑定后,对CPU进行电源管理操作,会通过SMC + Func ID的方式,传递给ATF完成。
真正的电源操作,在ATF中完成。
PSCI的电源管理框架的层次结构如下图所示:
[ SMP Framework ]
[ cpu_ops ]
[ cpu_psci_ops ]
[ psci_ops ]
[ HVC/SMC ]
---------------------------------
[ ATF or HYP ]
其中,SMP的框架调用cpu_ops来完成单个CPU的电源操作。
cpu_ops(cpu_ops.c)在初始化时,会从dts中读取cpu节点的enable-method,绑定对应的cpu_ops实现(psci或spin table),这里我们只关心基于psci实现的cpu_ops(cpu_psci_ops)
cpu_psci_ops使用psci_ops实现。
psci_ops在初始化时,根据dts描述,绑定好对应的底层操作函数。
这些底层函数是基于HVC或SMC + Func ID的简单封装。
- /arch/arm64/kernel/smp.c # SMP Operations, based on cpu_ops framework
-------------------------------------
- /arch/arm64/kernel/cpu_ops.c # CPU Oerations (cpu_ops) framework, point to cpu_psci_ops
- /arch/arm64/kernel/psci.c # PSCI cpu_ops implementation (cpu_psci_ops), based on psci_ops
- /arch/arm64/include/asm/cpu_ops.h
-------------------------------------
- /drivers/firmware/psci/psci.c # PSCI SMC/HVC Wrap Functions (psci_ops)
- /include/linux/psci.h
- /include/uapi/linux/psci.h # PSCI Function IDs
struct psci_operations {
u32 (*get_version)(void);
int (*cpu_suspend)(u32 state, unsigned long entry_point);
int (*cpu_off)(u32 state);
int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
int (*migrate)(unsigned long cpuid);
int (*affinity_info)(unsigned long target_affinity,
unsigned long lowest_affinity_level);
int (*migrate_info_type)(void);
};
struct psci_operations psci_ops
全局psci_ops变量
invoke_psci_fn
psci method function,hvc / smc
psci {
compatible = "arm,psci-1.0"; // 配置psci版本
method = "smc"; // 配置psci方法
};
&cpu0 {
enable-method = "psci"; // 使用psci控制cpu上下电(cpu_ops use psci)
};
> psci_dt_init
在setup_arch中被初始化
会读取dts中psci节点,完成对应版本的psci和method(invoke_psci_fn)的初始化。
> get_set_conduit_method
如果是smc,invoke_psci_fn=\_\_invoke_psci_fn_smc,底层使用arm_smccc_smc发送指令
如果是hvc,invoke_psci_fn=\_\_invoke_psci_fn_hvc,底层使用arm_smccc_hvc发送指令
指令对应的Function ID在psci.h中定义,底层smc、hvc接口在smccc-call.S中实现
> psci_probe
初始化psci_ops全局变量,绑定的所有回调函数都是对smc + func_id的封装。
psci_features
通过psci call(smc)请求检查某个Func ID是否支持。
psci_ops
Handle CPU PM Ops
.get_version = psci_0_2_get_version,
.cpu_suspend = psci_0_2_cpu_suspend,
.cpu_off = psci_0_2_cpu_off,
.cpu_on = psci_0_2_cpu_on,
.migrate = psci_0_2_migrate,
.affinity_info = psci_affinity_info,
.migrate_info_type = psci_migrate_info_type,
psci_sys_reset_nb
Handle System Reset
psci_sys_poweroff
Handle System Power Off