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

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 ;