smp启动-secondary cpu 启动流程和boot cpu的交互点

上一篇:smp_init 整体流程-新核心执行 secondary_entry

https://www.cnblogs.com/zhangzhiwei122/p/16093602.html

 

secondary cpu启动流程

secondary_entry  //  arch/arm64/kernel/head.S

 

 ->secondary_startup

    ->secondary_switched

       ->secondary_start_kernel // arch/arm64/kernel/smp.c

         ->cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);  // kernel/sched/idle.c

 

过程分析

(1、先要有 primary_entry 启动过程分析相关知识,2、和primary 启动过程大同小异,3、下面的这篇很好):

https://www.cnblogs.com/pengdonglin137/p/11925299.html

 

boot cpu 和 secondary cpu 的交互点

1、cpu_running completion

等待 secondary cpu 设置 online

arch/arm64/kernel/smp.c

a: boot cpu 

 

 113int __cpu_up(unsigned int cpu, struct task_struct *idle)
 114{

 127        /* Now bring the CPU into our world */
 128        ret = boot_secondary(cpu, idle);
 129        if (ret) {
 130                pr_err("CPU%u: failed to boot: %d\n", cpu, ret);
 131                return ret;
 132        }
 133
 134        /*
 135         * CPU was successfully started, wait for it to come online or
 136         * time out.
 137         */
 138        wait_for_completion_timeout(&cpu_running,
 139                                    msecs_to_jiffies(5000));
 140        if (cpu_online(cpu))
 141                return 0;

 

128  - boot_secondary

138  - wait for completion_timeout

140 - if secondary cpu online , return 0;

b: secondary cpu

 199asmlinkage notrace void secondary_start_kernel(void)
 200{


 259         */
 260        pr_info("CPU%u: Booted secondary processor 0x%010lx [0x%08x]\n",
 261                                         cpu, (unsigned long)mpidr,
 262                                         read_cpuid_id());
 263        update_cpu_boot_status(CPU_BOOT_SUCCESS);
 264        set_cpu_online(cpu, true);
 265        complete(&cpu_running);

199 - 定义函数, secondary_start_kernel

264 - set online

265 - complete cpu running

 

2、bringup_cpu->bringup_wait_for_ap->wait_for_ap_thread ->wait_for_completion(st->done)

等 secondary cpu 设置(到达) CPUHP_AP_ONLINE_IDLE

 

kernel/cpu.c

a: boot cpu 流程

 

 242static inline void wait_for_ap_thread(struct cpuhp_cpu_state *st, bool bringup)
 243{
 244        struct completion *done = bringup ? &st->done_up : &st->done_down;
 245        wait_for_completion(done);
 246}


 519
 520static int bringup_wait_for_ap(unsigned int cpu)
 521{
 522        struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
 523
 524        /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */
 525        wait_for_ap_thread(st, true);
 526        if (WARN_ON_ONCE((!cpu_online(cpu))))
 527                return -ECANCELED;
 528
 529        /* Unpark the hotplug thread of the target cpu */
 530        kthread_unpark(st->thread);
 531


 548static int bringup_cpu(unsigned int cpu)
 549{

 560        /* Arch-specific enabling code. */
 561        ret = __cpu_up(cpu, idle);

 565        return bringup_wait_for_ap(cpu);
 566}

 

 

b: secondary cpu 流程

arch/arm64/kernel/smp.c

 199asmlinkage notrace void secondary_start_kernel(void)
 200{

 270         * OK, it's off to the idle thread for us
 271         */
 272        cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
 273}

kernel/sched/idle.c

 390void cpu_startup_entry(enum cpuhp_state state)
 391{
 392        arch_cpu_idle_prepare();
 393        cpuhp_online_idle(state);
 394        while (1)
 395                do_idle();
 396}

 

kernel/cpu.c

 248static inline void complete_ap_thread(struct cpuhp_cpu_state *st, bool bringup)
 249{
 250        struct completion *done = bringup ? &st->done_up : &st->done_down;
 251        complete(done);
 252}


1175void cpuhp_online_idle(enum cpuhp_state state) 1176{ 1177 struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 1189 st->state = CPUHP_AP_ONLINE_IDLE; 1190 complete_ap_thread(st, true); 1191}

 

3、__cpuhp_kick_ap->wait_for_ap_thread

等 secondary cpu 到达 CPUHP_ONLINE 状态,bringup_noboot_cpus->cpu_up(cpu, CPUHP_ONLINE);给定的 目标状态是 CPUHP_ONLINE

percpu  变量 cpuhp_state 中记录的 各个CPU的state,

 

从 CPUHP_OFFLINE(即 0 ) 到  CPUHP_AP_ONLINE_IDLE 由 boot cpu 作工作(调用函数完成),然后 bringup_cpu 等待 secondary cpu

进入到 CPUHP_AP_ONLINE_IDLE 。之后,给secondary cpu 执行 unparking cpuhp task, 由 secondary cpu 执行 cpuhp task ( smpboot_thread_fn->cpuhp_thread_fun 函数) 推进  secondary cpu cpuhp_state 的状态,从CPUHP_AP_ONLINE_IDLE  到 CPUHP_ONLINE

这儿等待 secondary cpu 状态到达 CPUHP_ONLINE 后返回。

cpuhp_up_callbacks 中的 while(st->state <target ) 循环结束, _cpu_up 函数返回, cpu_up 函数返回, bringup_noboot_cpus 函数返回

smp_init 函数 收到 bringup_noboot_cpus 函数调用的返回值。

a: boot cpu 流程

kernel/cpu.c

bringup_cpu
->bringup_wait_for_ap
 ->cpuhp_kick_ap
  ->__cpuhp_kick_ap
   ->wait_for_ap_thread



 488/* Regular hotplug invocation of the AP hotplug thread */
 489static void __cpuhp_kick_ap(struct cpuhp_cpu_state *st)
 490{

 500        st->should_run = true;
 501        wake_up_process(st->thread);
 502        wait_for_ap_thread(st, st->bringup);
 503}


 505static int cpuhp_kick_ap(struct cpuhp_cpu_state *st, enum cpuhp_state target)
 506{
 507        enum cpuhp_state prev_state;

 510        prev_state = cpuhp_set_state(st, target);
 511        __cpuhp_kick_ap(st);


 520static int bringup_wait_for_ap(unsigned int cpu)
 521{
 522        struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
 523
 524        /* Wait for the CPU to reach CPUHP_AP_ONLINE_IDLE */
 525        wait_for_ap_thread(st, true);

 545        return cpuhp_kick_ap(st, st->target);
 546}

b: secondary cpu 流程

smpboot_thread_fn      // kernel/smpboot.c
->cpuhp_thread_fun     // kernel/cpu.c
 ->complete_ap_thread  //kernel/cpu.c

kernel/smpboot.c

 107static int smpboot_thread_fn(void *data)
 108{
 109        struct smpboot_thread_data *td = data;
 110        struct smp_hotplug_thread *ht = td->ht;
 111
 112        while (1) {


 159                if (!ht->thread_should_run(td->cpu)) {
 160                        preempt_enable_no_resched();
 161                        schedule();
 162                } else {
 163                        __set_current_state(TASK_RUNNING);
 164                        preempt_enable();
 165                        ht->thread_fn(td->cpu);
 166                }
 167        }
 168}

kernel/cpu.c

 659static void cpuhp_thread_fun(unsigned int cpu)
 660{
 661        struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state);
 662        bool bringup = st->bringup;

 727        if (!st->should_run)
 728                complete_ap_thread(st, bringup);
 729}

 802static struct smp_hotplug_thread cpuhp_threads = {
 803        .store                  = &cpuhp_state.thread,
 804        .create                 = &cpuhp_create,
 805        .thread_should_run      = cpuhp_should_run,
 806        .thread_fn              = cpuhp_thread_fun,
 807        .thread_comm            = "cpuhp/%u",
 808        .selfparking            = true,
 809};

 

posted @ 2022-04-03 10:33  张志伟122  阅读(1633)  评论(0编辑  收藏  举报