Android使用的调频governor都是interactive,我们就以interactive为例,
看下整个调频的代码实现。
我们沿着driver初始化往下分析代码流程,高通平台对应的驱动文件qcom-cpufreq.c。
初始化首先调用:msm_cpufreq_register
看下整个调频的代码实现。
我们沿着driver初始化往下分析代码流程,高通平台对应的驱动文件qcom-cpufreq.c。
初始化首先调用:msm_cpufreq_register
//依次初始化每个cpu suspend_mutex和device_suspended,注册驱动,最后注册notify调用
static int __init msm_cpufreq_register(void)
{
int cpu, rc;
for_each_possible_cpu(cpu) {
mutex_init(&(per_cpu(cpufreq_suspend, cpu).suspend_mutex));
per_cpu(cpufreq_suspend, cpu).device_suspended = 0;
}
rc = platform_driver_probe(&msm_cpufreq_plat_driver,
msm_cpufreq_probe);
if (rc < 0) {
/* Unblock hotplug if msm-cpufreq probe fails */
unregister_hotcpu_notifier(&msm_cpufreq_cpu_notifier);
for_each_possible_cpu(cpu)
mutex_destroy(&(per_cpu(cpufreq_suspend, cpu).
suspend_mutex));
return rc;
}
register_pm_notifier(&msm_cpufreq_pm_notifier);
return cpufreq_register_driver(&msm_cpufreq_driver);
}
//解析 qcom,msm-cpufreq 节点,获取cpu clock和频率信息
static int __init msm_cpufreq_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
char clk_name[] = "cpu??_clk";
char tbl_name[] = "qcom,cpufreq-table-??";
struct clk *c;
int cpu;
struct cpufreq_frequency_table *ftbl;
l2_clk = devm_clk_get(dev, "l2_clk");
if (IS_ERR(l2_clk))
l2_clk = NULL;
for_each_possible_cpu(cpu) {
snprintf(clk_name, sizeof(clk_name), "cpu%d_clk", cpu);
c = devm_clk_get(dev, clk_name);
if (IS_ERR(c))
return PTR_ERR(c);
cpu_clk[cpu] = c;
}
hotplug_ready = true;
/* Use per-policy governor tunable for some targets */
//该属性表示每个policy使用各自的governor
if (of_property_read_bool(dev->of_node, "qcom,governor-per-policy"))
msm_cpufreq_driver.flags |= CPUFREQ_HAVE_GOVERNOR_PER_POLICY;
/* Parse commong cpufreq table for all CPUs */
ftbl = cpufreq_parse_dt(dev, "qcom,cpufreq-table", 0);
if (!IS_ERR(ftbl)) {
for_each_possible_cpu(cpu)
per_cpu(freq_table, cpu) = ftbl;
return 0;
}
/*
* No common table. Parse individual tables for each unique
* CPU clock.
*/
//以8核四个大核,四个小核为例,四个大核公用一个频率表,四个小核公用一个频率表
for_each_possible_cpu(cpu) {
snprintf(tbl_name, sizeof(tbl_name),
"qcom,cpufreq-table-%d", cpu);
ftbl = cpufreq_parse_dt(dev, tbl_name, cpu);
/* CPU0 must contain freq table */
if (cpu == 0 && IS_ERR(ftbl)) {
dev_err(dev, "Failed to parse CPU0's freq table\n");
return PTR_ERR(ftbl);
}
if (cpu == 0) {
per_cpu(freq_table, cpu) = ftbl;
continue;
}
if (cpu_clk[cpu] != cpu_clk[cpu - 1] && IS_ERR(ftbl)) {
dev_err(dev, "Failed to parse CPU%d's freq table\n",
cpu);
return PTR_ERR(ftbl);
}
/* Use previous CPU's table if it shares same clock */
if (cpu_clk[cpu] == cpu_clk[cpu - 1]) {
if (!IS_ERR(ftbl)) {
dev_warn(dev, "Conflicting tables for CPU%d\n",
cpu);
devm_kfree(dev, ftbl);
}
ftbl = per_cpu(freq_table, cpu - 1);
}
per_cpu(freq_table, cpu) = ftbl;
}
return 0;
}
//接下来看下cpufreq_register_driver,这个函数主要用来向cpufreq core部分
//注册驱动并初始化每个cpu 调频策略
int cpufreq_register_driver(struct cpufreq_driver *driver_data)
{
unsigned long flags;
int ret;
if (cpufreq_disabled())
return -ENODEV;
/*
setpolicy跟target驱动必须实现这两个函数中的其中一个,
如果不支持通过governor选择合适的运行频率,则实现setpolicy回调函数,
这样系统只能支持CPUFREQ_POLICY_POWERSAVE和CPUFREQ_POLICY_PERFORMANCE这两种工作策略。
反之,实现target回调函数,通过target回调设定governor所需要的频率
*/
if (!driver_data || !driver_data->verify || !driver_data->init ||
!(driver_data->setpolicy || driver_data->target_index ||
driver_data->target))
return -EINVAL;
pr_debug("trying to register driver %s\n", driver_data->name);
if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS;
write_lock_irqsave(&cpufreq_driver_lock, flags);
if (cpufreq_driver) {
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
return -EEXIST;
}
//驱动赋值,供cpufreq core使用
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
//注册cpu hotplug 处理函数
register_hotcpu_notifier(&cpufreq_cpu_notifier);
get_online_cpus();
//调用驱动实现的add_dev,初始化每个cpu 调频策略
ret = subsys_interface_register(&cpufreq_interface);
put_online_cpus();
if (ret)
goto err_null_driver;
if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
int i;
ret = -ENODEV;
/* check for at least one working CPU */
for (i = 0; i < nr_cpu_ids; i++)
if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {
ret = 0;
break;
}
/* if all ->init() calls failed, unregister */
if (ret) {
pr_debug("no CPU initialized for driver %s\n",
driver_data->name);
goto err_if_unreg;
}
}
pr_info("driver %s up and running\n", driver_data->name);
return 0;
err_if_unreg:
subsys_interface_unregister(&cpufreq_interface);
err_null_driver:
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
write_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
return ret;
}
//调用cpufreq_add_dev,依次初始化每个cpu core
int subsys_interface_register(struct subsys_interface *sif)
{
struct bus_type *subsys;
struct subsys_dev_iter iter;
struct device *dev;
if (!sif || !sif->subsys)
return -ENODEV;
subsys = bus_get(sif->subsys);
if (!subsys)
return -EINVAL;
mutex_lock(&subsys->p->mutex);
list_add_tail(&sif->node, &subsys->p->interfaces);
if (sif->add_dev) {
subsys_dev_iter_init(&iter, subsys, NULL, NULL);
while ((dev = subsys_dev_iter_next(&iter)))
sif->add_dev(dev, sif);
subsys_dev_iter_exit(&iter);
}
mutex_unlock(&subsys->p->mutex);
return 0;
}
//每个cpu核心的初始化工作,为cpu建立policy,执行policy对应的governor函数,启动governor,
//建立sysfs文件系统
static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
bool frozen)
{
unsigned int j, cpu = dev->id;
int ret = -ENOMEM;
struct cpufreq_policy *policy;
unsigned long flags;
#ifdef CONFIG_HOTPLUG_CPU
struct cpufreq_policy *tpolicy;
struct cpufreq_governor *gov;
#endif
if (cpu_is_offline(cpu))
return 0;
pr_debug("adding CPU %u\n", cpu);
#ifdef CONFIG_SMP
/* check whether a different CPU already registered this
* CPU because it is in the same boat. */
//cpufreq_cpu_get获取cpu对应的policy,如果多个cpu公用一个policy,那么之前共用policy //cpu初始化时已经为该cpu建立好了policy
policy = cpufreq_cpu_get(cpu);
if (unlikely(policy)) {
cpufreq_cpu_put(policy);
return 0;
}
#endif
if (!down_read_trylock(&cpufreq_rwsem))
return 0;
#ifdef CONFIG_HOTPLUG_CPU
/* Check if this cpu was hot-unplugged earlier and has siblings */
//如果当前cpu之前被拔出,并且此cpu跟其他未移除cpu共用policy,则无需创建policy,只需要
//将此cpu加入policy管理,并启动对应的governor即可
read_lock_irqsave(&cpufreq_driver_lock, flags);
list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {//当前cpu属于此policy管理的cpu
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev);//给cpu创建policy,执行governor start/limit函数
up_read(&cpufreq_rwsem);
return ret;
}
}
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
#endif
if (frozen)//cpu 之前处于冻结状态,无需申请policy结构
/* Restore the saved policy when doing light-weight init */
policy = cpufreq_policy_restore(cpu);
else//非冻结时,分配一个新的policy结构体,并初始化
policy = cpufreq_policy_alloc();
if (!policy)
goto nomem_out;
/*
* In the resume path, since we restore a saved policy, the assignment
* to policy->cpu is like an update of the existing policy, rather than
* the creation of a brand new one. So we need to perform this update
* by invoking update_policy_cpu().
*/
//对于之前处于frozen cpu,需要更新其policy
if (frozen && cpu != policy->cpu)
update_policy_cpu(policy, cpu);
else
policy->cpu = cpu;
//设定governor默认为performance
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
cpumask_copy(policy->cpus, cpumask_of(cpu));
init_completion(&policy->kobj_unregister);
INIT_WORK(&policy->update, handle_update);
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
//调用驱动的init函数msm_cpufreq_init
ret = cpufreq_driver->init(policy);
if (ret) {
pr_debug("initialization failed\n");
goto err_set_policy_cpu;
}
//获取cpu当前频率
if (cpufreq_driver->get) {
policy->cur = cpufreq_driver->get(policy->cpu);
if (!policy->cur) {
pr_err("%s: ->get() failed\n", __func__);
goto err_get_freq;
}
}
/* related cpus should atleast have policy->cpus */
//设定policy管理的cpu
cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
/*
* affected cpus must always be the one, which are online. We aren't
* managing offline cpus here.
*/
//policy 管理的online cpu
cpumask_and(policy->cpus, policy->cpus, cpu_online_mask);
policy->user_policy.min = policy->min;
policy->user_policy.max = policy->max;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_START, policy);
//如果是hot-plug加入的cpu,找出它上次使用的governor
#ifdef CONFIG_HOTPLUG_CPU
gov = __find_governor(per_cpu(cpufreq_policy_save, cpu).gov);
if (gov) {
policy->governor = gov;
pr_debug("Restoring governor %s for cpu %d\n",
policy->governor->name, cpu);
}
if (per_cpu(cpufreq_policy_save, cpu).min) {
policy->min = per_cpu(cpufreq_policy_save, cpu).min;
policy->user_policy.min = policy->min;
}
if (per_cpu(cpufreq_policy_save, cpu).max) {
policy->max = per_cpu(cpufreq_policy_save, cpu).max;
policy->user_policy.max = policy->max;
}
pr_debug("Restoring CPU%d user policy min %d and max %d\n", cpu,
policy->min, policy->max);
#endif
//建立cpufreq文件节点,然后在它的下面再建立一系列节点,
//用户可以通过这些文件节点控制该policy的一些参数
if (!frozen) {
ret = cpufreq_add_dev_interface(policy, dev);
if (ret)
goto err_out_unregister;
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_CREATE_POLICY, policy);
}
write_lock_irqsave(&cpufreq_driver_lock, flags);
list_add(&policy->policy_list, &cpufreq_policy_list);
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
//policy 初始化,主要是启动对应的governor
cpufreq_init_policy(policy);
write_lock_irqsave(&cpufreq_driver_lock, flags);
//设定policy下所有cpu 的policy,避免重复创建policy
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobject_uevent(&policy->kobj, KOBJ_ADD);
up_read(&cpufreq_rwsem);
pr_debug("initialization complete\n");
return 0;
err_out_unregister:
write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
err_get_freq:
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
err_set_policy_cpu:
if (frozen)
cpufreq_policy_put_kobj(policy);
cpufreq_policy_free(policy);
nomem_out:
up_read(&cpufreq_rwsem);
return ret;
}
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
unsigned int cpu, struct device *dev)
{
int ret = 0;
unsigned long flags;
if (has_target()) {
ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
if (ret) {
pr_err("%s: Failed to stop governor for CPU%u, policy CPU%u\n",
__func__, cpu, policy->cpu);
return ret;
}
}
down_write(&policy->rwsem);
write_lock_irqsave(&cpufreq_driver_lock, flags);
//将cpu加入policy管理
cpumask_set_cpu(cpu, policy->cpus);
per_cpu(cpufreq_cpu_data, cpu) = policy;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
up_write(&policy->rwsem);
//启动governor,并设定cpu工作频率
if (has_target()) {
if ((ret = __cpufreq_governor(policy, CPUFREQ_GOV_START)) ||
(ret = __cpufreq_governor(policy, CPUFREQ_GOV_LIMITS))) {
pr_err("%s: Failed to start governor for CPU%u, policy CPU%u\n",
__func__, cpu, policy->cpu);
return ret;
}
}
//创建cpu对应的sysfs节点
return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
}
//每颗cpu都要调用init,因为使用的是cpu上的本地数据,不需要锁保护
/*
设定该cpu的最大和最小工作频率
设定该policy的最大和最小工作频率
设定该policy可供调节的频率档位
设定cpu调节频率时的延迟时间特性
该policy可以管理的cpu个数(policy->cpus)
*/
static int msm_cpufreq_init(struct cpufreq_policy *policy)
{
int cur_freq;
int index;
int ret = 0;
//每个cpu频率数组
struct cpufreq_frequency_table *table =
per_cpu(freq_table, policy->cpu);
int cpu;
/*
* In some SoC, some cores are clocked by same source, and their
* frequencies can not be changed independently. Find all other
* CPUs that share same clock, and mark them as controlled by
* same policy.
*/
//共享同一个时钟源的cpu,有同一个policy管理
for_each_possible_cpu(cpu)
if (cpu_clk[cpu] == cpu_clk[policy->cpu])
cpumask_set_cpu(cpu, policy->cpus);
//遍历频率表找到最大最小频率,更新policy最大、最小频率
if (cpufreq_frequency_table_cpuinfo(policy, table))
pr_err("cpufreq: failed to get policy min/max\n");
//获取当前频率
cur_freq = clk_get_rate(cpu_clk[policy->cpu])/1000;
/*
CPUFREQ_RELATION_L:取freq table中大于或等于new_freq的频率中最小的一个频率,返回index,再由index得到new freq
CPUFREQ_RELATION_H表示取即是取freq table中小于或等于new_freq的频率中最大的一个频率
*/
if (cpufreq_frequency_table_target(policy, table, cur_freq,
CPUFREQ_RELATION_H, &index) &&
cpufreq_frequency_table_target(policy, table, cur_freq,
CPUFREQ_RELATION_L, &index)) {
pr_info("cpufreq: cpu%d at invalid freq: %d\n",
policy->cpu, cur_freq);
return -EINVAL;
}
/*
* Call set_cpu_freq unconditionally so that when cpu is set to
* online, frequency limit will always be updated.
*/
//设定cpu频率
ret = set_cpu_freq(policy, table[index].frequency,
table[index].driver_data);
if (ret)
return ret;
pr_debug("cpufreq: cpu%d init at %d switching to %d\n",
policy->cpu, cur_freq, table[index].frequency);
policy->cur = table[index].frequency;
cpufreq_frequency_table_get_attr(table, policy->cpu);
return 0;
}
以上的整个过程从驱动初始化,一步步到governor初始化,接下来开始详细分析interactive对应的代码流程。