cpufreq-set.c 7.1 KB

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