freq_table.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
  54. int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
  55. struct cpufreq_frequency_table *table)
  56. {
  57. struct cpufreq_frequency_table *pos;
  58. unsigned int freq, next_larger = ~0;
  59. bool found = false;
  60. pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
  61. policy->min, policy->max, policy->cpu);
  62. cpufreq_verify_within_cpu_limits(policy);
  63. cpufreq_for_each_valid_entry(pos, table) {
  64. freq = pos->frequency;
  65. if ((freq >= policy->min) && (freq <= policy->max)) {
  66. found = true;
  67. break;
  68. }
  69. if ((next_larger > freq) && (freq > policy->max))
  70. next_larger = freq;
  71. }
  72. if (!found) {
  73. policy->max = next_larger;
  74. cpufreq_verify_within_cpu_limits(policy);
  75. }
  76. pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
  77. policy->min, policy->max, policy->cpu);
  78. return 0;
  79. }
  80. EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
  81. /*
  82. * Generic routine to verify policy & frequency table, requires driver to set
  83. * policy->freq_table prior to it.
  84. */
  85. int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
  86. {
  87. struct cpufreq_frequency_table *table =
  88. cpufreq_frequency_get_table(policy->cpu);
  89. if (!table)
  90. return -ENODEV;
  91. return cpufreq_frequency_table_verify(policy, table);
  92. }
  93. EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
  94. int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
  95. struct cpufreq_frequency_table *table,
  96. unsigned int target_freq,
  97. unsigned int relation,
  98. unsigned int *index)
  99. {
  100. struct cpufreq_frequency_table optimal = {
  101. .driver_data = ~0,
  102. .frequency = 0,
  103. };
  104. struct cpufreq_frequency_table suboptimal = {
  105. .driver_data = ~0,
  106. .frequency = 0,
  107. };
  108. struct cpufreq_frequency_table *pos;
  109. unsigned int freq, diff, i = 0;
  110. pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
  111. target_freq, relation, policy->cpu);
  112. switch (relation) {
  113. case CPUFREQ_RELATION_H:
  114. suboptimal.frequency = ~0;
  115. break;
  116. case CPUFREQ_RELATION_L:
  117. case CPUFREQ_RELATION_C:
  118. optimal.frequency = ~0;
  119. break;
  120. }
  121. cpufreq_for_each_valid_entry(pos, table) {
  122. freq = pos->frequency;
  123. i = pos - table;
  124. if ((freq < policy->min) || (freq > policy->max))
  125. continue;
  126. if (freq == target_freq) {
  127. optimal.driver_data = i;
  128. break;
  129. }
  130. switch (relation) {
  131. case CPUFREQ_RELATION_H:
  132. if (freq < target_freq) {
  133. if (freq >= optimal.frequency) {
  134. optimal.frequency = freq;
  135. optimal.driver_data = i;
  136. }
  137. } else {
  138. if (freq <= suboptimal.frequency) {
  139. suboptimal.frequency = freq;
  140. suboptimal.driver_data = i;
  141. }
  142. }
  143. break;
  144. case CPUFREQ_RELATION_L:
  145. if (freq > target_freq) {
  146. if (freq <= optimal.frequency) {
  147. optimal.frequency = freq;
  148. optimal.driver_data = i;
  149. }
  150. } else {
  151. if (freq >= suboptimal.frequency) {
  152. suboptimal.frequency = freq;
  153. suboptimal.driver_data = i;
  154. }
  155. }
  156. break;
  157. case CPUFREQ_RELATION_C:
  158. diff = abs(freq - target_freq);
  159. if (diff < optimal.frequency ||
  160. (diff == optimal.frequency &&
  161. freq > table[optimal.driver_data].frequency)) {
  162. optimal.frequency = diff;
  163. optimal.driver_data = i;
  164. }
  165. break;
  166. }
  167. }
  168. if (optimal.driver_data > i) {
  169. if (suboptimal.driver_data > i)
  170. return -EINVAL;
  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 0;
  177. }
  178. EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
  179. int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
  180. unsigned int freq)
  181. {
  182. struct cpufreq_frequency_table *pos, *table;
  183. table = cpufreq_frequency_get_table(policy->cpu);
  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(pos, table)
  189. if (pos->frequency == freq)
  190. return pos - table;
  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], "%d ", 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. * show_scaling_available_frequencies - 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. * show_available_boost_freqs - 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. #ifdef CONFIG_CPU_FREQ_BOOST_SW
  251. &cpufreq_freq_attr_scaling_boost_freqs,
  252. #endif
  253. NULL,
  254. };
  255. EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
  256. int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
  257. struct cpufreq_frequency_table *table)
  258. {
  259. int ret = cpufreq_frequency_table_cpuinfo(policy, table);
  260. if (!ret)
  261. policy->freq_table = table;
  262. return ret;
  263. }
  264. EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
  265. MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>");
  266. MODULE_DESCRIPTION("CPUfreq frequency table helpers");
  267. MODULE_LICENSE("GPL");