^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/drivers/cpufreq/freq_table.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2002 - 2003 Dominik Brodowski
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <trace/hooks/cpufreq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /*********************************************************************
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * FREQUENCY TABLE HELPERS *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) *********************************************************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) bool policy_has_boost_freq(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct cpufreq_frequency_table *pos, *table = policy->freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) cpufreq_for_each_valid_entry(pos, table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (pos->flags & CPUFREQ_BOOST_FREQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) EXPORT_SYMBOL_GPL(policy_has_boost_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct cpufreq_frequency_table *table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct cpufreq_frequency_table *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned int min_freq = ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) unsigned int max_freq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) unsigned int freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) cpufreq_for_each_valid_entry(pos, table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) freq = pos->frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (!cpufreq_boost_enabled()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) && (pos->flags & CPUFREQ_BOOST_FREQ))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (freq < min_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) min_freq = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (freq > max_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) max_freq = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) trace_android_vh_freq_table_limits(policy, min_freq, max_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) policy->min = policy->cpuinfo.min_freq = min_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) policy->max = max_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * If the driver has set its own cpuinfo.max_freq above max_freq, leave
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * it as is.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) if (policy->cpuinfo.max_freq < max_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) policy->max = policy->cpuinfo.max_freq = max_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (policy->min == ~0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) int cpufreq_frequency_table_verify(struct cpufreq_policy_data *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct cpufreq_frequency_table *table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct cpufreq_frequency_table *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) unsigned int freq, next_larger = ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) bool found = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) policy->min, policy->max, policy->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) cpufreq_verify_within_cpu_limits(policy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) cpufreq_for_each_valid_entry(pos, table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) freq = pos->frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if ((freq >= policy->min) && (freq <= policy->max)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) found = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if ((next_larger > freq) && (freq > policy->max))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) next_larger = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (!found) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) policy->max = next_larger;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) cpufreq_verify_within_cpu_limits(policy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) policy->min, policy->max, policy->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Generic routine to verify policy & frequency table, requires driver to set
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * policy->freq_table prior to it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) int cpufreq_generic_frequency_table_verify(struct cpufreq_policy_data *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if (!policy->freq_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return cpufreq_frequency_table_verify(policy, policy->freq_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned int target_freq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) unsigned int relation)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct cpufreq_frequency_table optimal = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .driver_data = ~0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .frequency = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct cpufreq_frequency_table suboptimal = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .driver_data = ~0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .frequency = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct cpufreq_frequency_table *pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) struct cpufreq_frequency_table *table = policy->freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned int freq, diff, i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) target_freq, relation, policy->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) switch (relation) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) case CPUFREQ_RELATION_H:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) suboptimal.frequency = ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) case CPUFREQ_RELATION_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) case CPUFREQ_RELATION_C:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) optimal.frequency = ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) cpufreq_for_each_valid_entry_idx(pos, table, i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) freq = pos->frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) if ((freq < policy->min) || (freq > policy->max))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (freq == target_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) optimal.driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) switch (relation) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) case CPUFREQ_RELATION_H:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (freq < target_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (freq >= optimal.frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) optimal.frequency = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) optimal.driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (freq <= suboptimal.frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) suboptimal.frequency = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) suboptimal.driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) case CPUFREQ_RELATION_L:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (freq > target_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (freq <= optimal.frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) optimal.frequency = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) optimal.driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (freq >= suboptimal.frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) suboptimal.frequency = freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) suboptimal.driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) case CPUFREQ_RELATION_C:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) diff = abs(freq - target_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (diff < optimal.frequency ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) (diff == optimal.frequency &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) freq > table[optimal.driver_data].frequency)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) optimal.frequency = diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) optimal.driver_data = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (optimal.driver_data > i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (suboptimal.driver_data > i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) WARN(1, "Invalid frequency table: %d\n", policy->cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) index = suboptimal.driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) index = optimal.driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) pr_debug("target index is %u, freq is:%u kHz\n", index,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) table[index].frequency);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) unsigned int freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct cpufreq_frequency_table *pos, *table = policy->freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (unlikely(!table)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) pr_debug("%s: Unable to find frequency table\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) cpufreq_for_each_valid_entry_idx(pos, table, idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (pos->frequency == freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * show_available_freqs - show available frequencies for the specified CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) bool show_boost)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ssize_t count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) struct cpufreq_frequency_table *pos, *table = policy->freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (!table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) cpufreq_for_each_valid_entry(pos, table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) * show_boost = true and driver_data = BOOST freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) * display BOOST freqs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * show_boost = false and driver_data = BOOST freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) * show_boost = true and driver_data != BOOST freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * continue - do not display anything
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * show_boost = false and driver_data != BOOST freq
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * display NON BOOST freqs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) count += sprintf(&buf[count], "%d ", pos->frequency);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) count += sprintf(&buf[count], "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) #define cpufreq_attr_available_freq(_name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct freq_attr cpufreq_freq_attr_##_name##_freqs = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) __ATTR_RO(_name##_frequencies)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * show_scaling_available_frequencies - show available normal frequencies for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * the specified CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static ssize_t scaling_available_frequencies_show(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) return show_available_freqs(policy, buf, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) cpufreq_attr_available_freq(scaling_available);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * show_available_boost_freqs - show available boost frequencies for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * the specified CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static ssize_t scaling_boost_frequencies_show(struct cpufreq_policy *policy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return show_available_freqs(policy, buf, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) cpufreq_attr_available_freq(scaling_boost);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_boost_freqs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct freq_attr *cpufreq_generic_attr[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) &cpufreq_freq_attr_scaling_available_freqs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) static int set_freq_table_sorted(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) struct cpufreq_frequency_table *pos, *table = policy->freq_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) struct cpufreq_frequency_table *prev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) int ascending = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) cpufreq_for_each_valid_entry(pos, table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (!prev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) prev = pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) if (pos->frequency == prev->frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) pr_warn("Duplicate freq-table entries: %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) pos->frequency);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) /* Frequency increased from prev to pos */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (pos->frequency > prev->frequency) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) /* But frequency was decreasing earlier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (ascending < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) pr_debug("Freq table is unsorted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) ascending++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /* Frequency decreased from prev to pos */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) /* But frequency was increasing earlier */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (ascending > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) pr_debug("Freq table is unsorted\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ascending--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) prev = pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) if (ascending > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) pr_debug("Freq table is sorted in %s order\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) ascending > 0 ? "ascending" : "descending");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (!policy->freq_table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ret = cpufreq_frequency_table_cpuinfo(policy, policy->freq_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return set_freq_table_sorted(policy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) MODULE_DESCRIPTION("CPUfreq frequency table helpers");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) MODULE_LICENSE("GPL");