~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/power/cpupower/utils/cpufreq-set.c

Version: ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 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;
 45         int             power_of_ten;
 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 == '')
 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] = '';
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)
183                         return cpufreq_modify_policy_governor(cpu,
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, "%19s", 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 */
288         if (bitmask_isallclear(cpus_chosen))
289                 bitmask_setall(cpus_chosen);
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) {
305                                 bitmask_setbit(cpus_chosen, cpus->cpu);
306                                 cpus = cpus->next;
307                         }
308                         cpufreq_put_related_cpus(cpus);
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                         print_error();
325                         return ret;
326                 }
327         }
328 
329         return 0;
330 }
331 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp