online 可以被调度的
active 可以被迁移的
present 内核已接管的
possible 系统存在的CPU,但没有被内核接管
cpu_down
\->_cpu_down(cpu, 0)
\->take_cpu_down
\->__cpu_disable()
\->mp_ops->cpu_disable()
\->__cpu_die(cpu)
cpu_up
\->_cpu_up
\->__cpu_up
\->mp_ops->boot_secondary(cpu, tidle)
start_kernel
setup_arch
arch_call_rest_init()--rest_init
kernel_thread(kernel_init)
kernel_init
kernel_init_freeable
smp_prepare_cpus
init_cpu_topology();
this_cpu = smp_processor_id
store_cpu_topology(this_cpu);
numa_store_cpu_info(this_cpu);
numa_add_cpu(this_cpu);
set_cpu_present(cpu, true);
numa_store_cpu_info(cpu);
smp_init
idle_threads_init(); /*初始化各个cpu上的idle thread*/
cpuhp_threads_init(); /*初始化各个cpu上的hotplug thread*/
smpboot_register_percpu_thread /*smp thread 即是 cpuhp_threads--> cpuhp_thread_fun?*/
cpu_up(cpu);
do_cpu_up(CPUHP_ONLINE)
try_online_node
_cpu_up
cpus_write_lock
idle_thread_get
cpuhp_set_state
cpuhp_kick_ap_work
cpuhp_kick_ap
__cpuhp_kick_ap(st);
smp_mb
wake_up_process(st-thread)
wait_for_ap_thread(st, st->bringup);
if ((ret = st->result)) {
cpuhp_reset_state
__cpuhp_kick_ap
}
cpuhp_up_callbacks
cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
cbm(cpu, node)
smp_cpus_done(setup_max_cpus); /*Total of %d processors activated*/
setup_cpu_features();
hyp_mode_check();
apply_alternatives_all();
mark_linear_text_alias_ro();
cpu_startup_entry()
do_idle(CPU_ONLINE)
st-thread---------->cpuhp_thread_fun
smp_mb
cpuhp_lock_acquire
cpuhp_invoke_callback
hlist_for_each(node, &step->list)
cbm(cpu, node);
******************
.bringup_cpu
__cpu_up
secondary_data.task = idle; /*设置起来的第一个task idle, stack, 关闭其MMU, 将dcache flush掉*/
secondary_data.stack = task_stack_page(idle) + THREAD_SIZE;
update_cpu_boot_status(CPU_MMU_OFF);
__flush_dcache_area(&secondary_data, sizeof(secondary_data));
boot_secondary
cpu_ops[cpu]->cpu_boot(cpu);
psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry)); /*从这里将回kernel的地址带下去, ENDPROC(secondary_entry)
定义在head.S里面*/
bringup_wait_for_ap
wait_for_ap_thread /*Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE*/
cpuhp_kick_ap
cpuhp_lock_release
complete_ap_thread
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_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 = NULL,
.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_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,
},
};