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}