freq_table.c 8.8 KB

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