CPPC的全称是Collaborative Processor Performance Control
CPC的全称是Per cpu table called,是bios提供的一组acpi表,用于设置cpu的频率。这组acpi表如下:
/* * An example CPC table looks like the following. * * Name(_CPC, Package() * { * 17, * NumEntries * 1, * // Revision * ResourceTemplate(){Register(PCC, 32, 0, 0x120, 2)}, * // Highest Performance * ResourceTemplate(){Register(PCC, 32, 0, 0x124, 2)}, * // Nominal Performance * ResourceTemplate(){Register(PCC, 32, 0, 0x128, 2)}, * // Lowest Nonlinear Performance * ResourceTemplate(){Register(PCC, 32, 0, 0x12C, 2)}, * // Lowest Performance * ResourceTemplate(){Register(PCC, 32, 0, 0x130, 2)}, * // Guaranteed Performance Register * ResourceTemplate(){Register(PCC, 32, 0, 0x110, 2)}, * // Desired Performance Register * ResourceTemplate(){Register(SystemMemory, 0, 0, 0, 0)}, * .. * .. * .. * * } * Each Register() encodes how to access that specific register. * e.g. a sample PCC entry has the following encoding: * * Register ( * PCC, * AddressSpaceKeyword * 8, * //RegisterBitWidth * 8, * //RegisterBitOffset * 0x30, * //RegisterAddress * 9 * //AccessSize (subspace ID) * 0 * ) * } */
那cppc表具体要怎么工作呢?具体在driver/cpufreq/cppc_cpufreq.c中。
这里的cppc_cpufreq_init是入口函数,这个函数向cpufreq的framework注册了一个可以调频的cpu driver
static int __init cppc_cpufreq_init(void) { ret = cpufreq_register_driver(&cppc_cpufreq_driver); if (ret) goto out; } static struct cpufreq_driver cppc_cpufreq_driver = { .flags = CPUFREQ_CONST_LOOPS, .verify = cppc_verify_policy, .target = cppc_cpufreq_set_target, .get = cppc_cpufreq_get_rate, .init = cppc_cpufreq_cpu_init, .stop_cpu = cppc_cpufreq_stop_cpu, .name = "cppc_cpufreq", }; //cppc_cpufreq_driver 最终的函数就是target,最终cpu调频就是通过target 这个回调函数来实现 static int cppc_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) { struct cppc_cpudata *cpu; struct cpufreq_freqs freqs; u32 desired_perf; int ret = 0; cpu = all_cpu_data[policy->cpu]; //得到要设置的频率 desired_perf = cppc_cpufreq_khz_to_perf(cpu, target_freq); /* Return if it is exactly the same perf */ if (desired_perf == cpu->perf_ctrls.desired_perf) return ret; cpu->perf_ctrls.desired_perf = desired_perf; freqs.old = policy->cur; freqs.new = target_freq; cpufreq_freq_transition_begin(policy, &freqs); //通过acpi 提供的的接口来设置cpu 频率 ret = cppc_set_perf(cpu->cpu, &cpu->perf_ctrls); cpufreq_freq_transition_end(policy, &freqs, ret != 0); if (ret) pr_debug("Failed to set target on CPU:%d. ret:%d\n", cpu->cpu, ret); return ret; }
这里的cppc_set_perf实现在driver/acpi/cppc_acpi.c中实现,通过这个接口可以通过固件来设置cpu频率。