structcpufreq_policy { /* CPUs sharing clock, require sw coordination */ cpumask_var_t cpus; /* Online CPUs only */ cpumask_var_t related_cpus; /* Online + Offline CPUs */ cpumask_var_t real_cpus; /* Related and present */ ... unsignedint policy; /* see above */ unsignedint last_policy; /* policy before unplug */ structcpufreq_governor *governor;/* see below */ void *governor_data; char last_governor[CPUFREQ_NAME_LEN]; /* last governor used */
offline有两种情况:逻辑offline和物理offline(for NUMA arch)。related_cpus里的offline就有这两个,而real_cpus必须是物理存在的所有CPU。
看下文档描述:
SMP systems normally have same clock source for a group of cpus. For these the .init() would be called only once for the first online cpu. Here the .init() routine must initialize policy->cpus with mask of all possible cpus (Online + Offline) that share the clock. Then the core would copy this mask onto policy->related_cpus and will reset policy->cpus to carry only online cpus.
staticint msm_cpufreq_init(struct cpufreq_policy *policy) { ... /* * 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);
所有的cpu core共用同一个clock,所以共用一个调频策略。
staticintcpufreq_online(unsignedint cpu) { ... if (new_policy) { /* related_cpus should at least include policy->cpus. */ cpumask_copy(policy->related_cpus, policy->cpus); }
bringing CPU online时会copy。 CPU offline时会clear这个cpus。
staticintcpufreq_offline(unsignedint cpu) { structcpufreq_policy *policy; int ret;
pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
policy = cpufreq_cpu_get_raw(cpu); if (!policy) { pr_debug("%s: No cpu_data found\n", __func__); return0; }
down_write(&policy->rwsem); if (has_target()) cpufreq_stop_governor(policy);
cpufreq: create cpu/cpufreq/policyX directories The cpufreq sysfs interface had been a bit inconsistent as one of the CPUs for a policy had a real directory within its sysfs 'cpuX' directory and all other CPUs had links to it. That also made the code a bit complex as we need to take care of moving the sysfs directory if the CPU containing the real directory is getting physically hot-unplugged. Solve this by creating 'policyX' directories (per-policy) in /sys/devices/system/cpu/cpufreq/ directory, where X is the CPU for which the policy was first created.
/* * If (cpufreq_driver->target) exists, the ->governor decides what frequency * within the limits is used. If (cpufreq_driver->setpolicy> exists, these * two generic policies are available: */ #define CPUFREQ_POLICY_POWERSAVE (1) #define CPUFREQ_POLICY_PERFORMANCE (2)
staticintcpufreq_init_policy(struct cpufreq_policy *policy) { ... /* Use the default policy if there is no last_policy. */ if (cpufreq_driver->setpolicy) { if (policy->last_policy) new_policy.policy = policy->last_policy; else cpufreq_parse_governor(gov->name, &new_policy.policy, NULL); }