arm-psci分析

  1. 5个ops
  • cpu_ops
  • cpu_psci_ops,它的接口,最终调用到psci_ops
  • psci_ops
  • suspend_ops
  • psci_suspend_ops

在内核中针对的cpu的操作,比如arm_cpuidle_init、arm_cpuidle_suspend、boot_secondary、

secondary_start_kernel、op_cpu_disable、op_cpu_kill、cpu_die、smp_cpu_setup、

smp_prepare_cpus的都会回落到对cpu_ops的调用。

cpu_ops将针对底层cpu的操作抽象为一系列回调函数,以统一的形式向上层提供API。

cpu_psci_ops作为cpu_ops的一个特殊实现,将cpu_ops关联到PSCI的psci_ops。psci_ops的函数在PSCI Firmware中实现,提供一系列基于Function ID的调用。

这种分层思想将内核通用cpu_operations和硬件相关部分分隔开。

cpu_ops和suspend_ops将内核通用API和底层arch-specific代码区隔开;

cpu_ops和suspend_ops分别调用cpu_psci_ops和psci_suspend_ops,这些回调函数最终都会回落到PSCI Firmware提供的接口。machine_restart/machine_power_off直接调用PSCI提供的接口。

arch/arm64/kernel/psci.c

cpu_psci_ops

const struct cpu_operations  cpu_psci_ops = {

               .name                   = "psci",

               .cpu_init              = cpu_psci_cpu_init,  //空函数

               .cpu_prepare      = cpu_psci_cpu_prepare,  //空函数

               .cpu_boot           = cpu_psci_cpu_boot,

#ifdef CONFIG_HOTPLUG_CPU

               .cpu_can_disable = cpu_psci_cpu_can_disable,

               .cpu_disable       = cpu_psci_cpu_disable,

               .cpu_die               = cpu_psci_cpu_die,

               .cpu_kill               = cpu_psci_cpu_kill,

#endif

};

cpu_psci_cpu_boot

cpu_psci_cpu_boot(unsigned int cpu)

->psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry));

psci_ops又是在哪里定义的呢?

drivers/firmware/psci/psci.c

drivers/firmware/psci/psci.c

psci_ops

struct psci_operations   psci_ops = {

               .conduit = PSCI_CONDUIT_NONE,

               .smccc_version = SMCCC_VERSION_1_0,

};

static const struct of_device_id psci_of_match[] __initconst = {

               { .compatible = "arm,psci",           .data = psci_0_1_init},

               { .compatible = "arm,psci-0.2",    .data = psci_0_2_init},  //dts文件中,定义了这个结点

               { .compatible = "arm,psci-1.0",    .data = psci_1_0_init},

               {},

};

psci_dt_init

int __init psci_dt_init(void)

{

               struct device_node *np;

               const struct of_device_id *matched_np;

               psci_initcall_t init_fn;

               int ret;

               np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);

               if (!np || !of_device_is_available(np))

                              return -ENODEV;

               init_fn = (psci_initcall_t)matched_np->data;

               ret = init_fn(np);  //指向psci_0_2_init

               of_node_put(np);

               return ret;

}

​​​​​​​psci_0_2_init

static int __init psci_0_2_init(struct device_node *np)

{

               int err;

               err = get_set_conduit_method(np);

               if (err)

                              return err;

               /*

                * Starting with v0.2, the PSCI specification introduced a call

                * (PSCI_VERSION) that allows probing the firmware version, so

                * that PSCI function IDs and version specific initialization

                * can be carried out according to the specific version reported

                * by firmware

                */

               return psci_probe();

}

static int  get_set_conduit_method(struct device_node *np)

{

               const char *method;

               pr_info("probing for conduit method from DT.\n");

               if (of_property_read_string(np, "method", &method)) {

                              pr_warn("missing \"method\" property\n");

                              return -ENXIO;

               }

               if (!strcmp("hvc", method)) {

                              set_conduit(PSCI_CONDUIT_HVC);

               } else if (!strcmp("smc", method)) {

                              set_conduit(PSCI_CONDUIT_SMC);

               } else {

                              pr_warn("invalid \"method\" property: %s\n", method);

                              return -EINVAL;

               }

               return 0;

}

static void set_conduit(enum psci_conduit conduit)

{

               switch (conduit) {

               case PSCI_CONDUIT_HVC:

                              invoke_psci_fn = __invoke_psci_fn_hvc;

                              break;

               case PSCI_CONDUIT_SMC:

                              invoke_psci_fn = __invoke_psci_fn_smc;

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值