root/tools/power/cpupower/utils/cpufreq-set.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. print_error
  2. print_unknown_arg
  3. string_to_frequency
  4. do_new_policy
  5. do_one_cpu
  6. cmd_freq_set

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
   4  */
   5 
   6 
   7 #include <unistd.h>
   8 #include <stdio.h>
   9 #include <errno.h>
  10 #include <stdlib.h>
  11 #include <limits.h>
  12 #include <string.h>
  13 #include <ctype.h>
  14 
  15 #include <getopt.h>
  16 
  17 #include "cpufreq.h"
  18 #include "cpuidle.h"
  19 #include "helpers/helpers.h"
  20 
  21 #define NORM_FREQ_LEN 32
  22 
  23 static struct option set_opts[] = {
  24         {"min",         required_argument,      NULL, 'd'},
  25         {"max",         required_argument,      NULL, 'u'},
  26         {"governor",    required_argument,      NULL, 'g'},
  27         {"freq",        required_argument,      NULL, 'f'},
  28         {"related",     no_argument,            NULL, '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 == '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)
 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                             cpupower_is_cpu_online(cpu) != 1)
 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                         /* Set the last cpu in related cpus list */
 309                         bitmask_setbit(cpus_chosen, cpus->cpu);
 310                         cpufreq_put_related_cpus(cpus);
 311                 }
 312         }
 313 
 314 
 315         /* loop over CPUs */
 316         for (cpu = bitmask_first(cpus_chosen);
 317              cpu <= bitmask_last(cpus_chosen); cpu++) {
 318 
 319                 if (!bitmask_isbitset(cpus_chosen, cpu) ||
 320                     cpupower_is_cpu_online(cpu) != 1)
 321                         continue;
 322 
 323                 printf(_("Setting cpu: %d\n"), cpu);
 324                 ret = do_one_cpu(cpu, &new_pol, freq, policychange);
 325                 if (ret) {
 326                         print_error();
 327                         return ret;
 328                 }
 329         }
 330 
 331         return 0;
 332 }

/* [<][>][^][v][top][bottom][index][help] */