smp启动-psci模块初始化
setup_arch -> psci_dt_init
arch/arm64/kernel/setup.c
284void __init __no_sanitize_address setup_arch(char **cmdline_p) 285{ 339
340 if (acpi_disabled)
341 unflatten_device_tree();
347 request_standard_resources(); 348 349 early_ioremap_reset(); 350 351 if (acpi_disabled) 352 psci_dt_init(); 353 else 354 psci_acpi_init(); 355 356 init_bootcpu_ops(); 357 smp_init_cpus(); 358 smp_build_mpidr_hash();
352 - 调用psci_dt_init(),在 drivers/firmware/psci/psci.c 里面
558static const struct of_device_id psci_of_match[] __initconst = { 559 { .compatible = "arm,psci", .data = psci_0_1_init}, 560 { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, 561 { .compatible = "arm,psci-1.0", .data = psci_1_0_init}, 562 {}, 563}; 564 565int __init psci_dt_init(void) 566{ 567 struct device_node *np; 568 const struct of_device_id *matched_np; 569 psci_initcall_t init_fn; 570 int ret; 571 572 np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); 573 574 if (!np || !of_device_is_available(np)) 575 return -ENODEV; 576 577 init_fn = (psci_initcall_t)matched_np->data; 578 ret = init_fn(np); 579 580 of_node_put(np); 581 return ret; 582}
572 行,使用 558 行定义的 of_device_id 对象数组 来匹配。找到 匹配的,将其指针放入到 matched_np, 然后在 577 ~ 578 行 调用 matched_np->data 字段定义的函数。
dts 中, psci 的示例(更多,可以参考 Documentation/devicetree/bindings/arm/psci.yaml ) :
psci { compatible = "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0x95c10000>; cpu_off = <0x95c10001>; cpu_on = <0x95c10002>; migrate = <0x95c10003>; };
如果 dtb 中具有 上面的 psci 节点,则 572 行 成功找到匹配的 of_device_id 对象,并且返回一个 device_node 指针 np.
device_node 这个对象,在arch/arm64/kernel/setup.c 的 setup_arch 341 行 调用 unflatten_device_tree 函数 进行创建。unflatten_device_tree 在fdt.c 里面。
psci_0_2_init 为例说明
假设 578 行调用的是 psci_0_2_init 函数
drivers/firmware/psci/psci.c
485static int __init psci_0_2_init(struct device_node *np) 486{ 487 int err; 489 err = get_set_conduit_method(np); 490 if (err) 491 return err; 492 493 /* 494 * Starting with v0.2, the PSCI specification introduced a call 495 * (PSCI_VERSION) that allows probing the firmware version, so 496 * that PSCI function IDs and version specific initialization 497 * can be carried out according to the specific version reported 498 * by firmware 499 */ 500 return psci_probe(); 501}
489 行,调用 同文件中的 get_set_conduit_method ,解析 dts 中,psci 节点的 method 属性,为hvc 或者 smc , 设置 psci 下层使用 hvc 还是 smc 中断机制。
493 ~ 500 注释很清楚了,从 0.2 开始,可以从firmware 获取版本信息,这样就可以使用 从 firmware 获取的版本来作 特定的初始化了。调用 psci_probe 函数。
psci 大于等于 0.2 版本,都可以使用 psci_probe 函数
447 448/* 449 * Probe function for PSCI firmware versions >= 0.2 450 */ 451static int __init psci_probe(void) 452{ 453 u32 ver = psci_get_version(); 454 455 pr_info("PSCIv%d.%d detected in firmware.\n", 456 PSCI_VERSION_MAJOR(ver), 457 PSCI_VERSION_MINOR(ver)); 458 459 if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { 460 pr_err("Conflicting PSCI version detected.\n"); 461 return -EINVAL; 462 } 463 464 psci_0_2_set_functions(); 465 466 psci_init_migrate(); 467 468 if (PSCI_VERSION_MAJOR(ver) >= 1) { 469 psci_init_smccc(); 470 psci_init_cpu_suspend(); 471 psci_init_system_suspend(); 472 psci_init_system_reset2(); 473 } 474 475 return 0; 476}
453 ~ 463 行,从firmware 获取version 并进行检查
464 行 调用 psci_0_2_set_functions 设置 0.2 版本定义的函数
466 行,调用 psci_init_migrate 初始化迁移功能
468 ~ 473 ,只有版本大于等于1.0 时,调用。高版本的 psci firmware 增加了新功能,比如 cpu suspend system suspend 等
421static void __init psci_0_2_set_functions(void) 422{ 423 pr_info("Using standard PSCI v0.2 function IDs\n"); 424 psci_ops.get_version = psci_get_version; 425 426 psci_function_id[PSCI_FN_CPU_SUSPEND] = 427 PSCI_FN_NATIVE(0_2, CPU_SUSPEND); 428 psci_ops.cpu_suspend = psci_cpu_suspend; 429 430 psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; 431 psci_ops.cpu_off = psci_cpu_off; 432 433 psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON); 434 psci_ops.cpu_on = psci_cpu_on; 435 436 psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE); 437 psci_ops.migrate = psci_migrate; 438 439 psci_ops.affinity_info = psci_affinity_info; 440 441 psci_ops.migrate_info_type = psci_migrate_info_type; 442 443 arm_pm_restart = psci_sys_reset; 444 445 pm_power_off = psci_sys_poweroff; 446}
psci_0_2_set_functions 函数,主要两件事情:
1、设置 psci_functions_id[] 数组的值; psci_function_id[ PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON) ;
这是一个 u32 数据类型的数组
69static u32 psci_function_id[PSCI_FN_MAX];
0.1 版本中,这个值来自于 dts 。
0.2 及以后,这个值 定义在 include/uapi/linux/psci.h 中。
PSCI_FN_NATIVE 宏展开后, PSCI_FN_NATIVE(0_2, CPU_ON) 对应 PSCI_0_2_FN64_CPU_ON,
在 include/uapi/linux/psci.h 中,
25/* PSCI v0.2 interface */ 26#define PSCI_0_2_FN_BASE 0x84000000 27#define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) 28#define PSCI_0_2_64BIT 0x40000000 29#define PSCI_0_2_FN64_BASE \ 30 (PSCI_0_2_FN_BASE + PSCI_0_2_64BIT) 31#define PSCI_0_2_FN64(n) (PSCI_0_2_FN64_BASE + (n)) 45#define PSCI_0_2_FN64_CPU_ON PSCI_0_2_FN64(3)
2、设置 psci_ops 结构体的值。比如: psci_opt.cpu_on = psci_cpu_on ;
下一篇: cpu_ops 初始化