1. 程式人生 > 其它 >smp啟動-smp_prepare_cpus smp啟動-psci模組初始化

smp啟動-smp_prepare_cpus smp啟動-psci模組初始化

上一篇:time_init() 呼叫 drivers/clocksource/arm_arch_timer.c 中 arch_timer_of_init 註冊CPUHP_AP_ARM_ARCH_TIMER_STARTING的回撥函式

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

 

參考-總流程:https://www.cnblogs.com/pengdonglin137/p/11925299.html

 

start_kernel -> rest_init-> kernel_thread(kernel_init) & kernel_init-> kernel_init_freeable->smp_prepare_cpus

start_kernel -> rest_init-> kernel_thread 函式建立新 task, 新task 執行 kernel_init 函式

kernel_init 呼叫 kernel_init_freeable

1497 - 等待 kthreadd_done , 這個在 rest_init 函式裡面  713        complete(&kthreadd_done);

1492static noinline void __init kernel_init_freeable(void)
1493{
1494        /*
1495         * Wait until kthreadd is all set-up.
1496         
*/ 1497 wait_for_completion(&kthreadd_done); 1507 cad_pid = task_pid(current); 1508 1509 smp_prepare_cpus(setup_max_cpus); 1510 1511 workqueue_init(); 1512 1513 init_mm_internals(); 1514 1515 do_pre_smp_initcalls(); 1517 1518 smp_init();

 

smp_prepare_cpus

setup_max_cpus - 這個在 kernel/smp.c 裡面,

 738/* Setup configured maximum number of CPUs to activate */
 739unsigned int setup_max_cpus = NR_CPUS;
 740EXPORT_SYMBOL(setup_max_cpus);

去掉 numa 相關資訊,smp_prepare_cpus 如下

 743void __init smp_prepare_cpus(unsigned int max_cpus)
 744{
 745        const struct cpu_operations *ops;
 746        int err;
 747        unsigned int cpu;
 748        unsigned int this_cpu;
 749
 750        init_cpu_topology();

 752        this_cpu = smp_processor_id();
 753        store_cpu_topology(this_cpu);
 756
 757        /*
 758         * If UP is mandated by "nosmp" (which implies "maxcpus=0"), don't set
 759         * secondary CPUs present.
 760         */
 761        if (max_cpus == 0)
 762                return;
 763
 764        /*
 765         * Initialise the present map (which describes the set of CPUs
 766         * actually populated at the present time) and release the
 767         * secondaries from the bootloader.
 768         */
 769        for_each_possible_cpu(cpu) {
 770
 771                per_cpu(cpu_number, cpu) = cpu;
 772
 773                if (cpu == smp_processor_id())
 774                        continue;
 775
 776                ops = get_cpu_ops(cpu);
 777                if (!ops)
 778                        continue;
 779
 780                err = ops->cpu_prepare(cpu);
 781                if (err)
 782                        continue;
 783
 784                set_cpu_present(cpu, true);
 786        }
 787}
 788

cpu topology

750 ~ 753 ,先 init_cpu_topology 和 store_cpu_topology

drivers/base/arch_topology.c 中,init_cpu_topology 

489  -  定義陣列  cpu_topology ,就是這個陣列 來記錄 cpu 拓撲關係。 結構定義在  include/linux/arch_topology.h 中

588 - reset_cpu_topology 將數組裡面的值都設定為 無效 值。

594 ~ 598 先後嘗試使用 parse_acpi_topology 和 parse_dt_topology 來填充 上面的陣列資訊。

更多細節,可以參考: https://blog.csdn.net/u013910383/article/details/110082275

 486/*
 487 * cpu topology table
 488 */
 489struct cpu_topology cpu_topology[NR_CPUS];
 490EXPORT_SYMBOL_GPL(cpu_topology);


 585#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
 586void __init init_cpu_topology(void)
 587{
 588        reset_cpu_topology();
 589
 590        /*
 591         * Discard anything that was parsed if we hit an error so we
 592         * don't use partial information.
 593         */
 594        if (parse_acpi_topology())
 595                reset_cpu_topology();
 596        else if (of_have_populated_dt() && parse_dt_topology())
 597                reset_cpu_topology();
 598}
 599#endif

 

753 store_cpu_topology  ,在 arch/arm64/kernel/topology.c 裡面,在arm64 arch 上面,cpu 指示的是 core ,所以 cpuid 賦值到 core_id 裡面。

註釋 解釋了這樣賦值的原因。

  25void store_cpu_topology(unsigned int cpuid)
  26{
  27        struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];


  39        /*
  40         * This would be the place to create cpu topology based on MPIDR.
  41         *
  42         * However, it cannot be trusted to depict the actual topology; some
  43         * pieces of the architecture enforce an artificial cap on Aff0 values
  44         * (e.g. GICv3's ICC_SGI1R_EL1 limits it to 15), leading to an
  45         * artificial cycling of Aff1, Aff2 and Aff3 values. IOW, these end up
  46         * having absolutely no relationship to the actual underlying system
  47         * topology, and cannot be reasonably used as core / package ID.
  48         *
  49         * If the MT bit is set, Aff0 *could* be used to define a thread ID, but
  50         * we still wouldn't be able to obtain a sane core ID. This means we
  51         * need to entirely ignore MPIDR for any topology deduction.
  52         */
  53        cpuid_topo->thread_id  = -1;
  54        cpuid_topo->core_id    = cpuid;
  55        cpuid_topo->package_id = cpu_to_node(cpuid);

 

769 ~ 786 for each cpu 迴圈

771   對 cpu_number 這個 per cpu變數 賦值

773 ~ 774 跳過 boot cpu 【當前執行程式碼的cpu】,因為對於 boot cpu ,不需要 呼叫 cpu ops 的  cpu_prepare ,也不需要 set_preset

對於其他cpu,呼叫  cpu_ops[cpu]->cpu_prepare  &  set_cpu_preset

 

cpu_prepare 對於 psci 機制而言,就是 arch/arm64/kernel/psci.c 裡面的 cpu_psci_cpu_prepare ,

裡面僅僅檢查了 psci_ops.cpu_on ,如果不存在,就輸出 錯誤告警。

psci_ops 這個在 drivers/firmware/psci/psci.c 中定義,在 psci_0_2_set_functions(void) 函式中賦值。

psci_0_2_set_functions 函式呼叫見  smp啟動-psci模組初始化   https://www.cnblogs.com/zhangzhiwei122/p/16090641.html

  28
  29static int __init cpu_psci_cpu_prepare(unsigned int cpu)
  30{
  31        if (!psci_ops.cpu_on) {
  32                pr_err("no cpu_on method, not booting CPU%d\n", cpu);
  33                return -ENODEV;
  34        }
  35
  36        return 0;
  37}