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