1 // SPDX-License-Identifier: GPL-2.0-only
3 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
19 #include "helpers/helpers.h"
21 #define NORM_FREQ_LEN 32
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'},
32 static void print_error(void)
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"));
48 const struct freq_units def_units[] = {
50 {"khz", 0}, /* default */
57 static void print_unknown_arg(void)
59 printf(_("invalid or unknown argument\n"));
62 static unsigned long string_to_frequency(const char *str)
64 char normalized[NORM_FREQ_LEN];
65 const struct freq_units *unit;
69 int power = 0, match_count = 0, i, cp, pad;
74 for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
75 if (*scan == '.' && match_count == 0)
77 else if (*scan == '.' && match_count == 1)
83 for (unit = def_units; unit->str_unit; unit++) {
85 scan[i] && tolower(scan[i]) == unit->str_unit[i];
91 power = unit->power_of_ten;
97 /* count the number of digits to be copied */
98 for (cp = 0; isdigit(str[cp]); cp++)
101 if (str[cp] == '.') {
102 while (power > -1 && isdigit(str[cp+1])) {
107 if (power >= -1) { /* not enough => pad */
109 } else { /* too much => strip */
114 if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
118 for (i = 0; i < cp; i++, str++) {
121 normalized[i] = *str;
124 for (; i < cp + pad; i++)
127 /* round up, down ? */
128 match_count = (normalized[i-1] >= '5');
129 /* and drop the decimal part */
130 normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
132 /* final conversion (and applying rounding) */
134 freq = strtoul(normalized, &end, 10);
138 if (match_count && freq != ULONG_MAX)
144 static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
146 struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
150 printf(_("wrong, unknown or unhandled CPU?\n"));
155 new_pol->min = cur_pol->min;
158 new_pol->max = cur_pol->max;
160 if (!new_pol->governor)
161 new_pol->governor = cur_pol->governor;
163 ret = cpufreq_set_policy(cpu, new_pol);
165 cpufreq_put_policy(cur_pol);
171 static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
172 unsigned long freq, unsigned int pc)
176 return cpufreq_set_frequency(cpu, freq);
179 /* if only one value of a policy is to be changed, we can
183 return cpufreq_modify_policy_min(cpu, new_pol->min);
184 else if (new_pol->max)
185 return cpufreq_modify_policy_max(cpu, new_pol->max);
186 else if (new_pol->governor)
187 return cpufreq_modify_policy_governor(cpu,
192 return do_new_policy(cpu, new_pol);
196 int cmd_freq_set(int argc, char **argv)
199 extern int optind, opterr, optopt;
200 int ret = 0, cont = 1;
201 int double_parm = 0, related = 0, policychange = 0;
202 unsigned long freq = 0;
206 struct cpufreq_policy new_pol = {
212 /* parameter parsing */
214 ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);
231 new_pol.min = string_to_frequency(optarg);
232 if (new_pol.min == 0) {
241 new_pol.max = string_to_frequency(optarg);
242 if (new_pol.max == 0) {
250 freq = string_to_frequency(optarg);
257 if (new_pol.governor)
260 if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
264 if ((sscanf(optarg, "%19s", gov)) != 1) {
268 new_pol.governor = gov;
273 /* parameter checking */
275 printf("the same parameter was passed more than once\n");
279 if (freq && policychange) {
280 printf(_("the -f/--freq parameter cannot be combined with -d/--min, -u/--max or\n"
281 "-g/--governor parameters\n"));
285 if (!freq && !policychange) {
286 printf(_("At least one parameter out of -f/--freq, -d/--min, -u/--max, and\n"
287 "-g/--governor must be passed\n"));
291 /* Default is: set all CPUs */
292 if (bitmask_isallclear(cpus_chosen))
293 bitmask_setall(cpus_chosen);
295 /* Also set frequency settings for related CPUs if -r is passed */
297 for (cpu = bitmask_first(cpus_chosen);
298 cpu <= bitmask_last(cpus_chosen); cpu++) {
299 struct cpufreq_affected_cpus *cpus;
301 if (!bitmask_isbitset(cpus_chosen, cpu) ||
302 cpupower_is_cpu_online(cpu) != 1)
305 cpus = cpufreq_get_related_cpus(cpu);
309 bitmask_setbit(cpus_chosen, cpus->cpu);
312 /* Set the last cpu in related cpus list */
313 bitmask_setbit(cpus_chosen, cpus->cpu);
314 cpufreq_put_related_cpus(cpus);
321 for (cpu = bitmask_first(cpus_chosen);
322 cpu <= bitmask_last(cpus_chosen); cpu++) {
324 if (!bitmask_isbitset(cpus_chosen, cpu) ||
325 cpupower_is_cpu_online(cpu) != 1)
328 printf(_("Setting cpu: %d\n"), cpu);
329 ret = do_one_cpu(cpu, &new_pol, freq, policychange);
336 print_offline_cpus();