Linux电源管理——CPU Hotplug 流程

news2024/12/27 5:31:16

目录

一、相关概念

二、基本原理

三、代码分析

1、CPU_ON

2、CPU_OFF

References


Linux Version:linux-5.4.239

 一、相关概念

        在单核操作系统中,操作系统只需管理一个CPU,当系统有任务需要执行时,所有的任务会在该CPU的就绪队列上进行排队,然后调度器会选择一个合适的任务执行。当就绪队列上的所有任务都执行完成后,CPU就会执行idle进程而进入空闲状态,但由于idle进程的优先级最低,一旦有其它任务进入就绪队列,就会抢占idle进程转去执行其它任务。CPU就是在不同的任务间切换,实现整个系统的运行。其基本架构如下:

        但是在引入SMP(Symmetric Multi Processing)之后,操作系统需要同时管理多个CPU,每个CPU拥有自己的就绪队列和idle进程,并可以独立地执行调度操作。当CPU之间的负载出现不均衡时,可以由负载均衡模块在它们之间迁移任务。相应的其基本架构如下:

        如果只考虑让操作系统能够正常运行,那只需要一个CPU即可,当操作系统任务不多或者系统需要Suspend时,就可以将多余的CPU从系统中下线,以减少系统功耗,因此在SMP系统中引入了CPU Hotplug的功能,以实现动态地关闭或者打开 Non-Boot CPU。

CPU hotplug 目前主要有以下两个应用场景:
 (1)用户通过sysfs接口手动开启或关闭某个cpu

echo 0 > /sys/devices/system/cpu/cpu1/online      # 关闭CPU1
echo 1 > /sys/devices/system/cpu/cpu1/online      # 打开CPU1

(2)作为系统休眠唤醒流程的一部分,当系统需要休眠时可以前先关闭所有的Secondary CPU,当系统被唤醒后再重新开启。

suspend_enter
    -> suspend_disable_secondary_cpus
        -> freeze_secondary_cpus
            -> __freeze_secondary_cpus
                -> _cpu_down(cpu, 1, CPUHP_OFFLINE)

二、基本原理

​         CPU Online相当于把一个关闭的CPU重新上电运行,因此在开启时需要先为该CPU设置内核的入口地址,然后上电运行,当CPU执行一系列的初始化流程之后,最终加入内核的调度系统参与任务调度。而 CPU Offline则是将一个当前正在执行任务的CPU下电,因为运行中的CPU和系统中很多模块都有联系,所以如果要下线一个CPU,需要先将CPU与相关模块进行分离 ( 解耦),如将该 CPU 就绪队列上的所有任务,中断等都迁移到其它CPU上去。

​        当CPU与系统中的相关模块分离之后,此时就可以通过调用 cpu_psci_cpu_die -> psci_cpu_off 完成 CPU 的下电,因此,关闭一个CPU的关键就是分离与相关模块之间的联系。

  由于各个模块的作用不同,因此打开或关闭的时间点也有所不同,因此kernel为 CPU Hotplug实现了一个状态机,该状态机在不同阶段执行不同的回调函数,并且这些回调函数在不同阶段的执行由不同的CPU负责,通常用来开启或者关闭其它 CPU 的 CPU被称为 Boot Processor (BP),被 BP 开启或者关闭的 CPU 称为 Application Processor (AP)。

cpu hotplug状态机定义如下:

enum cpuhp_state {
	CPUHP_INVALID = -1,
	CPUHP_OFFLINE = 0,
	CPUHP_CREATE_THREADS,
	CPUHP_PERF_PREPARE,
    ......
    CPUHP_AP_ACTIVE,
	CPUHP_ONLINE,
};

        该状态机以CPUHP_OFFLINE开始,并以CPUHP_ONLINE结束,其中每个状态都包含CPU上下线需要执行的操作。

        当上线一个CPU时,其初始状态为CPUHP_OFFLINE,如果最终成功执行到CPUHP_ONLINE状态,则该CPU成功上线。其相应的状态转换关系如下图所示:

​        当下线一个CPU时,其初始状态为CPUHP_ONLINE,如果最终成功执行到CPUHP_OFFLINE状态,则CPU成功下线。其相应的状态转换关系如下图所示:

        状态机中的每个状态都以cpuhp_step结构体表示,该结构体包含cpu online和offline时需要执行的回调函数。其定义如下:

/**
 * cpuhp_step - Hotplug state machine step
 * @name:	Name of the step
 * @startup:	Startup function of the step
 * @teardown:	Teardown function of the step
 * @cant_stop:	Bringup/teardown can't be stopped at this step
 */
struct cpuhp_step {
	const char		*name;
	union {
		int		(*single)(unsigned int cpu);
		int		(*multi)(unsigned int cpu,
					 struct hlist_node *node);
	} startup;  // cpu online时需要执行的回调
	union {
		int		(*single)(unsigned int cpu);
		int		(*multi)(unsigned int cpu,
					 struct hlist_node *node);
	} teardown; // cpu offline时需要执行的回调
	struct hlist_head	list;
	bool			cant_stop;
	bool			multi_instance;
};

cpuhp_step 结构体的初始化如下:

/* Boot processor state steps */
static struct cpuhp_step cpuhp_hp_states[] = {
	[CPUHP_OFFLINE] = {
		.name			= "offline",
		.startup.single		= NULL,
		.teardown.single	= NULL,
	},
#ifdef CONFIG_SMP
	[CPUHP_CREATE_THREADS]= {
		.name			= "threads:prepare",
		.startup.single		= smpboot_create_threads,
		.teardown.single	= NULL,
		.cant_stop		= true,
	},
	[CPUHP_PERF_PREPARE] = {
		.name			= "perf:prepare",
		.startup.single		= perf_event_init_cpu,
		.teardown.single	= perf_event_exit_cpu,
	},
	[CPUHP_RANDOM_PREPARE] = {
		.name			= "random:prepare",
		.startup.single		= random_prepare_cpu,
		.teardown.single	= NULL,
	},
	[CPUHP_WORKQUEUE_PREP] = {
		.name			= "workqueue:prepare",
		.startup.single		= workqueue_prepare_cpu,
		.teardown.single	= NULL,
	},
	[CPUHP_HRTIMERS_PREPARE] = {
		.name			= "hrtimers:prepare",
		.startup.single		= hrtimers_prepare_cpu,
		.teardown.single	= hrtimers_dead_cpu,
	},
	[CPUHP_SMPCFD_PREPARE] = {
		.name			= "smpcfd:prepare",
		.startup.single		= smpcfd_prepare_cpu,
		.teardown.single	= smpcfd_dead_cpu,
	},
	[CPUHP_RELAY_PREPARE] = {
		.name			= "relay:prepare",
		.startup.single		= relay_prepare_cpu,
		.teardown.single	= NULL,
	},
	[CPUHP_SLAB_PREPARE] = {
		.name			= "slab:prepare",
		.startup.single		= slab_prepare_cpu,
		.teardown.single	= slab_dead_cpu,
	},
	[CPUHP_RCUTREE_PREP] = {
		.name			= "RCU/tree:prepare",
		.startup.single		= rcutree_prepare_cpu,
		.teardown.single	= rcutree_dead_cpu,
	},
	/*
	 * On the tear-down path, timers_dead_cpu() must be invoked
	 * before blk_mq_queue_reinit_notify() from notify_dead(),
	 * otherwise a RCU stall occurs.
	 */
	[CPUHP_TIMERS_PREPARE] = {
		.name			= "timers:prepare",
		.startup.single		= timers_prepare_cpu,
		.teardown.single	= timers_dead_cpu,
	},
	/* Kicks the plugged cpu into life */
	[CPUHP_BRINGUP_CPU] = {
		.name			= "cpu:bringup",
		.startup.single		= bringup_cpu,
		.teardown.single	= finish_cpu,
		.cant_stop		= true,
	},
	/* Final state before CPU kills itself */
	[CPUHP_AP_IDLE_DEAD] = {
		.name			= "idle:dead",
	},
	/*
	 * Last state before CPU enters the idle loop to die. Transient state
	 * for synchronization.
	 */
	[CPUHP_AP_OFFLINE] = {
		.name			= "ap:offline",
		.cant_stop		= true,
	},
	/* First state is scheduler control. Interrupts are disabled */
	[CPUHP_AP_SCHED_STARTING] = {
		.name			= "sched:starting",
		.startup.single		= sched_cpu_starting,
		.teardown.single	= sched_cpu_dying,
	},
	[CPUHP_AP_RCUTREE_DYING] = {
		.name			= "RCU/tree:dying",
		.startup.single		= NULL,
		.teardown.single	= rcutree_dying_cpu,
	},
	[CPUHP_AP_SMPCFD_DYING] = {
		.name			= "smpcfd:dying",
		.startup.single		= NULL,
		.teardown.single	= smpcfd_dying_cpu,
	},
	/* Entry state on starting. Interrupts enabled from here on. Transient
	 * state for synchronsization */
	[CPUHP_AP_ONLINE] = {
		.name			= "ap:online",
	},
	/*
	 * Handled on controll processor until the plugged processor manages
	 * this itself.
	 */
	[CPUHP_TEARDOWN_CPU] = {
		.name			= "cpu:teardown",
		.startup.single		= NULL,
		.teardown.single	= takedown_cpu,
		.cant_stop		= true,
	},
	/* Handle smpboot threads park/unpark */
	[CPUHP_AP_SMPBOOT_THREADS] = {
		.name			= "smpboot/threads:online",
		.startup.single		= smpboot_unpark_threads,
		.teardown.single	= smpboot_park_threads,
	},
	[CPUHP_AP_IRQ_AFFINITY_ONLINE] = {
		.name			= "irq/affinity:online",
		.startup.single		= irq_affinity_online_cpu,
		.teardown.single	= NULL,
	},
	[CPUHP_AP_PERF_ONLINE] = {
		.name			= "perf:online",
		.startup.single		= perf_event_init_cpu,
		.teardown.single	= perf_event_exit_cpu,
	},
	[CPUHP_AP_WATCHDOG_ONLINE] = {
		.name			= "lockup_detector:online",
		.startup.single		= lockup_detector_online_cpu,
		.teardown.single	= lockup_detector_offline_cpu,
	},
	[CPUHP_AP_WORKQUEUE_ONLINE] = {
		.name			= "workqueue:online",
		.startup.single		= workqueue_online_cpu,
		.teardown.single	= workqueue_offline_cpu,
	},
	[CPUHP_AP_RANDOM_ONLINE] = {
		.name			= "random:online",
		.startup.single		= random_online_cpu,
		.teardown.single	= NULL,
	},
	[CPUHP_AP_RCUTREE_ONLINE] = {
		.name			= "RCU/tree:online",
		.startup.single		= rcutree_online_cpu,
		.teardown.single	= rcutree_offline_cpu,
	},
#endif
	/*
	 * The dynamically registered state space is here
	 */

#ifdef CONFIG_SMP
	/* Last state is scheduler control setting the cpu active */
	[CPUHP_AP_ACTIVE] = {
		.name			= "sched:active",
		.startup.single		= sched_cpu_activate,
		.teardown.single	= sched_cpu_deactivate,
	},
#endif

	/* CPU is fully up and running. */
	[CPUHP_ONLINE] = {
		.name			= "online",
		.startup.single		= NULL,
		.teardown.single	= NULL,
	},
};

三、代码分析

1、CPU_ON

        根据前面的分析,启动一个 CPU 其实就是将一个 CPU 的状态从 CPUHP_OFFLINE 转换到 CPUHP_ONLINE ,在不同的阶段由不同的 CPU 执行。

        如上图所示,当需要启动一个 CPU 时,BP 会先将 AP 的状态转换为 CPUHP_BRINGUP_CPU ,然后执行 bringup_cpu 回调函数,在回调函数中调用 psci_cpu_on 通过smc陷入到 ATF 进行开启 AP,当 AP 执行到 secondary_start_kernel 函数时会告诉 BP 自己已经启动了,让 BP 继续运行,当 AP 在进入 idle 之前还会通知 BP 自己启动到哪里了,这时 BP 就会 kick AP 的 hotplug 线程(cpuhp_thread_fun)继续执行状态机中后面的回调,直到 AP 的状态变成 CPUHP_ONLINE 为止,当 AP 的状态达到 CPUHP_ONLINE 时,AP 也就完全启动了。

CPU_ON 执行log:

注意:

1、本测试平台为 qemu,所以最后是 hvc 陷入到 hypervisor,而不是smc陷入到 ATF。

2、func 表示本行打印所在函数,line 表示行数,st->state 表示CPU的当前状态,CPU表示执行这一行代码的 CPU。

# echo 1 > /sys/devices/system/cpu/cpu3/online 
[  150.887484] func: cpu_subsys_online  line: 53, CPU: 0
[  150.887634] func: _cpu_up  line: 1219, CPU: 0
[  150.897642] func: _cpu_up: before cpuhp_up_callbacks line: 1267, CPU: 0 
[  150.897804] func: cpuhp_up_callbacks, st->state: 1, line: 628, CPU: 0
[  150.897817] func: cpuhp_up_callbacks, st->state: 2, line: 628, CPU: 0
[  150.897958] func: cpuhp_up_callbacks, st->state: 3, line: 628, CPU: 0
[  150.898096] func: cpuhp_up_callbacks, st->state: 4, line: 628, CPU: 0
[  150.898231] func: cpuhp_up_callbacks, st->state: 5, line: 628, CPU: 0
[  150.898364] func: cpuhp_up_callbacks, st->state: 6, line: 628, CPU: 0
[  150.898490] func: cpuhp_up_callbacks, st->state: 7, line: 628, CPU: 0
[  150.898618] func: cpuhp_up_callbacks, st->state: 8, line: 628, CPU: 0
[  150.898758] func: cpuhp_up_callbacks, st->state: 9, line: 628, CPU: 0
[  150.898890] func: cpuhp_up_callbacks, st->state: 10, line: 628, CPU: 0
[  150.899012] func: cpuhp_up_callbacks, st->state: 11, line: 628, CPU: 0
[  150.899136] func: cpuhp_up_callbacks, st->state: 12, line: 628, CPU: 0
[  150.899261] func: cpuhp_up_callbacks, st->state: 13, line: 628, CPU: 0
[  150.899387] func: cpuhp_up_callbacks, st->state: 14, line: 628, CPU: 0
[  150.899517] func: cpuhp_up_callbacks, st->state: 15, line: 628, CPU: 0
[  150.899649] func: cpuhp_up_callbacks, st->state: 16, line: 628, CPU: 0
[  150.899781] func: cpuhp_up_callbacks, st->state: 17, line: 628, CPU: 0
[  150.899911] func: cpuhp_up_callbacks, st->state: 18, line: 628, CPU: 0
[  150.900043] func: cpuhp_up_callbacks, st->state: 19, line: 628, CPU: 0
[  150.900176] func: cpuhp_up_callbacks, st->state: 20, line: 628, CPU: 0
[  150.900306] func: cpuhp_up_callbacks, st->state: 21, line: 628, CPU: 0
[  150.900441] func: cpuhp_up_callbacks, st->state: 22, line: 628, CPU: 0
[  150.900571] func: cpuhp_up_callbacks, st->state: 23, line: 628, CPU: 0
[  150.900701] func: cpuhp_up_callbacks, st->state: 24, line: 628, CPU: 0
[  150.900827] func: cpuhp_up_callbacks, st->state: 25, line: 628, CPU: 0
[  150.900956] func: cpuhp_up_callbacks, st->state: 26, line: 628, CPU: 0
[  150.901088] func: cpuhp_up_callbacks, st->state: 27, line: 628, CPU: 0
[  150.901221] func: cpuhp_up_callbacks, st->state: 28, line: 628, CPU: 0
[  150.901352] func: cpuhp_up_callbacks, st->state: 29, line: 628, CPU: 0
[  150.901489] func: cpuhp_up_callbacks, st->state: 30, line: 628, CPU: 0
[  150.904508] func: cpuhp_up_callbacks, st->state: 31, line: 628, CPU: 0
[  150.904657] func: cpuhp_up_callbacks, st->state: 32, line: 628, CPU: 0
[  150.904805] func: cpuhp_up_callbacks, st->state: 33, line: 628, CPU: 0
[  150.904945] func: cpuhp_up_callbacks, st->state: 34, line: 628, CPU: 0
[  150.905082] func: cpuhp_up_callbacks, st->state: 35, line: 628, CPU: 0
[  150.905220] func: cpuhp_up_callbacks, st->state: 36, line: 628, CPU: 0
[  150.905363] func: cpuhp_up_callbacks, st->state: 37, line: 628, CPU: 0
[  150.905517] func: cpuhp_up_callbacks, st->state: 38, line: 628, CPU: 0
[  150.906525] func: cpuhp_up_callbacks, st->state: 39, line: 628, CPU: 0
[  150.906674] func: cpuhp_up_callbacks, st->state: 40, line: 628, CPU: 0
[  150.906814] func: cpuhp_up_callbacks, st->state: 41, line: 628, CPU: 0
[  150.906949] func: cpuhp_up_callbacks, st->state: 42, line: 628, CPU: 0
[  150.907108] func: cpuhp_up_callbacks, st->state: 43, line: 628, CPU: 0
[  150.907242] func: cpuhp_up_callbacks, st->state: 44, line: 628, CPU: 0
[  150.907376] func: cpuhp_up_callbacks, st->state: 45, line: 628, CPU: 0
[  150.907512] func: cpuhp_up_callbacks, st->state: 46, line: 628, CPU: 0
[  150.907649] func: cpuhp_up_callbacks, st->state: 47, line: 628, CPU: 0
[  150.907784] func: cpuhp_up_callbacks, st->state: 48, line: 628, CPU: 0
[  150.907917] func: cpuhp_up_callbacks, st->state: 49, line: 628, CPU: 0
[  150.908048] func: cpuhp_up_callbacks, st->state: 50, line: 628, CPU: 0
[  150.908179] func: cpuhp_up_callbacks, st->state: 51, line: 628, CPU: 0
[  150.908308] func: cpuhp_up_callbacks, st->state: 52, line: 628, CPU: 0
[  150.908437] func: cpuhp_up_callbacks, st->state: 53, line: 628, CPU: 0
[  150.908571] func: cpuhp_up_callbacks, st->state: 54, line: 628, CPU: 0
[  150.908705] func: cpuhp_up_callbacks, st->state: 55, line: 628, CPU: 0
[  150.908892] func: cpuhp_up_callbacks, st->state: 56, line: 628, CPU: 0
[  150.909027] func: cpuhp_up_callbacks, st->state: 57, line: 628, CPU: 0
[  150.909157] func: cpuhp_up_callbacks, st->state: 58, line: 628, CPU: 0
[  150.909288] func: cpuhp_up_callbacks, st->state: 59, line: 628, CPU: 0
[  150.909419] func: cpuhp_up_callbacks, st->state: 60, line: 628, CPU: 0
[  150.911541] func: cpuhp_up_callbacks, st->state: 61, line: 628, CPU: 0
[  150.911692] func: cpuhp_up_callbacks, st->state: 62, line: 628, CPU: 0
[  150.911828] func: cpuhp_up_callbacks, st->state: 63, line: 628, CPU: 0
[  150.911960] func: cpuhp_up_callbacks, st->state: 64, line: 628, CPU: 0
[  150.912096] func: cpuhp_up_callbacks, st->state: 65, line: 628, CPU: 0
[  150.912227] func: cpuhp_up_callbacks, st->state: 66, line: 628, CPU: 0
[  150.912360] func: cpuhp_up_callbacks, st->state: 67, line: 628, CPU: 0
[  150.912490] func: cpuhp_up_callbacks, st->state: 68, line: 628, CPU: 0
[  150.912629] func: cpuhp_up_callbacks, st->state: 69, line: 628, CPU: 0
[  150.912770] func: cpuhp_up_callbacks, st->state: 70, line: 628, CPU: 0
[  150.912904] func: cpuhp_up_callbacks, st->state: 71, line: 628, CPU: 0
[  150.913040] func: cpuhp_up_callbacks, st->state: 72, line: 628, CPU: 0
[  150.913176] func: cpuhp_up_callbacks, st->state: 73, line: 628, CPU: 0
[  150.913311] func: cpuhp_up_callbacks, st->state: 74, line: 628, CPU: 0
[  150.913447] func: cpuhp_up_callbacks, st->state: 75, line: 628, CPU: 0
[  150.915031] func: cpuhp_up_callbacks, st->state: 76, line: 628, CPU: 0
[  150.915174] func: cpuhp_up_callbacks, st->state: 77, line: 628, CPU: 0
[  150.915308] func: cpuhp_up_callbacks, st->state: 78, line: 628, CPU: 0
[  150.915440] func: cpuhp_up_callbacks, st->state: 79, line: 628, CPU: 0
[  150.915575] func: cpuhp_up_callbacks, st->state: 80, line: 628, CPU: 0
[  150.915712] func: cpuhp_up_callbacks, st->state: 81, line: 628, CPU: 0
[  150.915847] func: cpuhp_up_callbacks, st->state: 82, line: 628, CPU: 0
[  150.915980] func: cpuhp_up_callbacks, st->state: 83, line: 628, CPU: 0
[  150.916111] func: cpuhp_up_callbacks, st->state: 84, line: 628, CPU: 0
[  150.916242] func: cpuhp_up_callbacks, st->state: 85, line: 628, CPU: 0
[  150.916368] func: cpuhp_up_callbacks, st->state: 86, line: 628, CPU: 0
[  150.916503] func: cpuhp_up_callbacks, st->state: 87, line: 628, CPU: 0
[  150.916641] func: bringup_cpu  line: 558, CPU: 0
[  150.916869] func: bringup_cpu: before __cpu_up line: 566, CPU: 0 
[  150.916995] func: __cpu_up  line: 106, CPU: 0
[  150.917091] psci: func: psci_cpu_on  line: 199, entry_point: 40c9e1e0, CPU: 0
[  150.917233] psci: func: __invoke_psci_fn_hvc  line: 136, CPU: 0
[  150.917471] Detected VIPT I-cache on CPU3
[  150.917602] GICv3: CPU3: found redistributor 3 region 0:0x0000000008100000
[  150.918077] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]
[  150.918242] func: cpu_startup_entry, line: 365
[  150.918344] func: cpu_startup_entry, before cpuhp_online_idle function line: 367, CPU: 3 
[  150.918530] func: cpu_startup_entry, after cpuhp_online_idle function line: 369, CPU: 3 
[  150.920524] func: __cpu_up: after wait_for_completion_timeout line: 127, CPU: 0
[  150.920693] func: bringup_cpu: after __cpu_up line: 569, CPU: 0
[  150.920819] func: bringup_cpu: before bringup_wait_for_ap line: 575, CPU: 0 
[  150.920961] func: bringup_wait_for_ap: before wait_for_ap_thread line: 525, CPU: 0
[  150.921115] func: bringup_wait_for_ap: after wait_for_ap_thread line: 530, CPU: 0
[  150.921278] func: bringup_wait_for_ap: before cpuhp_kick_ap line: 548, CPU: 0
[  150.921497] func: cpuhp_thread_fun st->state: 140, line: 696, CPU: 3
[  150.921522] func: cpuhp_thread_fun st->state: 141, line: 696, CPU: 3
[  150.921718] func: cpuhp_thread_fun st->state: 142, line: 696, CPU: 3
[  150.921854] func: cpuhp_thread_fun st->state: 143, line: 696, CPU: 3
[  150.921977] func: cpuhp_thread_fun st->state: 144, line: 696, CPU: 3
[  150.922085] func: cpuhp_thread_fun st->state: 145, line: 696, CPU: 3
[  150.922194] func: cpuhp_thread_fun st->state: 146, line: 696, CPU: 3
[  150.922300] func: cpuhp_thread_fun st->state: 147, line: 696, CPU: 3
[  150.922399] func: cpuhp_thread_fun st->state: 148, line: 696, CPU: 3
[  150.922515] func: cpuhp_thread_fun st->state: 149, line: 696, CPU: 3
[  150.922621] func: cpuhp_thread_fun st->state: 150, line: 696, CPU: 3
[  150.922725] func: cpuhp_thread_fun st->state: 151, line: 696, CPU: 3
[  150.922832] func: cpuhp_thread_fun st->state: 152, line: 696, CPU: 3
[  150.922933] func: cpuhp_thread_fun st->state: 153, line: 696, CPU: 3
[  150.923051] func: cpuhp_thread_fun st->state: 154, line: 696, CPU: 3
[  150.923166] func: cpuhp_thread_fun st->state: 155, line: 696, CPU: 3
[  150.923269] func: cpuhp_thread_fun st->state: 156, line: 696, CPU: 3
[  150.923380] func: cpuhp_thread_fun st->state: 157, line: 696, CPU: 3
[  150.923501] func: cpuhp_thread_fun st->state: 158, line: 696, CPU: 3
[  150.923604] func: cpuhp_thread_fun st->state: 159, line: 696, CPU: 3
[  150.923723] func: cpuhp_thread_fun st->state: 160, line: 696, CPU: 3
[  150.923831] func: cpuhp_thread_fun st->state: 161, line: 696, CPU: 3
[  150.923953] func: cpuhp_thread_fun st->state: 162, line: 696, CPU: 3
[  150.924064] func: cpuhp_thread_fun st->state: 163, line: 696, CPU: 3
[  150.924175] func: cpuhp_thread_fun st->state: 164, line: 696, CPU: 3
[  150.924288] func: cpuhp_thread_fun st->state: 165, line: 696, CPU: 3
[  150.924395] func: cpuhp_thread_fun st->state: 166, line: 696, CPU: 3
[  150.924508] func: cpuhp_thread_fun st->state: 167, line: 696, CPU: 3
[  150.924619] func: cpuhp_thread_fun st->state: 168, line: 696, CPU: 3
[  150.924735] func: cpuhp_thread_fun st->state: 169, line: 696, CPU: 3
[  150.924844] func: cpuhp_thread_fun st->state: 170, line: 696, CPU: 3
[  150.925051] func: cpuhp_thread_fun st->state: 171, line: 696, CPU: 3
[  150.925168] func: cpuhp_thread_fun st->state: 172, line: 696, CPU: 3
[  150.925287] func: cpuhp_thread_fun st->state: 173, line: 696, CPU: 3
[  150.925401] func: cpuhp_thread_fun st->state: 174, line: 696, CPU: 3
[  150.925511] func: cpuhp_thread_fun st->state: 175, line: 696, CPU: 3
[  150.925685] func: cpuhp_thread_fun st->state: 176, line: 696, CPU: 3
[  150.925816] func: cpuhp_thread_fun st->state: 177, line: 696, CPU: 3
[  150.925983] func: cpuhp_thread_fun st->state: 178, line: 696, CPU: 3
[  150.926103] func: cpuhp_thread_fun st->state: 179, line: 696, CPU: 3
[  150.926224] func: cpuhp_thread_fun st->state: 180, line: 696, CPU: 3
[  150.926367] func: cpuhp_thread_fun st->state: 181, line: 696, CPU: 3
[  150.926487] func: cpuhp_thread_fun st->state: 182, line: 696, CPU: 3
[  150.926611] func: cpuhp_thread_fun st->state: 183, line: 696, CPU: 3
[  150.926722] func: cpuhp_thread_fun st->state: 184, line: 696, CPU: 3
[  150.926830] func: cpuhp_thread_fun st->state: 185, line: 696, CPU: 3
[  150.926928] func: cpuhp_thread_fun st->state: 186, line: 696, CPU: 3
[  150.927028] func: cpuhp_thread_fun st->state: 187, line: 696, CPU: 3
[  150.927145] func: cpuhp_thread_fun st->state: 188, line: 696, CPU: 3
[  150.927259] func: cpuhp_thread_fun st->state: 189, line: 696, CPU: 3
[  150.927360] func: cpuhp_thread_fun st->state: 190, line: 696, CPU: 3
[  150.927468] func: cpuhp_thread_fun st->state: 191, line: 696, CPU: 3
[  150.927581] func: cpuhp_thread_fun st->state: 192, line: 696, CPU: 3
[  150.927687] func: cpuhp_thread_fun st->state: 193, line: 696, CPU: 3
[  150.927789] func: cpuhp_thread_fun st->state: 194, line: 696, CPU: 3
[  150.927902] func: cpuhp_thread_fun st->state: 195, line: 696, CPU: 3
[  150.928023] func: cpuhp_thread_fun st->state: 196, line: 696, CPU: 3
[  150.928132] func: cpuhp_thread_fun st->state: 197, line: 696, CPU: 3
[  150.928251] func: cpuhp_thread_fun st->state: 198, line: 696, CPU: 3
[  150.928357] func: cpuhp_thread_fun st->state: 199, line: 696, CPU: 3
[  150.928469] func: cpuhp_thread_fun st->state: 200, line: 696, CPU: 3
[  150.928580] func: cpuhp_thread_fun st->state: 201, line: 696, CPU: 3
[  150.928689] func: cpuhp_thread_fun st->state: 202, line: 696, CPU: 3
[  150.928798] func: cpuhp_thread_fun st->state: 203, line: 696, CPU: 3
[  150.928914] func: cpuhp_thread_fun st->state: 204, line: 696, CPU: 3
[  150.929018] func: cpuhp_thread_fun st->state: 205, line: 696, CPU: 3
[  150.929125] func: cpuhp_thread_fun st->state: 206, line: 696, CPU: 3
[  150.929232] func: cpuhp_thread_fun st->state: 207, line: 696, CPU: 3
[  150.929389] func: cpuhp_thread_fun st->state: 208, line: 696, CPU: 3
[  150.929503] func: cpuhp_thread_fun before complete_ap_thread st->state: 209 , line: 744, CPU: 3
[  150.929768] func: bringup_cpu: after bringup_wait_for_ap line: 577, CPU: 0 
[  150.930102] func: _cpu_up: after cpuhp_up_callbacks line: 1269, CPU: 0 
# 

        可以看到 CPU_ON 最开始是由 BP 调用状态机中的回调函数,当调用到第 87 (CPUHP_BRINGUP_CPU)个状态时,调用 bringup_cpu 回调进行开核,当 AP 启动之后会自己调用后面状态的回调,直至 AP 状态等于 209 (CPUHP_ONLINE)。

2、CPU_OFF

        CPU_OFF 的执行过程刚好和 CPU_ON 相反,当一个 CPU 的状态从 CPUHP_ONLINE 变成 CPUHP_OFFLINE 时,说明这个 CPU 已经被关闭了。

        如上图所示,当需要关闭一个 CPU 时,BP 会先调用 cpuhp_kick_ap_work 函数让 AP 的 hotplug 线程去执行状态转换,会从 CPUHP_ONLINE 转换成 CPUHP_TEARDOWN_CPU,然后执行 takedown_cpu 回调函数,在该回调函数中会通过 stop_machine_cpuslocked 函数将 AP 设置为 离线状态,然后在 AP 的 idle 线程中会调用 cpu_is_offline 函数来检测 AP 是否已经离线,如果已经离线则会调用 cpuhp_report_idle_dead 函数告诉 BP,BP 会在__cpu_die函数中调用cpu_wait_death函数等待 AP 死亡,这时 AP 就会调用 arch_cpu_idle_dead 函数,告诉 BP 这个cpu现在可以安全地处理了,然后调用 psci_cpu_off 通过 smc 陷入到 ATF 中完成 AP 的下电操作,当 takedown_cpu 函数执行完成后 BP 会回到 cpuhp_down_callbacks 函数中继续调用 AP 后续状态的回调函数,直到 AP 状态变成 CPUHP_OFFLINE 为止,当 AP 状态变成 CPUHP_OFFLINE 时,AP 也就完全关闭了。

CPU_OFF 执行log:

注意:

1、本测试平台为 qemu,所以最后是 hvc 陷入到 hypervisor,而不是smc陷入到 ATF。

2、func 表示本行打印所在函数,line 表示行数,st->state 表示CPU的当前状态,CPU表示执行这一行代码的 CPU。

# echo 0 > /sys/devices/system/cpu/cpu3/online 
[  105.166968] func: cpu_subsys_offline  line: 72, CPU: 3
[  105.167080] func: _cpu_down  line: 1076, CPU: 3
[  105.181625] func: _cpu_down: before cpuhp_kick_ap_work line: 1094, CPU: 3
[  105.181770] func: cpuhp_thread_fun st->state: 209, line: 696, CPU: 3
[  105.181778] func: cpuhp_thread_fun st->state: 208, line: 696, CPU: 3
[  105.213647] func: cpuhp_thread_fun st->state: 207, line: 696, CPU: 3
[  105.213833] func: cpuhp_thread_fun st->state: 206, line: 696, CPU: 3
[  105.213993] func: cpuhp_thread_fun st->state: 205, line: 696, CPU: 3
[  105.214168] func: cpuhp_thread_fun st->state: 204, line: 696, CPU: 3
[  105.214338] func: cpuhp_thread_fun st->state: 203, line: 696, CPU: 3
[  105.214444] func: cpuhp_thread_fun st->state: 202, line: 696, CPU: 3
[  105.214539] func: cpuhp_thread_fun st->state: 201, line: 696, CPU: 3
[  105.214634] func: cpuhp_thread_fun st->state: 200, line: 696, CPU: 3
[  105.214730] func: cpuhp_thread_fun st->state: 199, line: 696, CPU: 3
[  105.214826] func: cpuhp_thread_fun st->state: 198, line: 696, CPU: 3
[  105.214926] func: cpuhp_thread_fun st->state: 197, line: 696, CPU: 3
[  105.215021] func: cpuhp_thread_fun st->state: 196, line: 696, CPU: 3
[  105.215113] func: cpuhp_thread_fun st->state: 195, line: 696, CPU: 3
[  105.215208] func: cpuhp_thread_fun st->state: 194, line: 696, CPU: 3
[  105.215304] func: cpuhp_thread_fun st->state: 193, line: 696, CPU: 3
[  105.215396] func: cpuhp_thread_fun st->state: 192, line: 696, CPU: 3
[  105.215487] func: cpuhp_thread_fun st->state: 191, line: 696, CPU: 3
[  105.215577] func: cpuhp_thread_fun st->state: 190, line: 696, CPU: 3
[  105.215669] func: cpuhp_thread_fun st->state: 189, line: 696, CPU: 3
[  105.215765] func: cpuhp_thread_fun st->state: 188, line: 696, CPU: 3
[  105.215861] func: cpuhp_thread_fun st->state: 187, line: 696, CPU: 3
[  105.215955] func: cpuhp_thread_fun st->state: 186, line: 696, CPU: 3
[  105.216053] func: cpuhp_thread_fun st->state: 185, line: 696, CPU: 3
[  105.216148] func: cpuhp_thread_fun st->state: 184, line: 696, CPU: 3
[  105.216246] func: cpuhp_thread_fun st->state: 183, line: 696, CPU: 3
[  105.216348] func: cpuhp_thread_fun st->state: 182, line: 696, CPU: 3
[  105.216445] func: cpuhp_thread_fun st->state: 181, line: 696, CPU: 3
[  105.216548] func: cpuhp_thread_fun st->state: 180, line: 696, CPU: 3
[  105.216648] func: cpuhp_thread_fun st->state: 179, line: 696, CPU: 3
[  105.216748] func: cpuhp_thread_fun st->state: 178, line: 696, CPU: 3
[  105.216878] func: cpuhp_thread_fun st->state: 177, line: 696, CPU: 3
[  105.216977] func: cpuhp_thread_fun st->state: 176, line: 696, CPU: 3
[  105.217076] func: cpuhp_thread_fun st->state: 175, line: 696, CPU: 3
[  105.217174] func: cpuhp_thread_fun st->state: 174, line: 696, CPU: 3
[  105.217270] func: cpuhp_thread_fun st->state: 173, line: 696, CPU: 3
[  105.217371] func: cpuhp_thread_fun st->state: 172, line: 696, CPU: 3
[  105.217461] func: cpuhp_thread_fun st->state: 171, line: 696, CPU: 3
[  105.217701] func: cpuhp_thread_fun st->state: 170, line: 696, CPU: 3
[  105.217823] func: cpuhp_thread_fun st->state: 169, line: 696, CPU: 3
[  105.217931] func: cpuhp_thread_fun st->state: 168, line: 696, CPU: 3
[  105.218033] func: cpuhp_thread_fun st->state: 167, line: 696, CPU: 3
[  105.218138] func: cpuhp_thread_fun st->state: 166, line: 696, CPU: 3
[  105.218248] func: cpuhp_thread_fun st->state: 165, line: 696, CPU: 3
[  105.218371] func: cpuhp_thread_fun st->state: 164, line: 696, CPU: 3
[  105.218482] func: cpuhp_thread_fun st->state: 163, line: 696, CPU: 3
[  105.218594] func: cpuhp_thread_fun st->state: 162, line: 696, CPU: 3
[  105.218707] func: cpuhp_thread_fun st->state: 161, line: 696, CPU: 3
[  105.218818] func: cpuhp_thread_fun st->state: 160, line: 696, CPU: 3
[  105.218922] func: cpuhp_thread_fun st->state: 159, line: 696, CPU: 3
[  105.219029] func: cpuhp_thread_fun st->state: 158, line: 696, CPU: 3
[  105.219136] func: cpuhp_thread_fun st->state: 157, line: 696, CPU: 3
[  105.219243] func: cpuhp_thread_fun st->state: 156, line: 696, CPU: 3
[  105.219352] func: cpuhp_thread_fun st->state: 155, line: 696, CPU: 3
[  105.219453] func: cpuhp_thread_fun st->state: 154, line: 696, CPU: 3
[  105.219565] func: cpuhp_thread_fun st->state: 153, line: 696, CPU: 3
[  105.219670] func: cpuhp_thread_fun st->state: 152, line: 696, CPU: 3
[  105.219793] func: cpuhp_thread_fun st->state: 151, line: 696, CPU: 3
[  105.219907] func: cpuhp_thread_fun st->state: 150, line: 696, CPU: 3
[  105.220019] func: cpuhp_thread_fun st->state: 149, line: 696, CPU: 3
[  105.220128] func: cpuhp_thread_fun st->state: 148, line: 696, CPU: 3
[  105.220240] func: cpuhp_thread_fun st->state: 147, line: 696, CPU: 3
[  105.220351] func: cpuhp_thread_fun st->state: 146, line: 696, CPU: 3
[  105.220471] func: cpuhp_thread_fun st->state: 145, line: 696, CPU: 3
[  105.220577] func: cpuhp_thread_fun st->state: 144, line: 696, CPU: 3
[  105.220693] func: cpuhp_thread_fun st->state: 143, line: 696, CPU: 3
[  105.220801] func: cpuhp_thread_fun st->state: 142, line: 696, CPU: 3
[  105.220912] func: cpuhp_thread_fun st->state: 141, line: 696, CPU: 3
[  105.221046] func: cpuhp_thread_fun st->state: 140, line: 696, CPU: 3
[  105.221158] func: cpuhp_thread_fun before complete_ap_thread st->state: 139 , line: 744, CPU: 3
[  105.221318] func: _cpu_down: after cpuhp_kick_ap_work line: 1096, CPU: 0
[  105.221607] func: _cpu_down: before cpuhp_down_callbacks line: 1117, CPU: 0
[  105.221713] func: cpuhp_down_callbacks, st->state: 139, line: 1057 CPU: 0
[  105.221819] func: takedown_cpu  line: 969, CPU: 0
[  105.221950] func: stop_machine_cpuslocked  line: 606, CPU: 0
[  105.222063] func: cpu_stopper_thread  line: 502, CPU: 0
[  105.222067] func: cpu_stopper_thread  line: 502, CPU: 3
[  105.222143] func: multi_cpu_stop  line: 196, CPU: 0
[  105.222233] func: multi_cpu_stop  line: 196, CPU: 3
[  105.222393] func: take_cpu_down  line: 935, CPU: 3
[  105.222481] func: __cpu_disable  line: 294, CPU: 3
[  105.222628] func: cpu_stop_signal_done  line: 64, CPU: 0
[  105.222631] func: cpu_stop_signal_done  line: 64, CPU: 3
[  105.222863] func: cpu_die  line: 367, CPU: 3
[  105.222879] func: cpuhp_complete_idle_dead  line: 1023, CPU: 0
[  105.222937] psci: func: cpu_psci_cpu_die  line: 78, CPU: 3
[  105.223123] psci: func: psci_cpu_off  line: 188, CPU: 3
[  105.223176] func: takedown_cpu: before wait_for_ap_thread line: 1001, CPU: 0
[  105.223210] psci: func: __invoke_psci_fn_hvc  line: 136, CPU: 3
[  105.223325] func: takedown_cpu: after wait_for_ap_thread line: 1003, CPU: 0
[  105.223522] func: takedown_cpu: before __cpu_die line: 1011, CPU: 0
[  105.223616] func: __cpu_die: before cpu_wait_death line: 337, CPU: 0
[  105.223712] func: __cpu_die: after cpu_wait_death line: 342, CPU: 0
[  105.223806] CPU3: shutdown
[  105.223850] func: __cpu_die: before op_cpu_kill line: 351, CPU: 0
[  105.223938] func: op_cpu_kill  line: 325, CPU: 0
[  105.224006] psci: func: cpu_psci_cpu_kill  line: 94, CPU: 0
[  105.224089] psci: func: psci_affinity_info  line: 219, CPU: 0
[  105.224172] psci: func: __invoke_psci_fn_hvc  line: 136, CPU: 0
[  105.224268] psci: CPU3 killed (polled 0 ms)
[  105.224336] func: __cpu_die: after op_cpu_kill line: 353, CPU: 0
[  105.224431] func: takedown_cpu: after __cpu_die line: 1013, CPU: 0
[  105.224541] func: cpuhp_down_callbacks, st->state: 87, line: 1057 CPU: 0
[  105.224658] func: cpuhp_down_callbacks, st->state: 86, line: 1057 CPU: 0
[  105.224761] func: cpuhp_down_callbacks, st->state: 85, line: 1057 CPU: 0
[  105.224855] func: cpuhp_down_callbacks, st->state: 84, line: 1057 CPU: 0
[  105.224961] func: cpuhp_down_callbacks, st->state: 83, line: 1057 CPU: 0
[  105.225061] func: cpuhp_down_callbacks, st->state: 82, line: 1057 CPU: 0
[  105.225161] func: cpuhp_down_callbacks, st->state: 81, line: 1057 CPU: 0
[  105.225258] func: cpuhp_down_callbacks, st->state: 80, line: 1057 CPU: 0
[  105.225359] func: cpuhp_down_callbacks, st->state: 79, line: 1057 CPU: 0
[  105.225454] func: cpuhp_down_callbacks, st->state: 78, line: 1057 CPU: 0
[  105.225590] func: cpuhp_down_callbacks, st->state: 77, line: 1057 CPU: 0
[  105.225695] func: cpuhp_down_callbacks, st->state: 76, line: 1057 CPU: 0
[  105.225795] func: cpuhp_down_callbacks, st->state: 75, line: 1057 CPU: 0
[  105.225893] func: cpuhp_down_callbacks, st->state: 74, line: 1057 CPU: 0
[  105.225992] func: cpuhp_down_callbacks, st->state: 73, line: 1057 CPU: 0
[  105.226088] func: cpuhp_down_callbacks, st->state: 72, line: 1057 CPU: 0
[  105.226184] func: cpuhp_down_callbacks, st->state: 71, line: 1057 CPU: 0
[  105.226281] func: cpuhp_down_callbacks, st->state: 70, line: 1057 CPU: 0
[  105.226378] func: cpuhp_down_callbacks, st->state: 69, line: 1057 CPU: 0
[  105.226480] func: cpuhp_down_callbacks, st->state: 68, line: 1057 CPU: 0
[  105.226576] func: cpuhp_down_callbacks, st->state: 67, line: 1057 CPU: 0
[  105.226679] func: cpuhp_down_callbacks, st->state: 66, line: 1057 CPU: 0
[  105.226797] func: cpuhp_down_callbacks, st->state: 65, line: 1057 CPU: 0
[  105.226893] func: cpuhp_down_callbacks, st->state: 64, line: 1057 CPU: 0
[  105.227002] func: cpuhp_down_callbacks, st->state: 63, line: 1057 CPU: 0
[  105.227096] func: cpuhp_down_callbacks, st->state: 62, line: 1057 CPU: 0
[  105.227191] func: cpuhp_down_callbacks, st->state: 61, line: 1057 CPU: 0
[  105.227290] func: cpuhp_down_callbacks, st->state: 60, line: 1057 CPU: 0
[  105.227445] func: cpuhp_down_callbacks, st->state: 59, line: 1057 CPU: 0
[  105.227579] func: cpuhp_down_callbacks, st->state: 58, line: 1057 CPU: 0
[  105.227681] func: cpuhp_down_callbacks, st->state: 57, line: 1057 CPU: 0
[  105.227784] func: cpuhp_down_callbacks, st->state: 56, line: 1057 CPU: 0
[  105.227879] func: cpuhp_down_callbacks, st->state: 55, line: 1057 CPU: 0
[  105.228001] func: cpuhp_down_callbacks, st->state: 54, line: 1057 CPU: 0
[  105.228098] func: cpuhp_down_callbacks, st->state: 53, line: 1057 CPU: 0
[  105.228195] func: cpuhp_down_callbacks, st->state: 52, line: 1057 CPU: 0
[  105.228290] func: cpuhp_down_callbacks, st->state: 51, line: 1057 CPU: 0
[  105.228388] func: cpuhp_down_callbacks, st->state: 50, line: 1057 CPU: 0
[  105.228482] func: cpuhp_down_callbacks, st->state: 49, line: 1057 CPU: 0
[  105.228579] func: cpuhp_down_callbacks, st->state: 48, line: 1057 CPU: 0
[  105.228677] func: cpuhp_down_callbacks, st->state: 47, line: 1057 CPU: 0
[  105.228777] func: cpuhp_down_callbacks, st->state: 46, line: 1057 CPU: 0
[  105.228870] func: cpuhp_down_callbacks, st->state: 45, line: 1057 CPU: 0
[  105.228971] func: cpuhp_down_callbacks, st->state: 44, line: 1057 CPU: 0
[  105.229067] func: cpuhp_down_callbacks, st->state: 43, line: 1057 CPU: 0
[  105.229165] func: cpuhp_down_callbacks, st->state: 42, line: 1057 CPU: 0
[  105.229272] func: cpuhp_down_callbacks, st->state: 41, line: 1057 CPU: 0
[  105.229370] func: cpuhp_down_callbacks, st->state: 40, line: 1057 CPU: 0
[  105.229475] func: cpuhp_down_callbacks, st->state: 39, line: 1057 CPU: 0
[  105.237927] func: cpuhp_down_callbacks, st->state: 38, line: 1057 CPU: 0
[  105.238038] func: cpuhp_down_callbacks, st->state: 37, line: 1057 CPU: 0
[  105.238139] func: cpuhp_down_callbacks, st->state: 36, line: 1057 CPU: 0
[  105.238260] func: cpuhp_down_callbacks, st->state: 35, line: 1057 CPU: 0
[  105.238361] func: cpuhp_down_callbacks, st->state: 34, line: 1057 CPU: 0
[  105.238464] func: cpuhp_down_callbacks, st->state: 33, line: 1057 CPU: 0
[  105.238574] func: cpuhp_down_callbacks, st->state: 32, line: 1057 CPU: 0
[  105.238671] func: cpuhp_down_callbacks, st->state: 31, line: 1057 CPU: 0
[  105.238775] func: cpuhp_down_callbacks, st->state: 30, line: 1057 CPU: 0
[  105.241146] func: cpuhp_down_callbacks, st->state: 29, line: 1057 CPU: 0
[  105.241410] func: cpuhp_down_callbacks, st->state: 28, line: 1057 CPU: 0
[  105.241521] func: cpuhp_down_callbacks, st->state: 27, line: 1057 CPU: 0
[  105.241702] func: cpuhp_down_callbacks, st->state: 26, line: 1057 CPU: 0
[  105.241812] func: cpuhp_down_callbacks, st->state: 25, line: 1057 CPU: 0
[  105.241913] func: cpuhp_down_callbacks, st->state: 24, line: 1057 CPU: 0
[  105.242012] func: cpuhp_down_callbacks, st->state: 23, line: 1057 CPU: 0
[  105.242119] func: cpuhp_down_callbacks, st->state: 22, line: 1057 CPU: 0
[  105.242218] func: cpuhp_down_callbacks, st->state: 21, line: 1057 CPU: 0
[  105.242321] func: cpuhp_down_callbacks, st->state: 20, line: 1057 CPU: 0
[  105.245616] func: cpuhp_down_callbacks, st->state: 19, line: 1057 CPU: 0
[  105.245734] func: cpuhp_down_callbacks, st->state: 18, line: 1057 CPU: 0
[  105.245833] func: cpuhp_down_callbacks, st->state: 17, line: 1057 CPU: 0
[  105.245938] func: cpuhp_down_callbacks, st->state: 16, line: 1057 CPU: 0
[  105.246042] func: cpuhp_down_callbacks, st->state: 15, line: 1057 CPU: 0
[  105.246140] func: cpuhp_down_callbacks, st->state: 14, line: 1057 CPU: 0
[  105.247745] func: cpuhp_down_callbacks, st->state: 13, line: 1057 CPU: 0
[  105.247860] func: cpuhp_down_callbacks, st->state: 12, line: 1057 CPU: 0
[  105.247964] func: cpuhp_down_callbacks, st->state: 11, line: 1057 CPU: 0
[  105.248260] func: cpuhp_down_callbacks, st->state: 10, line: 1057 CPU: 0
[  105.248388] func: cpuhp_down_callbacks, st->state: 9, line: 1057 CPU: 0
[  105.248487] func: cpuhp_down_callbacks, st->state: 8, line: 1057 CPU: 0
[  105.248582] func: cpuhp_down_callbacks, st->state: 7, line: 1057 CPU: 0
[  105.248677] func: cpuhp_down_callbacks, st->state: 6, line: 1057 CPU: 0
[  105.248779] func: cpuhp_down_callbacks, st->state: 5, line: 1057 CPU: 0
[  105.248875] func: cpuhp_down_callbacks, st->state: 4, line: 1057 CPU: 0
[  105.248971] func: cpuhp_down_callbacks, st->state: 3, line: 1057 CPU: 0
[  105.249066] func: cpuhp_down_callbacks, st->state: 2, line: 1057 CPU: 0
[  105.249163] func: cpuhp_down_callbacks, st->state: 1, line: 1057 CPU: 0
[  105.249259] func: _cpu_down: after cpuhp_down_callbacks line: 1119, CPU: 0
# 

      可以看到 CPU_OFF 最开始是由 AP 自己调用状态机中的回调函数,当调用到第 139(CPUHP_BRINGUP_CPU)个状态时,调用 takedown_cpu 回调进行关核,当被 AP 关闭之后 BP 会调用 AP 后面状态的回调,直至 AP 状态等于 0 (CPUHP_OFFLINE)。

References

[1] linux cpu hotplug_cpu offline-CSDN

[2] https://www.cnblogs.com/pengdonglin137/p/11925299.html

[3] https://zhuanlan.zhihu.com/p/545550388

[4] https://blog.csdn.net/chensong_2000/article/details/129442447

[5] https://blog.csdn.net/z20230508/article/details/143889879

[6] https://blog.csdn.net/big2chris/article/details/99588058

[7] https://www.cnblogs.com/lvzh/p/16401950.html

[8] https://zhuanlan.zhihu.com/p/501397835

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2266180.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

探索数据的艺术:R语言与Origin的完美结合

探索数据的艺术:R语言与Origin的完美结合 R语言统计分析与可视化从入门到精通内容简介获取方式 Origin绘图深度解析:科研数据的可视化艺术内容简介获取方式 R语言统计分析与可视化从入门到精通 内容简介 本书循序渐进、深入讲解了R语言数据统计分析与应…

python基础训练之元组的基本操作

主页包含元组基础知识点 【练习要求】 针对于元组的知识点进行常用的创建、定义、查询元素、查看元组长度等操作。效果实现如下 (注:特别要注意一下切片的用法) #创建元组的两种方法 T1 () T2 tuple() #定义一个元组并存储数据张三, 李四, 王五 T3 (张三, 李四…

选煤厂可视化技术助力智能化运营

通过图扑 HT 可视化搭建智慧选煤厂管理平台,优化了选煤生产流程,提高了资源利用率和安全性,助力企业实现智能化运营和可持续发展目标。

C语言基础:指针(数组指针与指针数组)

数组指针与指针数组 数组指针 概念:数组指针是指向数组的指针,本质上还是指针 特点: 先有数组,后有指针 它指向的是一个完整的数组 一维数组指针: 语法: 数据类型 (*指针变量名)[行容量][列容量]; 案…

接口测试Day03-postman断言关联

postman常用断言 注意:不需要手敲,点击自动生成 断言响应状态码 Status code:Code is 200 //断言响应状态码为 200 pm.test("Status code is 200", function () {pm.response.to.have.status(200); });pm: postman的实例 test() …

01- 三自由度串联机械臂位置分析

三自由度串联机械臂如下图所示(d180mm,L1100mm,L280mm),利用改进DH法建模,坐标系如下所示: 利用改进DH法建模,该机器人的DH参数表如下所示: 对该机械臂进行位置分析&…

lxml 解析xml\html

from lxml import etree# XML文档示例 xml_doc """ <root><book><title>Python编程指南</title><author>张三</author></book><book><title>Python高级编程</title><author>李四</autho…

用Python写炸金花游戏

文章目录 **代码分解与讲解**1. **扑克牌的生成与洗牌**2. **给玩家发牌**3. **打印玩家的手牌**4. **定义牌的优先级**5. **判断牌型**6. **确定牌型优先级**7. **比较两手牌的大小**8. **计算每个玩家的牌型并找出赢家**9. **打印结果** 完整代码 以下游戏规则&#xff1a; 那…

基于 SpringBoot微信小程序的医院预约挂号系统

摘 要 时代在飞速进步&#xff0c;每个行业都在努力发展现在先进技术&#xff0c;通过这些先进的技术来提高自己的水平和优势&#xff0c;医院预约挂号系统当然不能排除在外。医院预约挂号系统是在实际应用和软件工程的开发原理之上&#xff0c;运用微信开发者、java语言以及…

高仿CSDN编辑器,前端博客模板

高仿CSDN编辑器纯前端模板&#xff0c;使用的js、html、vue、axios等技术&#xff0c;网络请求库已进行封装&#xff0c;可以按需调整界面,需要源码联系(4k左右)。 1.支持代码高亮 2.支持目录点击定位 3.支持文件上传、图片上传&#xff08;需要自己写后端接口&#xff09; 4.M…

【C++11】类型分类、引用折叠、完美转发

目录 一、类型分类 二、引用折叠 三、完美转发 一、类型分类 C11以后&#xff0c;进一步对类型进行了划分&#xff0c;右值被划分纯右值(pure value&#xff0c;简称prvalue)和将亡值 (expiring value&#xff0c;简称xvalue)。 纯右值是指那些字面值常量或求值结果相当于…

在线oj项目 Ubuntu安装vue/cil(vue脚手架)

参考:https://blog.csdn.net/weixin_66062303/article/details/129046198 笔记 参考:https://blog.csdn.net/m0_74352571/article/details/144076227 https://cli.vuejs.org/zh/guide/installation.html 确保nodejs已经安装 npm换源淘宝镜像&#xff08;可以不操作或者使用魔…

Python字符串及正则表达式(十一):正则表达式、使用re模块实现正则表达式操作

前言&#xff1a;在 Python 编程的广阔天地中&#xff0c;字符串处理无疑是一项基础而关键的技能。正则表达式&#xff0c;作为处理字符串的强大工具&#xff0c;以其灵活的模式匹配能力&#xff0c;在文本搜索、数据清洗、格式验证等领域发挥着不可替代的作用。本系列博客已经…

项目37:简易个人健身记录器 --- 《跟着小王学Python·新手》

项目37&#xff1a;简易个人健身记录器 — 《跟着小王学Python新手》 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌…

华为:数字化转型只有“起点”,没有“终点”

上个月&#xff0c;我收到了一位朋友的私信&#xff0c;他询问我是否有关于华为数字化转型的资料。幸运的是&#xff0c;我手头正好收藏了一些&#xff0c;于是我便分享给他。 然后在昨天&#xff0c;他又再次联系我&#xff0c;并感慨&#xff1a;“如果当初我在进行企业数字…

count(1)、count(_)与count(列名)的区别?

大家好&#xff0c;我是锋哥。今天分享关于【count(1)、count(_)与count(列名)的区别&#xff1f;】面试题。希望对大家有帮助&#xff1b; count(1)、count(_)与count(列名)的区别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 SQL 中&#xff0c…

AAAI-2024 | 大语言模型赋能导航决策!NavGPT:基于大模型显式推理的视觉语言导航

作者&#xff1a;Gengze Zhou, Yicong Hong, Qi Wu 单位&#xff1a;阿德莱德大学&#xff0c;澳大利亚国立大学 论文链接&#xff1a; NavGPT: Explicit Reasoning in Vision-and-Language Navigation with Large Language Models &#xff08;https://ojs.aaai.org/index.p…

Linux高级--2.4.1 网络概念(分层、TCP)

关于网络分层理解的难点 对于一般人&#xff08;不参与设计和维护网络协议栈的人&#xff09;来讲&#xff0c;物理层和应用层很容易理解&#xff0c;也很好记住。首先&#xff0c;物理层是看的到的网线、基站的实体。再者&#xff0c;应用层是用户自己参与编写的程序。 而那…

使用VSCode Debugger 调试 React项目

一般我们调试代码时&#xff0c;用的最多的应该就是console.log方式了&#xff0c;还有的是使用Chrome DevTools 通过在对应的 sourcemap代码位置打断点进行调试&#xff0c;除了上面两种方式外还有一种更好用的调试方式&#xff1a; VSCode Debugger。 VSCode Debugger可以直…

Redis-十大数据类型

Reids数据类型指的是value的类型&#xff0c;key都是字符串 redis-server:启动redis服务 redis-cli:进入redis交互式终端 常用的key的操作 redis的命令和参数不区分大小写 &#xff0c;key和value区分 查看当前库所有的key keys * 判断某个key是否存在 exists key 查看key是什…