freq_table.c 8.9 KB

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