cpupower: make NLS truly optional
[linux-2.6.git] / tools / power / cpupower / utils / cpufreq-set.c
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
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 void freq_set_help(void)
24 {
25         printf(_("Usage: cpupower frequency-set [options]\n"));
26         printf(_("Options:\n"));
27         printf(_("  -d FREQ, --min FREQ      new minimum CPU frequency the governor may select\n"));
28         printf(_("  -u FREQ, --max FREQ      new maximum CPU frequency the governor may select\n"));
29         printf(_("  -g GOV, --governor GOV   new cpufreq governor\n"));
30         printf(_("  -f FREQ, --freq FREQ     specific frequency to be set. Requires userspace\n"
31                "                           governor to be available and loaded\n"));
32         printf(_("  -r, --related            Switches all hardware-related CPUs\n"));
33         printf(_("  -h, --help               Prints out this screen\n"));
34         printf("\n");
35         printf(_("Notes:\n"
36                "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
37         printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
38                "   except the -c CPU, --cpu CPU parameter\n"
39                "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
40                "   by postfixing the value with the wanted unit name, without any space\n"
41                "   (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
42
43 }
44
45 static struct option set_opts[] = {
46         { .name = "min",        .has_arg = required_argument,   .flag = NULL,   .val = 'd'},
47         { .name = "max",        .has_arg = required_argument,   .flag = NULL,   .val = 'u'},
48         { .name = "governor",   .has_arg = required_argument,   .flag = NULL,   .val = 'g'},
49         { .name = "freq",       .has_arg = required_argument,   .flag = NULL,   .val = 'f'},
50         { .name = "help",       .has_arg = no_argument,         .flag = NULL,   .val = 'h'},
51         { .name = "related",    .has_arg = no_argument,         .flag = NULL,   .val='r'},
52         { },
53 };
54
55 static void print_error(void)
56 {
57         printf(_("Error setting new values. Common errors:\n"
58                         "- Do you have proper administration rights? (super-user?)\n"
59                         "- Is the governor you requested available and modprobed?\n"
60                         "- Trying to set an invalid policy?\n"
61                         "- Trying to set a specific frequency, but userspace governor is not available,\n"
62                         "   for example because of hardware which cannot be set to a specific frequency\n"
63                         "   or because the userspace governor isn't loaded?\n"));
64 };
65
66 struct freq_units {
67         char            *str_unit;
68         int             power_of_ten;
69 };
70
71 const struct freq_units def_units[] = {
72         {"hz", -3},
73         {"khz", 0}, /* default */
74         {"mhz", 3},
75         {"ghz", 6},
76         {"thz", 9},
77         {NULL, 0}
78 };
79
80 static void print_unknown_arg(void)
81 {
82         printf(_("invalid or unknown argument\n"));
83         freq_set_help();
84 }
85
86 static unsigned long string_to_frequency(const char *str)
87 {
88         char normalized[NORM_FREQ_LEN];
89         const struct freq_units *unit;
90         const char *scan;
91         char *end;
92         unsigned long freq;
93         int power = 0, match_count = 0, i, cp, pad;
94
95         while (*str == '0')
96                 str++;
97
98         for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
99                 if (*scan == '.' && match_count == 0)
100                         match_count = 1;
101                 else if (*scan == '.' && match_count == 1)
102                         return 0;
103         }
104
105         if (*scan) {
106                 match_count = 0;
107                 for (unit = def_units; unit->str_unit; unit++) {
108                         for (i = 0;
109                              scan[i] && tolower(scan[i]) == unit->str_unit[i];
110                              ++i)
111                                 continue;
112                         if (scan[i])
113                                 continue;
114                         match_count++;
115                         power = unit->power_of_ten;
116                 }
117                 if (match_count != 1)
118                         return 0;
119         }
120
121         /* count the number of digits to be copied */
122         for (cp = 0; isdigit(str[cp]); cp++)
123                 continue;
124
125         if (str[cp] == '.') {
126                 while (power > -1 && isdigit(str[cp+1]))
127                         cp++, power--;
128         }
129         if (power >= -1)        /* not enough => pad */
130                 pad = power + 1;
131         else                    /* to much => strip */
132                 pad = 0, cp += power + 1;
133         /* check bounds */
134         if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
135                 return 0;
136
137         /* copy digits */
138         for (i = 0; i < cp; i++, str++) {
139                 if (*str == '.')
140                         str++;
141                 normalized[i] = *str;
142         }
143         /* and pad */
144         for (; i < cp + pad; i++)
145                 normalized[i] = '0';
146
147         /* round up, down ? */
148         match_count = (normalized[i-1] >= '5');
149         /* and drop the decimal part */
150         normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
151
152         /* final conversion (and applying rounding) */
153         errno = 0;
154         freq = strtoul(normalized, &end, 10);
155         if (errno)
156                 return 0;
157         else {
158                 if (match_count && freq != ULONG_MAX)
159                         freq++;
160                 return freq;
161         }
162 }
163
164 static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
165 {
166         struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
167         int ret;
168
169         if (!cur_pol) {
170                 printf(_("wrong, unknown or unhandled CPU?\n"));
171                 return -EINVAL;
172         }
173
174         if (!new_pol->min)
175                 new_pol->min = cur_pol->min;
176
177         if (!new_pol->max)
178                 new_pol->max = cur_pol->max;
179
180         if (!new_pol->governor)
181                 new_pol->governor = cur_pol->governor;
182
183         ret = cpufreq_set_policy(cpu, new_pol);
184
185         cpufreq_put_policy(cur_pol);
186
187         return ret;
188 }
189
190
191 static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
192                 unsigned long freq, unsigned int pc)
193 {
194         switch (pc) {
195         case 0:
196                 return cpufreq_set_frequency(cpu, freq);
197
198         case 1:
199                 /* if only one value of a policy is to be changed, we can
200                  * use a "fast path".
201                  */
202                 if (new_pol->min)
203                         return cpufreq_modify_policy_min(cpu, new_pol->min);
204                 else if (new_pol->max)
205                         return cpufreq_modify_policy_max(cpu, new_pol->max);
206                 else if (new_pol->governor)
207                         return cpufreq_modify_policy_governor(cpu,
208                                                         new_pol->governor);
209
210         default:
211                 /* slow path */
212                 return do_new_policy(cpu, new_pol);
213         }
214 }
215
216 int cmd_freq_set(int argc, char **argv)
217 {
218         extern char *optarg;
219         extern int optind, opterr, optopt;
220         int ret = 0, cont = 1;
221         int double_parm = 0, related = 0, policychange = 0;
222         unsigned long freq = 0;
223         char gov[20];
224         unsigned int cpu;
225
226         struct cpufreq_policy new_pol = {
227                 .min = 0,
228                 .max = 0,
229                 .governor = NULL,
230         };
231
232         /* parameter parsing */
233         do {
234                 ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
235                 switch (ret) {
236                 case '?':
237                         print_unknown_arg();
238                         return -EINVAL;
239                 case 'h':
240                         freq_set_help();
241                         return 0;
242                 case -1:
243                         cont = 0;
244                         break;
245                 case 'r':
246                         if (related)
247                                 double_parm++;
248                         related++;
249                         break;
250                 case 'd':
251                         if (new_pol.min)
252                                 double_parm++;
253                         policychange++;
254                         new_pol.min = string_to_frequency(optarg);
255                         if (new_pol.min == 0) {
256                                 print_unknown_arg();
257                                 return -EINVAL;
258                         }
259                         break;
260                 case 'u':
261                         if (new_pol.max)
262                                 double_parm++;
263                         policychange++;
264                         new_pol.max = string_to_frequency(optarg);
265                         if (new_pol.max == 0) {
266                                 print_unknown_arg();
267                                 return -EINVAL;
268                         }
269                         break;
270                 case 'f':
271                         if (freq)
272                                 double_parm++;
273                         freq = string_to_frequency(optarg);
274                         if (freq == 0) {
275                                 print_unknown_arg();
276                                 return -EINVAL;
277                         }
278                         break;
279                 case 'g':
280                         if (new_pol.governor)
281                                 double_parm++;
282                         policychange++;
283                         if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
284                                 print_unknown_arg();
285                                 return -EINVAL;
286                         }
287                         if ((sscanf(optarg, "%s", gov)) != 1) {
288                                 print_unknown_arg();
289                                 return -EINVAL;
290                         }
291                         new_pol.governor = gov;
292                         break;
293                 }
294         } while (cont);
295
296         /* parameter checking */
297         if (double_parm) {
298                 printf("the same parameter was passed more than once\n");
299                 return -EINVAL;
300         }
301
302         if (freq && policychange) {
303                 printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
304                                 "-g/--governor parameters\n"));
305                 return -EINVAL;
306         }
307
308         if (!freq && !policychange) {
309                 printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
310                                 "-g/--governor must be passed\n"));
311                 return -EINVAL;
312         }
313
314         /* Default is: set all CPUs */
315         if (bitmask_isallclear(cpus_chosen))
316                 bitmask_setall(cpus_chosen);
317
318         /* Also set frequency settings for related CPUs if -r is passed */
319         if (related) {
320                 for (cpu = bitmask_first(cpus_chosen);
321                      cpu <= bitmask_last(cpus_chosen); cpu++) {
322                         struct cpufreq_affected_cpus *cpus;
323
324                         if (!bitmask_isbitset(cpus_chosen, cpu) ||
325                             cpufreq_cpu_exists(cpu))
326                                 continue;
327
328                         cpus = cpufreq_get_related_cpus(cpu);
329                         if (!cpus)
330                                 break;
331                         while (cpus->next) {
332                                 bitmask_setbit(cpus_chosen, cpus->cpu);
333                                 cpus = cpus->next;
334                         }
335                         cpufreq_put_related_cpus(cpus);
336                 }
337         }
338
339
340         /* loop over CPUs */
341         for (cpu = bitmask_first(cpus_chosen);
342              cpu <= bitmask_last(cpus_chosen); cpu++) {
343
344                 if (!bitmask_isbitset(cpus_chosen, cpu) ||
345                     cpufreq_cpu_exists(cpu))
346                         continue;
347
348                 printf(_("Setting cpu: %d\n"), cpu);
349                 ret = do_one_cpu(cpu, &new_pol, freq, policychange);
350                 if (ret)
351                         break;
352         }
353
354         if (ret)
355                 print_error();
356
357         return ret;
358 }