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