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 初始化

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

posted @ 2022-04-02 09:54  张志伟122  阅读(300)  评论(0编辑  收藏  举报