2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
4 * Licensed under the terms of the GNU GPL License version 2.
19 #include "helpers/helpers.h"
21 #define NORM_FREQ_LEN 32
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'},
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]))
105 if (power
>= -1) /* not enough => pad */
107 else /* to much => strip */
108 pad
= 0, cp
+= power
+ 1;
110 if (cp
<= 0 || cp
+ pad
> NORM_FREQ_LEN
- 1)
114 for (i
= 0; i
< cp
; i
++, str
++) {
117 normalized
[i
] = *str
;
120 for (; i
< cp
+ pad
; i
++)
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 */
128 /* final conversion (and applying rounding) */
130 freq
= strtoul(normalized
, &end
, 10);
134 if (match_count
&& freq
!= ULONG_MAX
)
140 static int do_new_policy(unsigned int cpu
, struct cpufreq_policy
*new_pol
)
142 struct cpufreq_policy
*cur_pol
= cpufreq_get_policy(cpu
);
146 printf(_("wrong, unknown or unhandled CPU?\n"));
151 new_pol
->min
= cur_pol
->min
;
154 new_pol
->max
= cur_pol
->max
;
156 if (!new_pol
->governor
)
157 new_pol
->governor
= cur_pol
->governor
;
159 ret
= cpufreq_set_policy(cpu
, new_pol
);
161 cpufreq_put_policy(cur_pol
);
167 static int do_one_cpu(unsigned int cpu
, struct cpufreq_policy
*new_pol
,
168 unsigned long freq
, unsigned int pc
)
172 return cpufreq_set_frequency(cpu
, freq
);
175 /* if only one value of a policy is to be changed, we can
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
,
188 return do_new_policy(cpu
, new_pol
);
192 int cmd_freq_set(int argc
, char **argv
)
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;
202 struct cpufreq_policy new_pol
= {
208 /* parameter parsing */
210 ret
= getopt_long(argc
, argv
, "d:u:g:f:r", set_opts
, NULL
);
227 new_pol
.min
= string_to_frequency(optarg
);
228 if (new_pol
.min
== 0) {
237 new_pol
.max
= string_to_frequency(optarg
);
238 if (new_pol
.max
== 0) {
246 freq
= string_to_frequency(optarg
);
253 if (new_pol
.governor
)
256 if ((strlen(optarg
) < 3) || (strlen(optarg
) > 18)) {
260 if ((sscanf(optarg
, "%19s", gov
)) != 1) {
264 new_pol
.governor
= gov
;
269 /* parameter checking */
271 printf("the same parameter was passed more than once\n");
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"));
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"));
287 /* Default is: set all CPUs */
288 if (bitmask_isallclear(cpus_chosen
))
289 bitmask_setall(cpus_chosen
);
291 /* Also set frequency settings for related CPUs if -r is passed */
293 for (cpu
= bitmask_first(cpus_chosen
);
294 cpu
<= bitmask_last(cpus_chosen
); cpu
++) {
295 struct cpufreq_affected_cpus
*cpus
;
297 if (!bitmask_isbitset(cpus_chosen
, cpu
) ||
298 cpufreq_cpu_exists(cpu
))
301 cpus
= cpufreq_get_related_cpus(cpu
);
305 bitmask_setbit(cpus_chosen
, cpus
->cpu
);
308 cpufreq_put_related_cpus(cpus
);
314 for (cpu
= bitmask_first(cpus_chosen
);
315 cpu
<= bitmask_last(cpus_chosen
); cpu
++) {
317 if (!bitmask_isbitset(cpus_chosen
, cpu
) ||
318 cpufreq_cpu_exists(cpu
))
321 printf(_("Setting cpu: %d\n"), cpu
);
322 ret
= do_one_cpu(cpu
, &new_pol
, freq
, policychange
);