cpu idle arm linux,代码阅读 - Linux\kernel\linux-5.0\drivers\cpuidle\cpuidle-arm.c

/*

* ARM/ARM64 generic CPU idle driver.

*

* Copyright (C) 2014 ARM Ltd.

* Author: Lorenzo Pieralisi *

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation.

*/

#define pr_fmt(fmt) "CPUidle arm: " fmt

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "dt_idle_states.h"

/*

* arm_enter_idle_state - Programs CPU to enter the specified state

*

* dev: cpuidle device

* drv: cpuidle driver

* idx: state index

*

* Called from the CPUidle framework to program the device to the

* specified target state selected by the governor.

*/

static int arm_enter_idle_state(struct cpuidle_device *dev,

struct cpuidle_driver *drv, int idx)

{

/*

* Pass idle state index to arm_cpuidle_suspend which in turn

* will call the CPU ops suspend protocol with idle index as a

* parameter.

*/

return CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, idx);

}

static struct cpuidle_driver arm_idle_driver __initdata = {

.name = "arm_idle",

.owner = THIS_MODULE,

/*

* State at index 0 is standby wfi and considered standard

* on all ARM platforms. If in some platforms simple wfi

* can't be used as "state 0", DT bindings must be implemented

* to work around this issue and allow installing a special

* handler for idle state index 0.

*/

.states[0] = {

.enter = arm_enter_idle_state,

.exit_latency = 1,

.target_residency = 1,

.power_usage= UINT_MAX,

.name = "WFI",

.desc = "ARM WFI",

}

};

static const struct of_device_id arm_idle_state_match[] __initconst = {

{ .compatible = "arm,idle-state",

.data = arm_enter_idle_state },

{ },

};

/*

* arm_idle_init_cpu

*

* Registers the arm specific cpuidle driver with the cpuidle

* framework. It relies on core code to parse the idle states

* and initialize them using driver data structures accordingly.

*/

static int __init arm_idle_init_cpu(int cpu)

{

int ret;

struct cpuidle_driver *drv;

drv = kmemdup(&arm_idle_driver, sizeof(*drv), GFP_KERNEL);

if (!drv)

return -ENOMEM;

drv->cpumask = (struct cpumask *)cpumask_of(cpu);

/*

* Initialize idle states data, starting at index 1. This

* driver is DT only, if no DT idle states are detected (ret

* == 0) let the driver initialization fail accordingly since

* there is no reason to initialize the idle driver if only

* wfi is supported.

*/

ret = dt_init_idle_driver(drv, arm_idle_state_match, 1);

if (ret <= 0) {

ret = ret ? : -ENODEV;

goto out_kfree_drv;

}

/*

* Call arch CPU operations in order to initialize

* idle states suspend back-end specific data

*/

ret = arm_cpuidle_init(cpu);

/*

* Allow the initialization to continue for other CPUs, if the reported

* failure is a HW misconfiguration/breakage (-ENXIO).

*/

if (ret) {

pr_err("CPU %d failed to init idle CPU ops\n", cpu);

ret = ret == -ENXIO ? 0 : ret;

goto out_kfree_drv;

}

ret = cpuidle_register(drv, NULL);

if (ret)

goto out_kfree_drv;

return 0;

out_kfree_drv:

kfree(drv);

return ret;

}

/*

* arm_idle_init - Initializes arm cpuidle driver

*

* Initializes arm cpuidle driver for all CPUs, if any CPU fails

* to register cpuidle driver then rollback to cancel all CPUs

* registeration.

*/

static int __init arm_idle_init(void)

{

int cpu, ret;

struct cpuidle_driver *drv;

struct cpuidle_device *dev;

for_each_possible_cpu(cpu) {

ret = arm_idle_init_cpu(cpu);

if (ret)

goto out_fail;

}

return 0;

out_fail:

while (--cpu >= 0) {

dev = per_cpu(cpuidle_devices, cpu);

drv = cpuidle_get_cpu_driver(dev);

cpuidle_unregister(drv);

kfree(drv);

}

return ret;

}

device_initcall(arm_idle_init);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值