【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、电源管理等,均不支持。

posted @ 2022-06-20 19:01  zephyr~  阅读(363)  评论(0编辑  收藏  举报