cpufreq-set.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. /*
  2. * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
  3. *
  4. * Licensed under the terms of the GNU GPL License version 2.
  5. */
  6. #include <unistd.h>
  7. #include <stdio.h>
  8. #include <errno.h>
  9. #include <stdlib.h>
  10. #include <limits.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <getopt.h>
  14. #include "cpufreq.h"
  15. #include "helpers/helpers.h"
  16. #include "helpers/sysfs.h"
  17. #define NORM_FREQ_LEN 32
  18. static struct option set_opts[] = {
  19. {"min", required_argument, NULL, 'd'},
  20. {"max", required_argument, NULL, 'u'},
  21. {"governor", required_argument, NULL, 'g'},
  22. {"freq", required_argument, NULL, 'f'},
  23. {"related", no_argument, NULL, 'r'},
  24. { },
  25. };
  26. static void print_error(void)
  27. {
  28. printf(_("Error setting new values. Common errors:\n"
  29. "- Do you have proper administration rights? (super-user?)\n"
  30. "- Is the governor you requested available and modprobed?\n"
  31. "- Trying to set an invalid policy?\n"
  32. "- Trying to set a specific frequency, but userspace governor is not available,\n"
  33. " for example because of hardware which cannot be set to a specific frequency\n"
  34. " or because the userspace governor isn't loaded?\n"));
  35. };
  36. struct freq_units {
  37. char *str_unit;
  38. int power_of_ten;
  39. };
  40. const struct freq_units def_units[] = {
  41. {"hz", -3},
  42. {"khz", 0}, /* default */
  43. {"mhz", 3},
  44. {"ghz", 6},
  45. {"thz", 9},
  46. {NULL, 0}
  47. };
  48. static void print_unknown_arg(void)
  49. {
  50. printf(_("invalid or unknown argument\n"));
  51. }
  52. static unsigned long string_to_frequency(const char *str)
  53. {
  54. char normalized[NORM_FREQ_LEN];
  55. const struct freq_units *unit;
  56. const char *scan;
  57. char *end;
  58. unsigned long freq;
  59. int power = 0, match_count = 0, i, cp, pad;
  60. while (*str == '0')
  61. str++;
  62. for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
  63. if (*scan == '.' && match_count == 0)
  64. match_count = 1;
  65. else if (*scan == '.' && match_count == 1)
  66. return 0;
  67. }
  68. if (*scan) {
  69. match_count = 0;
  70. for (unit = def_units; unit->str_unit; unit++) {
  71. for (i = 0;
  72. scan[i] && tolower(scan[i]) == unit->str_unit[i];
  73. ++i)
  74. continue;
  75. if (scan[i])
  76. continue;
  77. match_count++;
  78. power = unit->power_of_ten;
  79. }
  80. if (match_count != 1)
  81. return 0;
  82. }
  83. /* count the number of digits to be copied */
  84. for (cp = 0; isdigit(str[cp]); cp++)
  85. continue;
  86. if (str[cp] == '.') {
  87. while (power > -1 && isdigit(str[cp+1]))
  88. cp++, power--;
  89. }
  90. if (power >= -1) /* not enough => pad */
  91. pad = power + 1;
  92. else /* to much => strip */
  93. pad = 0, cp += power + 1;
  94. /* check bounds */
  95. if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
  96. return 0;
  97. /* copy digits */
  98. for (i = 0; i < cp; i++, str++) {
  99. if (*str == '.')
  100. str++;
  101. normalized[i] = *str;
  102. }
  103. /* and pad */
  104. for (; i < cp + pad; i++)
  105. normalized[i] = '0';
  106. /* round up, down ? */
  107. match_count = (normalized[i-1] >= '5');
  108. /* and drop the decimal part */
  109. normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
  110. /* final conversion (and applying rounding) */
  111. errno = 0;
  112. freq = strtoul(normalized, &end, 10);
  113. if (errno)
  114. return 0;
  115. else {
  116. if (match_count && freq != ULONG_MAX)
  117. freq++;
  118. return freq;
  119. }
  120. }
  121. static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
  122. {
  123. struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
  124. int ret;
  125. if (!cur_pol) {
  126. printf(_("wrong, unknown or unhandled CPU?\n"));
  127. return -EINVAL;
  128. }
  129. if (!new_pol->min)
  130. new_pol->min = cur_pol->min;
  131. if (!new_pol->max)
  132. new_pol->max = cur_pol->max;
  133. if (!new_pol->governor)
  134. new_pol->governor = cur_pol->governor;
  135. ret = cpufreq_set_policy(cpu, new_pol);
  136. cpufreq_put_policy(cur_pol);
  137. return ret;
  138. }
  139. static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
  140. unsigned long freq, unsigned int pc)
  141. {
  142. switch (pc) {
  143. case 0:
  144. return cpufreq_set_frequency(cpu, freq);
  145. case 1:
  146. /* if only one value of a policy is to be changed, we can
  147. * use a "fast path".
  148. */
  149. if (new_pol->min)
  150. return cpufreq_modify_policy_min(cpu, new_pol->min);
  151. else if (new_pol->max)
  152. return cpufreq_modify_policy_max(cpu, new_pol->max);
  153. else if (new_pol->governor)
  154. return cpufreq_modify_policy_governor(cpu,
  155. new_pol->governor);
  156. default:
  157. /* slow path */
  158. return do_new_policy(cpu, new_pol);
  159. }
  160. }
  161. int cmd_freq_set(int argc, char **argv)
  162. {
  163. extern char *optarg;
  164. extern int optind, opterr, optopt;
  165. int ret = 0, cont = 1;
  166. int double_parm = 0, related = 0, policychange = 0;
  167. unsigned long freq = 0;
  168. char gov[20];
  169. unsigned int cpu;
  170. struct cpufreq_policy new_pol = {
  171. .min = 0,
  172. .max = 0,
  173. .governor = NULL,
  174. };
  175. /* parameter parsing */
  176. do {
  177. ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);
  178. switch (ret) {
  179. case '?':
  180. print_unknown_arg();
  181. return -EINVAL;
  182. case -1:
  183. cont = 0;
  184. break;
  185. case 'r':
  186. if (related)
  187. double_parm++;
  188. related++;
  189. break;
  190. case 'd':
  191. if (new_pol.min)
  192. double_parm++;
  193. policychange++;
  194. new_pol.min = string_to_frequency(optarg);
  195. if (new_pol.min == 0) {
  196. print_unknown_arg();
  197. return -EINVAL;
  198. }
  199. break;
  200. case 'u':
  201. if (new_pol.max)
  202. double_parm++;
  203. policychange++;
  204. new_pol.max = string_to_frequency(optarg);
  205. if (new_pol.max == 0) {
  206. print_unknown_arg();
  207. return -EINVAL;
  208. }
  209. break;
  210. case 'f':
  211. if (freq)
  212. double_parm++;
  213. freq = string_to_frequency(optarg);
  214. if (freq == 0) {
  215. print_unknown_arg();
  216. return -EINVAL;
  217. }
  218. break;
  219. case 'g':
  220. if (new_pol.governor)
  221. double_parm++;
  222. policychange++;
  223. if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
  224. print_unknown_arg();
  225. return -EINVAL;
  226. }
  227. if ((sscanf(optarg, "%19s", gov)) != 1) {
  228. print_unknown_arg();
  229. return -EINVAL;
  230. }
  231. new_pol.governor = gov;
  232. break;
  233. }
  234. } while (cont);
  235. /* parameter checking */
  236. if (double_parm) {
  237. printf("the same parameter was passed more than once\n");
  238. return -EINVAL;
  239. }
  240. if (freq && policychange) {
  241. printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
  242. "-g/--governor parameters\n"));
  243. return -EINVAL;
  244. }
  245. if (!freq && !policychange) {
  246. printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
  247. "-g/--governor must be passed\n"));
  248. return -EINVAL;
  249. }
  250. /* Default is: set all CPUs */
  251. if (bitmask_isallclear(cpus_chosen))
  252. bitmask_setall(cpus_chosen);
  253. /* Also set frequency settings for related CPUs if -r is passed */
  254. if (related) {
  255. for (cpu = bitmask_first(cpus_chosen);
  256. cpu <= bitmask_last(cpus_chosen); cpu++) {
  257. struct cpufreq_affected_cpus *cpus;
  258. if (!bitmask_isbitset(cpus_chosen, cpu) ||
  259. cpufreq_cpu_exists(cpu))
  260. continue;
  261. cpus = cpufreq_get_related_cpus(cpu);
  262. if (!cpus)
  263. break;
  264. while (cpus->next) {
  265. bitmask_setbit(cpus_chosen, cpus->cpu);
  266. cpus = cpus->next;
  267. }
  268. cpufreq_put_related_cpus(cpus);
  269. }
  270. }
  271. /* loop over CPUs */
  272. for (cpu = bitmask_first(cpus_chosen);
  273. cpu <= bitmask_last(cpus_chosen); cpu++) {
  274. if (!bitmask_isbitset(cpus_chosen, cpu) ||
  275. cpufreq_cpu_exists(cpu))
  276. continue;
  277. if (sysfs_is_cpu_online(cpu) != 1)
  278. continue;
  279. printf(_("Setting cpu: %d\n"), cpu);
  280. ret = do_one_cpu(cpu, &new_pol, freq, policychange);
  281. if (ret) {
  282. print_error();
  283. return ret;
  284. }
  285. }
  286. return 0;
  287. }