freq_table.c 8.9 KB

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