Cpufreq framework 分析-2

cpufreq 是如何来设置cpu频率的,通过哪里来做实际的频率设置

看下面的代码.

这个init 回调函数在cpufreq_register_driver(&msm_cpufreq_driver); 向core 层注册driver的时候执行.

static struct cpufreq_driver msm_cpufreq_driver = {
    /* lps calculations are handled here. */
    .flags      = CPUFREQ_STICKY | CPUFREQ_CONST_LOOPS,
    .init       = **msm_cpufreq_init**,
    .verify     = msm_cpufreq_verify,
    .target     = msm_cpufreq_target,
    .get        = msm_cpufreq_get_freq,
    .name       = "msm",
    .attr       = msm_freq_attr,
};

static int msm_cpufreq_init(struct cpufreq_policy *policy)
{
    int cur_freq;
    int index;
    int ret = 0;
    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. */
    for_each_possible_cpu(cpu)
        if (cpu_clk[cpu] == cpu_clk[policy->cpu])
            cpumask_set_cpu(cpu, policy->cpus);

    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;

    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.
     */
    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;
}

这个msm_cpufreq_target 是在每次CPU频率变化是通过core层或者sys 控制当前频率变化时调用.

static int msm_cpufreq_target(struct cpufreq_policy *policy,
                unsigned int target_freq,
                unsigned int relation)
{
    int ret = 0;
    int index;
    struct cpufreq_frequency_table *table;

    mutex_lock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);

    if (target_freq == policy->cur)
        goto done;

    if (per_cpu(cpufreq_suspend, policy->cpu).device_suspended) {
        pr_debug("cpufreq: cpu%d scheduling frequency change "
                "in suspend.\n", policy->cpu);
        ret = -EFAULT;
        goto done;
    }
// 获取table 
    table = cpufreq_frequency_get_table(policy->cpu);
    if (cpufreq_frequency_table_target(policy, table, target_freq, relation,
            &index)) {
        pr_err("cpufreq: invalid target_freq: %d\n", target_freq);
        ret = -EINVAL;
        goto done;
    }

    pr_debug("CPU[%d] target %d relation %d (%d-%d) selected %d\n",
        policy->cpu, target_freq, relation,
        policy->min, policy->max, table[index].frequency);
// 最终来设置检查后么有没问题的频率到cpu硬件.
    ret = set_cpu_freq(policy, table[index].frequency, table[index].driver_data);
done:
    mutex_unlock(&per_cpu(cpufreq_suspend, policy->cpu).suspend_mutex);
    return ret;
}

你可能感兴趣的:(Cpufreq framework 分析-2)