【cpu_operations】CPU smp topology hotplug ops操作(1)
kernel/cpu.c
kernel cpu control是一个承上启下的模块,向上层软件提供CPU core控制的统一API,主要功能包括:
cpu mask
在模块内部定义并维护所有CPU core的状态,将CPU core抽象为possible、present、online和active四种状态,并存储为bitmap的形式,同时以cpumask的形式向其它模块提供状态查询、修改的API。
// possible只是说CPU有可能存在,因为DTS定义了该CPU节点,但是此时CPU还不在位
struct cpumask __cpu_possible_mask __read_mostly;
// present表明CPU已经跳转到内核了,但是他们依然在做着无意义的循环
struct cpumask __cpu_online_mask __read_mostly;
// CPU进入online状态,也就是说这些CPU在线了,可以干活了
struct cpumask __cpu_present_mask __read_mostly;
// 当CPU处于active的时候,说明它已经准备好了一切,可以参与进程调度了
struct cpumask __cpu_active_mask __read_mostly;
cpu hotplug及sysfs接口
通俗地讲,所谓的CPU core up,就是将某一个CPU core“运行”起来。何为运行呢?回忆一下单核CPU的启动,就是让该CPU core在指定的memory地址处取指执行。因此该功能只对SMP系统有效(使能了CONFIG_SMP)。而CPU core down,就是让CPU core保存现场(后面可以继续执行)后,停止取指,只有在CPU hotplug功能使能(CONFIG_HOTPLUG_CPU)时有效。这两个功能对应的API为:
int add_cpu(unsigned int cpu);
int remove_cpu(unsigned int cpu);
smp pm操作
系统关机或者reboot过程中,将secondary CPU下电
void smp_shutdown_nonboot_cpus(unsigned int primary_cpu);
driver/base/cpu.c
从设备模型的角度,抽象CPU core设备,并通过sysfs提供CPU core状态查询、hotplug控制等接口。使用接口int register_cpu(struct cpu *cpu, int num)
在cpu目录下注册每个cpu的入口:
/sys/devices/system/cpu$ ls
cpu0 cpu3 cpu6 cpuidle kernel_max online present vulnerabilities
cpu1 cpu4 cpu7 hotplug modalias possible smt
cpu2 cpu5 cpufreq isolated offline power uevent
arch/arm64/kernel/smp.c
1)arch-dependent的SMP初始化、CPU core控制等操作。
2)IPI(Inter-Processor Interrupts)相关的支持。
SMP初始化操作,主要负责从DTS中解析CPU core信息,并获取必要的信息以及操作函数集,由smp_init_cpus接口实现,并在setup_arch(arch\arm64\kernel\setup.c)中调用。
// 从核跳转到kernel入口
asmlinkage notrace void secondary_start_kernel(void);
void __init smp_init_cpus(void);
arch/arm64/kernel/topology.c
负责在系统初始化的时候,由boot cpu读取DTS、ACPI,填充每个CPU core的struct cpu_topology变量。同时,该文件提供一些通用的宏定义,用于获取执行CPU core的信息,例如该CPU core的package id、core id等。
arch/arm64/kernel/cpuinfo.c
负责在初始化的时候将ARM CPU core有关的信息,从寄存器中读出,缓存在struct cpuinfo_arm64类型的变量中。包括cache策略icache_policy_str
,硬件能力hwcap_str
,兼容硬件能力compat_hwcap_str
。
arch/arm64/kernel/cpu_ops.c
cpu的idle、hotplug 、shutdown、reset、suspend/resume、big·LITTLE等电源管理操作封装抽象为了以下结构体
struct cpu_operations {
const char *name;
int (*cpu_init)(unsigned int);
int (*cpu_prepare)(unsigned int);
int (*cpu_boot)(unsigned int);
void (*cpu_postboot)(void);
#ifdef CONFIG_HOTPLUG_CPU
bool (*cpu_can_disable)(unsigned int cpu);
int (*cpu_disable)(unsigned int cpu);
void (*cpu_die)(unsigned int cpu);
int (*cpu_kill)(unsigned int cpu);
#endif
#ifdef CONFIG_CPU_IDLE
int (*cpu_init_idle)(unsigned int);
int (*cpu_suspend)(unsigned long);
#endif
};
ARM architecture提供多种可选的cpu ops实现,如spin-table、PSCI(Power State Coordination Interface)等,开发者可以根据需求,选择一种。
static const struct cpu_operations *const dt_supported_cpu_ops[] __initconst = {
&smp_spin_table_ops,
&cpu_psci_ops,
NULL,
};
static const struct cpu_operations *const acpi_supported_cpu_ops[] __initconst = {
#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL
&acpi_parking_protocol_ops,
#endif
&cpu_psci_ops,
NULL,
};
具体使用哪一个operation,是通过DTS指定的,DTS格式如下:
/* spin-table: arch/arm64/boot/dts/xxx.dtsi */
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53";
reg = <0x0 0x0>;
enable-method = "spin-table";
cpu-release-addr = <0x0 0x80000000>;
next-level-cache = <&cluster0_l2_cache>;
};
即,在每一个cpu子节点中,使用“enable-method”指定是使用“spin-table”还是“psci”。系统初始化的时候,会根据DTS信息,获取使用的operations(setup_arch-->cpu_read_bootcpu_ops-->cpu_read_ops),最终保存在一个operation数组(每个CPU一个)中,供SMP(arch/arm64/kernel/smp.c)使用。
spin-table operations只支持cpu_init、cpu_prepare和cpu_boot三个回调函数,因此,它只能实现secondary cpu boot的功能,其他功能,如cpu hotplug、cpuidle、电源管理等,均不支持。