int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { int ret = cpufreq_frequency_table_cpuinfo(policy, table); if (!ret) cpufreq_frequency_table_get_attr(table, policy->cpu); return ret; }
static int set_freq_table(struct cpufreq_policy *policy, int end_index) { int ret = 0; int i; int zero_no = 0; for (i = 0; i < end_index; i++) { if (profiles[i].cpu == 0) zero_no++; } end_index -= zero_no; cpu_freq_khz_min = profiles[0].cpu; cpu_freq_khz_max = profiles[0].cpu; for (i = 0; i < end_index; i++) { imx_freq_table[end_index - 1 - i].index = end_index - i; imx_freq_table[end_index - 1 - i].frequency = profiles[i].cpu; if ((profiles[i].cpu) < cpu_freq_khz_min) cpu_freq_khz_min = profiles[i].cpu; if ((profiles[i].cpu) > cpu_freq_khz_max) cpu_freq_khz_max = profiles[i].cpu; } imx_freq_table[i].index = 0; imx_freq_table[i].frequency = CPUFREQ_TABLE_END; policy->cur = clk_get_rate(cpu_clk) / 1000; policy->governor = CPUFREQ_DEFAULT_GOVERNOR; policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min; policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max; /* Manual states, that PLL stabilizes in two CLK32 periods */ policy->cpuinfo.transition_latency = 1000; ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table); if (ret < 0) { printk(KERN_ERR "%s: failed to register i.MXC CPUfreq\n", __func__); return ret; } cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu); return ret; }
static s32 balong_cpufreq_cpu_init(struct cpufreq_policy *policy) { /*cpu_online 这里的作用是 ? */ if (!cpu_online(policy->cpu)) return -ENODEV; pr_info("cpufreq: balong_cpufreq_cpu_init.\n"); cpufreq_table_init(); policy->governor = &cpufreq_balong_ondemand; policy->max = policy->cpuinfo.max_freq = BALONG_CPUFREQUENCY_666; policy->min = policy->cpuinfo.min_freq = BALONG_CPUFREQUENCY_100; policy->cur = BALONG_CPUFREQUENCY_666; g_cur_freq = policy->cur; cpufreq_frequency_table_get_attr(&balong_clockrate_table[0], policy->cpu); return cpufreq_frequency_table_cpuinfo(policy, &balong_clockrate_table[0]); }
static int powernow_cpufreq_cpu_init(struct cpufreq_policy *policy) { unsigned int i; unsigned int valid_states = 0; unsigned int cpu = policy->cpu; struct acpi_cpufreq_data *data; unsigned int result = 0; struct processor_performance *perf; u32 max_hw_pstate; uint64_t msr_content; struct cpuinfo_x86 *c = &cpu_data[policy->cpu]; data = xzalloc(struct acpi_cpufreq_data); if (!data) return -ENOMEM; cpufreq_drv_data[cpu] = data; data->acpi_data = &processor_pminfo[cpu]->perf; perf = data->acpi_data; policy->shared_type = perf->shared_type; if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL || policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { cpumask_set_cpu(cpu, policy->cpus); if (cpumask_weight(policy->cpus) != 1) { printk(XENLOG_WARNING "Unsupported sharing type %d (%u CPUs)\n", policy->shared_type, cpumask_weight(policy->cpus)); result = -ENODEV; goto err_unreg; } } else { cpumask_copy(policy->cpus, cpumask_of(cpu)); } /* capability check */ if (perf->state_count <= 1) { printk("No P-States\n"); result = -ENODEV; goto err_unreg; } rdmsrl(MSR_PSTATE_CUR_LIMIT, msr_content); max_hw_pstate = (msr_content & HW_PSTATE_MAX_MASK) >> HW_PSTATE_MAX_SHIFT; if (perf->control_register.space_id != perf->status_register.space_id) { result = -ENODEV; goto err_unreg; } data->freq_table = xmalloc_array(struct cpufreq_frequency_table, (perf->state_count+1)); if (!data->freq_table) { result = -ENOMEM; goto err_unreg; } /* detect transition latency */ policy->cpuinfo.transition_latency = 0; for (i=0; i<perf->state_count; i++) { if ((perf->states[i].transition_latency * 1000) > policy->cpuinfo.transition_latency) policy->cpuinfo.transition_latency = perf->states[i].transition_latency * 1000; } policy->governor = cpufreq_opt_governor ? : CPUFREQ_DEFAULT_GOVERNOR; /* table init */ for (i = 0; i < perf->state_count && i <= max_hw_pstate; i++) { if (i > 0 && perf->states[i].core_frequency >= data->freq_table[valid_states-1].frequency / 1000) continue; data->freq_table[valid_states].index = perf->states[i].control & HW_PSTATE_MASK; data->freq_table[valid_states].frequency = perf->states[i].core_frequency * 1000; valid_states++; } data->freq_table[valid_states].frequency = CPUFREQ_TABLE_END; perf->state = 0; result = cpufreq_frequency_table_cpuinfo(policy, data->freq_table); if (result) goto err_freqfree; if (c->cpuid_level >= 6) on_selected_cpus(cpumask_of(cpu), feature_detect, policy, 1); /* * the first call to ->target() should result in us actually * writing something to the appropriate registers. */ data->arch_cpu_flags |= ARCH_CPU_FLAG_RESUME; policy->cur = data->freq_table[i].frequency; return result; err_freqfree: xfree(data->freq_table); err_unreg: xfree(data); cpufreq_drv_data[cpu] = NULL; return result; }
int cpufreq_frequency_table_target(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table, unsigned int target_freq, unsigned int relation, unsigned int *index) { struct cpufreq_frequency_table optimal = { .driver_data = ~0, .frequency = 0, }; struct cpufreq_frequency_table suboptimal = { .driver_data = ~0, .frequency = 0, }; unsigned int i; pr_debug("request for target %u kHz (relation: %u) for cpu %u\n", target_freq, relation, policy->cpu); switch (relation) { case CPUFREQ_RELATION_H: suboptimal.frequency = ~0; break; case CPUFREQ_RELATION_L: optimal.frequency = ~0; break; } for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { unsigned int freq = table[i].frequency; if (freq == CPUFREQ_ENTRY_INVALID) continue; if ((freq < policy->min) || (freq > policy->max)) continue; switch (relation) { case CPUFREQ_RELATION_H: if (freq <= target_freq) { if (freq >= optimal.frequency) { optimal.frequency = freq; optimal.driver_data = i; } } else { if (freq <= suboptimal.frequency) { suboptimal.frequency = freq; suboptimal.driver_data = i; } } break; case CPUFREQ_RELATION_L: if (freq >= target_freq) { if (freq <= optimal.frequency) { optimal.frequency = freq; optimal.driver_data = i; } } else { if (freq >= suboptimal.frequency) { suboptimal.frequency = freq; suboptimal.driver_data = i; } } break; } } if (optimal.driver_data > i) { if (suboptimal.driver_data > i) return -EINVAL; *index = suboptimal.driver_data; } else *index = optimal.driver_data; pr_debug("target index is %u, freq is:%u kHz\n", *index, table[*index].frequency); return 0; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target); int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy, unsigned int freq) { struct cpufreq_frequency_table *table; int i; table = cpufreq_frequency_get_table(policy->cpu); if (unlikely(!table)) { pr_debug("%s: Unable to find frequency table\n", __func__); return -ENOENT; } for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { if (table[i].frequency == freq) return i; } return -EINVAL; } EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index); /** * show_available_freqs - show available frequencies for the specified CPU */ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf, bool show_boost) { unsigned int i = 0; ssize_t count = 0; struct cpufreq_frequency_table *table = policy->freq_table; if (!table) return -ENODEV; for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) { if (table[i].frequency == CPUFREQ_ENTRY_INVALID) continue; /* * show_boost = true and driver_data = BOOST freq * display BOOST freqs * * show_boost = false and driver_data = BOOST freq * show_boost = true and driver_data != BOOST freq * continue - do not display anything * * show_boost = false and driver_data != BOOST freq * display NON BOOST freqs */ if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ)) continue; count += sprintf(&buf[count], "%d ", table[i].frequency); } count += sprintf(&buf[count], "\n"); return count; } #define cpufreq_attr_available_freq(_name) \ struct freq_attr cpufreq_freq_attr_##_name##_freqs = \ __ATTR_RO(_name##_frequencies) /** * show_scaling_available_frequencies - show available normal frequencies for * the specified CPU */ static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy, char *buf) { return show_available_freqs(policy, buf, false); } cpufreq_attr_available_freq(scaling_available); EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs); /** * show_available_boost_freqs - show available boost frequencies for * the specified CPU */ static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy, char *buf) { return show_available_freqs(policy, buf, true); } cpufreq_attr_available_freq(scaling_boost); EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs); struct freq_attr *cpufreq_generic_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, #ifdef CONFIG_CPU_FREQ_BOOST_SW &cpufreq_freq_attr_scaling_boost_freqs, #endif NULL, }; EXPORT_SYMBOL_GPL(cpufreq_generic_attr); int cpufreq_table_validate_and_show(struct cpufreq_policy *policy, struct cpufreq_frequency_table *table) { int ret = cpufreq_frequency_table_cpuinfo(policy, table); if (!ret) policy->freq_table = table; return ret; }