summaryrefslogtreecommitdiffstats
path: root/tools/power/cpupower/utils
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/cpupower/utils')
-rw-r--r--tools/power/cpupower/utils/builtin.h18
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c665
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c357
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c245
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c154
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c153
-rw-r--r--tools/power/cpupower/utils/cpupower.c201
-rw-r--r--tools/power/cpupower/utils/helpers/amd.c137
-rw-r--r--tools/power/cpupower/utils/helpers/bitmask.c290
-rw-r--r--tools/power/cpupower/utils/helpers/bitmask.h33
-rw-r--r--tools/power/cpupower/utils/helpers/cpuid.c145
-rw-r--r--tools/power/cpupower/utils/helpers/helpers.h180
-rw-r--r--tools/power/cpupower/utils/helpers/misc.c34
-rw-r--r--tools/power/cpupower/utils/helpers/msr.c122
-rw-r--r--tools/power/cpupower/utils/helpers/pci.c44
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c350
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h23
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c108
-rw-r--r--tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c340
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c185
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c446
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h68
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def7
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.h18
-rw-r--r--tools/power/cpupower/utils/idle_monitor/mperf_monitor.c258
-rw-r--r--tools/power/cpupower/utils/idle_monitor/nhm_idle.c212
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c189
27 files changed, 4982 insertions, 0 deletions
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
new file mode 100644
index 000000000000..c870ffba5219
--- /dev/null
+++ b/tools/power/cpupower/utils/builtin.h
@@ -0,0 +1,18 @@
+#ifndef BUILTIN_H
+#define BUILTIN_H
+
+extern int cmd_set(int argc, const char **argv);
+extern int cmd_info(int argc, const char **argv);
+extern int cmd_freq_set(int argc, const char **argv);
+extern int cmd_freq_info(int argc, const char **argv);
+extern int cmd_idle_info(int argc, const char **argv);
+extern int cmd_monitor(int argc, const char **argv);
+
+extern void set_help(void);
+extern void info_help(void);
+extern void freq_set_help(void);
+extern void freq_info_help(void);
+extern void idle_info_help(void);
+extern void monitor_help(void);
+
+#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
new file mode 100644
index 000000000000..eaa8be06edfa
--- /dev/null
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -0,0 +1,665 @@
+/*
+ * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ * Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+#include "helpers/bitmask.h"
+
+#define LINE_LEN 10
+
+static unsigned int count_cpus(void)
+{
+ FILE *fp;
+ char value[LINE_LEN];
+ unsigned int ret = 0;
+ unsigned int cpunr = 0;
+
+ fp = fopen("/proc/stat", "r");
+ if(!fp) {
+ printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));
+ return 1;
+ }
+
+ while (!feof(fp)) {
+ if (!fgets(value, LINE_LEN, fp))
+ continue;
+ value[LINE_LEN - 1] = '\0';
+ if (strlen(value) < (LINE_LEN - 2))
+ continue;
+ if (strstr(value, "cpu "))
+ continue;
+ if (sscanf(value, "cpu%d ", &cpunr) != 1)
+ continue;
+ if (cpunr > ret)
+ ret = cpunr;
+ }
+ fclose(fp);
+
+ /* cpu count starts from 0, on error return 1 (UP) */
+ return (ret+1);
+}
+
+
+static void proc_cpufreq_output(void)
+{
+ unsigned int cpu, nr_cpus;
+ struct cpufreq_policy *policy;
+ unsigned int min_pctg = 0;
+ unsigned int max_pctg = 0;
+ unsigned long min, max;
+
+ printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n"));
+
+ nr_cpus = count_cpus();
+ for (cpu=0; cpu < nr_cpus; cpu++) {
+ policy = cpufreq_get_policy(cpu);
+ if (!policy)
+ continue;
+
+ if (cpufreq_get_hardware_limits(cpu, &min, &max)) {
+ max = 0;
+ } else {
+ min_pctg = (policy->min * 100) / max;
+ max_pctg = (policy->max * 100) / max;
+ }
+ printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n",
+ cpu , policy->min, max ? min_pctg : 0, policy->max, max ? max_pctg : 0, policy->governor);
+
+ cpufreq_put_policy(policy);
+ }
+}
+
+static void print_speed(unsigned long speed)
+{
+ unsigned long tmp;
+
+ if (speed > 1000000) {
+ tmp = speed % 10000;
+ if (tmp >= 5000)
+ speed += 10000;
+ printf ("%u.%02u GHz", ((unsigned int) speed/1000000),
+ ((unsigned int) (speed%1000000)/10000));
+ } else if (speed > 100000) {
+ tmp = speed % 1000;
+ if (tmp >= 500)
+ speed += 1000;
+ printf ("%u MHz", ((unsigned int) speed / 1000));
+ } else if (speed > 1000) {
+ tmp = speed % 100;
+ if (tmp >= 50)
+ speed += 100;
+ printf ("%u.%01u MHz", ((unsigned int) speed/1000),
+ ((unsigned int) (speed%1000)/100));
+ } else
+ printf ("%lu kHz", speed);
+
+ return;
+}
+
+static void print_duration(unsigned long duration)
+{
+ unsigned long tmp;
+
+ if (duration > 1000000) {
+ tmp = duration % 10000;
+ if (tmp >= 5000)
+ duration += 10000;
+ printf ("%u.%02u ms", ((unsigned int) duration/1000000),
+ ((unsigned int) (duration%1000000)/10000));
+ } else if (duration > 100000) {
+ tmp = duration % 1000;
+ if (tmp >= 500)
+ duration += 1000;
+ printf ("%u us", ((unsigned int) duration / 1000));
+ } else if (duration > 1000) {
+ tmp = duration % 100;
+ if (tmp >= 50)
+ duration += 100;
+ printf ("%u.%01u us", ((unsigned int) duration/1000),
+ ((unsigned int) (duration%1000)/100));
+ } else
+ printf ("%lu ns", duration);
+
+ return;
+}
+
+/* --boost / -b */
+
+static int get_boost_mode(unsigned int cpu) {
+ int support, active, b_states = 0, ret, pstate_no, i;
+ /* ToDo: Make this more global */
+ unsigned long pstates[MAX_HW_PSTATES] = {0,};
+
+ if (cpupower_cpu_info.vendor != X86_VENDOR_AMD &&
+ cpupower_cpu_info.vendor != X86_VENDOR_INTEL)
+ return 0;
+
+ ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);
+ if (ret) {
+ printf(_("Error while evaluating Boost Capabilities"
+ " on CPU %d -- are you root?\n"), cpu);
+ return ret;
+ }
+ /* P state changes via MSR are identified via cpuid 80000007
+ on Intel and AMD, but we assume boost capable machines can do that
+ if (cpuid_eax(0x80000000) >= 0x80000007
+ && (cpuid_edx(0x80000007) & (1 << 7)))
+ */
+
+ printf(_(" boost state support: \n"));
+
+ printf(_(" Supported: %s\n"), support ? _("yes") : _("no"));
+ printf(_(" Active: %s\n"), active ? _("yes") : _("no"));
+
+ /* ToDo: Only works for AMD for now... */
+
+ if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&
+ cpupower_cpu_info.family >= 0x10) {
+ ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states,
+ pstates, &pstate_no);
+ if (ret)
+ return ret;
+ } else
+ return 0;
+
+ printf(_(" Boost States: %d\n"), b_states);
+ printf(_(" Total States: %d\n"), pstate_no);
+ for (i = 0; i < pstate_no; i++) {
+ if (i < b_states)
+ printf(_(" Pstate-Pb%d: %luMHz (boost state)\n"),
+ i, pstates[i]);
+ else
+ printf(_(" Pstate-P%d: %luMHz\n"),
+ i - b_states, pstates[i]);
+ }
+ return 0;
+}
+
+static void debug_output_one(unsigned int cpu)
+{
+ char *driver;
+ struct cpufreq_affected_cpus *cpus;
+ struct cpufreq_available_frequencies *freqs;
+ unsigned long min, max, freq_kernel, freq_hardware;
+ unsigned long total_trans, latency;
+ unsigned long long total_time;
+ struct cpufreq_policy *policy;
+ struct cpufreq_available_governors * governors;
+ struct cpufreq_stats *stats;
+
+ if (cpufreq_cpu_exists(cpu)) {
+ return;
+ }
+
+ freq_kernel = cpufreq_get_freq_kernel(cpu);
+ freq_hardware = cpufreq_get_freq_hardware(cpu);
+
+ driver = cpufreq_get_driver(cpu);
+ if (!driver) {
+ printf(_(" no or unknown cpufreq driver is active on this CPU\n"));
+ } else {
+ printf(_(" driver: %s\n"), driver);
+ cpufreq_put_driver(driver);
+ }
+
+ cpus = cpufreq_get_related_cpus(cpu);
+ if (cpus) {
+ printf(_(" CPUs which run at the same hardware frequency: "));
+ while (cpus->next) {
+ printf("%d ", cpus->cpu);
+ cpus = cpus->next;
+ }
+ printf("%d\n", cpus->cpu);
+ cpufreq_put_related_cpus(cpus);
+ }
+
+ cpus = cpufreq_get_affected_cpus(cpu);
+ if (cpus) {
+ printf(_(" CPUs which need to have their frequency coordinated by software: "));
+ while (cpus->next) {
+ printf("%d ", cpus->cpu);
+ cpus = cpus->next;
+ }
+ printf("%d\n", cpus->cpu);
+ cpufreq_put_affected_cpus(cpus);
+ }
+
+ latency = cpufreq_get_transition_latency(cpu);
+ if (latency) {
+ printf(_(" maximum transition latency: "));
+ print_duration(latency);
+ printf(".\n");
+ }
+
+ if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) {
+ printf(_(" hardware limits: "));
+ print_speed(min);
+ printf(" - ");
+ print_speed(max);
+ printf("\n");
+ }
+
+ freqs = cpufreq_get_available_frequencies(cpu);
+ if (freqs) {
+ printf(_(" available frequency steps: "));
+ while (freqs->next) {
+ print_speed(freqs->frequency);
+ printf(", ");
+ freqs = freqs->next;
+ }
+ print_speed(freqs->frequency);
+ printf("\n");
+ cpufreq_put_available_frequencies(freqs);
+ }
+
+ governors = cpufreq_get_available_governors(cpu);
+ if (governors) {
+ printf(_(" available cpufreq governors: "));
+ while (governors->next) {
+ printf("%s, ", governors->governor);
+ governors = governors->next;
+ }
+ printf("%s\n", governors->governor);
+ cpufreq_put_available_governors(governors);
+ }
+
+ policy = cpufreq_get_policy(cpu);
+ if (policy) {
+ printf(_(" current policy: frequency should be within "));
+ print_speed(policy->min);
+ printf(_(" and "));
+ print_speed(policy->max);
+
+ printf(".\n ");
+ printf(_("The governor \"%s\" may"
+ " decide which speed to use\n within this range.\n"),
+ policy->governor);
+ cpufreq_put_policy(policy);
+ }
+
+ if (freq_kernel || freq_hardware) {
+ printf(_(" current CPU frequency is "));
+ if (freq_hardware) {
+ print_speed(freq_hardware);
+ printf(_(" (asserted by call to hardware)"));
+ }
+ else
+ print_speed(freq_kernel);
+ printf(".\n");
+ }
+ stats = cpufreq_get_stats(cpu, &total_time);
+ if (stats) {
+ printf(_(" cpufreq stats: "));
+ while (stats) {
+ print_speed(stats->frequency);
+ printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
+ stats = stats->next;
+ if (stats)
+ printf(", ");
+ }
+ cpufreq_put_stats(stats);
+ total_trans = cpufreq_get_transitions(cpu);
+ if (total_trans)
+ printf(" (%lu)\n", total_trans);
+ else
+ printf("\n");
+ }
+ get_boost_mode(cpu);
+
+}
+
+/* --freq / -f */
+
+static int get_freq_kernel(unsigned int cpu, unsigned int human) {
+ unsigned long freq = cpufreq_get_freq_kernel(cpu);
+ if (!freq)
+ return -EINVAL;
+ if (human) {
+ print_speed(freq);
+ printf("\n");
+ } else
+ printf("%lu\n", freq);
+ return 0;
+}
+
+
+/* --hwfreq / -w */
+
+static int get_freq_hardware(unsigned int cpu, unsigned int human) {
+ unsigned long freq = cpufreq_get_freq_hardware(cpu);
+ if (!freq)
+ return -EINVAL;
+ if (human) {
+ print_speed(freq);
+ printf("\n");
+ } else
+ printf("%lu\n", freq);
+ return 0;
+}
+
+/* --hwlimits / -l */
+
+static int get_hardware_limits(unsigned int cpu) {
+ unsigned long min, max;
+ if (cpufreq_get_hardware_limits(cpu, &min, &max))
+ return -EINVAL;
+ printf("%lu %lu\n", min, max);
+ return 0;
+}
+
+/* --driver / -d */
+
+static int get_driver(unsigned int cpu) {
+ char *driver = cpufreq_get_driver(cpu);
+ if (!driver)
+ return -EINVAL;
+ printf("%s\n", driver);
+ cpufreq_put_driver(driver);
+ return 0;
+}
+
+/* --policy / -p */
+
+static int get_policy(unsigned int cpu) {
+ struct cpufreq_policy *policy = cpufreq_get_policy(cpu);
+ if (!policy)
+ return -EINVAL;
+ printf("%lu %lu %s\n", policy->min, policy->max, policy->governor);
+ cpufreq_put_policy(policy);
+ return 0;
+}
+
+/* --governors / -g */
+
+static int get_available_governors(unsigned int cpu) {
+ struct cpufreq_available_governors *governors = cpufreq_get_available_governors(cpu);
+ if (!governors)
+ return -EINVAL;
+
+ while (governors->next) {
+ printf("%s ", governors->governor);
+ governors = governors->next;
+ }
+ printf("%s\n", governors->governor);
+ cpufreq_put_available_governors(governors);
+ return 0;
+}
+
+
+/* --affected-cpus / -a */
+
+static int get_affected_cpus(unsigned int cpu) {
+ struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);
+ if (!cpus)
+ return -EINVAL;
+
+ while (cpus->next) {
+ printf("%d ", cpus->cpu);
+ cpus = cpus->next;
+ }
+ printf("%d\n", cpus->cpu);
+ cpufreq_put_affected_cpus(cpus);
+ return 0;
+}
+
+/* --related-cpus / -r */
+
+static int get_related_cpus(unsigned int cpu) {
+ struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);
+ if (!cpus)
+ return -EINVAL;
+
+ while (cpus->next) {
+ printf("%d ", cpus->cpu);
+ cpus = cpus->next;
+ }
+ printf("%d\n", cpus->cpu);
+ cpufreq_put_related_cpus(cpus);
+ return 0;
+}
+
+/* --stats / -s */
+
+static int get_freq_stats(unsigned int cpu, unsigned int human) {
+ unsigned long total_trans = cpufreq_get_transitions(cpu);
+ unsigned long long total_time;
+ struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);
+ while (stats) {
+ if (human) {
+ print_speed(stats->frequency);
+ printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time);
+ }
+ else
+ printf("%lu:%llu", stats->frequency, stats->time_in_state);
+ stats = stats->next;
+ if (stats)
+ printf(", ");
+ }
+ cpufreq_put_stats(stats);
+ if (total_trans)
+ printf(" (%lu)\n", total_trans);
+ return 0;
+}
+
+/* --latency / -y */
+
+static int get_latency(unsigned int cpu, unsigned int human) {
+ unsigned long latency = cpufreq_get_transition_latency(cpu);
+ if (!latency)
+ return -EINVAL;
+
+ if (human) {
+ print_duration(latency);
+ printf("\n");
+ } else
+ printf("%lu\n", latency);
+ return 0;
+}
+
+void freq_info_help(void) {
+ printf(_("Usage: cpupower freqinfo [options]\n"));
+ printf(_("Options:\n"));
+ printf(_(" -e, --debug Prints out debug information [default]\n"));
+ printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
+ " to the cpufreq core *\n"));
+ printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
+ " it from hardware (only available to root) *\n"));
+ printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
+ printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
+ printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
+ printf(_(" -g, --governors Determines available cpufreq governors *\n"));
+ printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
+ printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
+ " coordinated by software *\n"));
+ printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
+ printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
+ printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
+ printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
+ " interface in 2.4. and early 2.6. kernels\n"));
+ printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
+ printf(_(" -h, --help Prints out this screen\n"));
+
+ printf("\n");
+ printf(_("If no argument is given, full output about\n"
+ "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
+ printf(_("By default info of CPU 0 is shown which can be overridden \n"
+ "with the cpupower --cpu main command option.\n"));
+}
+
+static struct option info_opts[] = {
+ { .name="debug", .has_arg=no_argument, .flag=NULL, .val='e'},
+ { .name="boost", .has_arg=no_argument, .flag=NULL, .val='b'},
+ { .name="freq", .has_arg=no_argument, .flag=NULL, .val='f'},
+ { .name="hwfreq", .has_arg=no_argument, .flag=NULL, .val='w'},
+ { .name="hwlimits", .has_arg=no_argument, .flag=NULL, .val='l'},
+ { .name="driver", .has_arg=no_argument, .flag=NULL, .val='d'},
+ { .name="policy", .has_arg=no_argument, .flag=NULL, .val='p'},
+ { .name="governors", .has_arg=no_argument, .flag=NULL, .val='g'},
+ { .name="related-cpus", .has_arg=no_argument, .flag=NULL, .val='r'},
+ { .name="affected-cpus",.has_arg=no_argument, .flag=NULL, .val='a'},
+ { .name="stats", .has_arg=no_argument, .flag=NULL, .val='s'},
+ { .name="latency", .has_arg=no_argument, .flag=NULL, .val='y'},
+ { .name="proc", .has_arg=no_argument, .flag=NULL, .val='o'},
+ { .name="human", .has_arg=no_argument, .flag=NULL, .val='m'},
+ { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
+ { },
+};
+
+int cmd_freq_info(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+ int ret = 0, cont = 1;
+ unsigned int cpu = 0;
+ unsigned int human = 0;
+ int output_param = 0;
+
+ do {
+ ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
+ switch (ret) {
+ case '?':
+ output_param = '?';
+ cont = 0;
+ break;
+ case 'h':
+ output_param = 'h';
+ cont = 0;
+ break;
+ case -1:
+ cont = 0;
+ break;
+ case 'b':
+ case 'o':
+ case 'a':
+ case 'r':
+ case 'g':
+ case 'p':
+ case 'd':
+ case 'l':
+ case 'w':
+ case 'f':
+ case 'e':
+ case 's':
+ case 'y':
+ if (output_param) {
+ output_param = -1;
+ cont = 0;
+ break;
+ }
+ output_param = ret;
+ break;
+ case 'm':
+ if (human) {
+ output_param = -1;
+ cont = 0;
+ break;
+ }
+ human = 1;
+ break;
+ default:
+ fprintf(stderr, "invalid or unknown argument\n");
+ return EXIT_FAILURE;
+ }
+ } while(cont);
+
+ switch (output_param) {
+ case 'o':
+ if (!bitmask_isallclear(cpus_chosen)) {
+ printf(_("The argument passed to this tool can't be "
+ "combined with passing a --cpu argument\n"));
+ return -EINVAL;
+ }
+ break;
+ case 0:
+ output_param = 'e';
+ }
+
+ ret = 0;
+
+ /* Default is: show output of CPU 0 only */
+ if (bitmask_isallclear(cpus_chosen))
+ bitmask_setbit(cpus_chosen, 0);
+
+ switch (output_param) {
+ case -1:
+ printf(_("You can't specify more than one --cpu parameter and/or\n"
+ "more than one output-specific argument\n"));
+ return -EINVAL;
+ case '?':
+ printf(_("invalid or unknown argument\n"));
+ freq_info_help();
+ return -EINVAL;
+ case 'h':
+ freq_info_help();
+ return EXIT_SUCCESS;
+ case 'o':
+ proc_cpufreq_output();
+ return EXIT_SUCCESS;
+ }
+
+ for (cpu = bitmask_first(cpus_chosen);
+ cpu <= bitmask_last(cpus_chosen); cpu++) {
+
+ if (!bitmask_isbitset(cpus_chosen, cpu))
+ continue;
+ if (cpufreq_cpu_exists(cpu)) {
+ printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu);
+ continue;
+ }
+ printf(_("analyzing CPU %d:\n"), cpu);
+
+ switch (output_param) {
+ case 'b':
+ get_boost_mode(cpu);
+ break;
+ case 'e':
+ debug_output_one(cpu);
+ break;
+ case 'a':
+ ret = get_affected_cpus(cpu);
+ break;
+ case 'r':
+ ret = get_related_cpus(cpu);
+ break;
+ case 'g':
+ ret = get_available_governors(cpu);
+ break;
+ case 'p':
+ ret = get_policy(cpu);
+ break;
+ case 'd':
+ ret = get_driver(cpu);
+ break;
+ case 'l':
+ ret = get_hardware_limits(cpu);
+ break;
+ case 'w':
+ ret = get_freq_hardware(cpu, human);
+ break;
+ case 'f':
+ ret = get_freq_kernel(cpu, human);
+ break;
+ case 's':
+ ret = get_freq_stats(cpu, human);
+ break;
+ case 'y':
+ ret = get_latency(cpu, human);
+ break;
+ }
+ if (ret)
+ return (ret);
+ }
+ return ret;
+}
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
new file mode 100644
index 000000000000..d415b6b52a09
--- /dev/null
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -0,0 +1,357 @@
+/*
+ * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
+ *
+ * Licensed under the terms of the GNU GPL License version 2.
+ */
+
+
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <getopt.h>
+
+#include "cpufreq.h"
+#include "helpers/helpers.h"
+
+#define NORM_FREQ_LEN 32
+
+void freq_set_help(void)
+{
+ printf(_("Usage: cpupower frequency-set [options]\n"));
+ printf(_("Options:\n"));
+ printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n"));
+ printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n"));
+ printf(_(" -g GOV, --governor GOV new cpufreq governor\n"));
+ printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
+ " governor to be available and loaded\n"));
+ printf(_(" -r, --related Switches all hardware-related CPUs\n"));
+ printf(_(" -h, --help Prints out this screen\n"));
+ printf("\n");
+ printf(_("Notes:\n"
+ "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
+ printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
+ " except the -c CPU, --cpu CPU parameter\n"
+ "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
+ " by postfixing the value with the wanted unit name, without any space\n"
+ " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
+
+}
+
+static struct option set_opts[] = {
+ { .name="min", .has_arg=required_argument, .flag=NULL, .val='d'},
+ { .name="max", .has_arg=required_argument, .flag=NULL, .val='u'},
+ { .name="governor", .has_arg=required_argument, .flag=NULL, .val='g'},
+ { .name="freq", .has_arg=required_argument, .flag=NULL, .val='f'},
+ { .name="help", .has_arg=no_argument, .flag=NULL, .val='h'},
+ { .name="related", .has_arg=no_argument, .flag=NULL, .val='r'},
+ { },
+};
+
+static void print_error(void)
+{
+ printf(_("Error setting new values. Common errors:\n"
+ "- Do you have proper administration rights? (super-user?)\n"
+ "- Is the governor you requested available and modprobed?\n"
+ "- Trying to set an invalid policy?\n"
+ "- Trying to set a specific frequency, but userspace governor is not available,\n"
+ " for example because of hardware which cannot be set to a specific frequency\n"
+ " or because the userspace governor isn't loaded?\n"));
+};
+
+struct freq_units {
+ char* str_unit;
+ int power_of_ten;
+};
+
+const struct freq_units def_units[] = {
+ {"hz", -3},
+ {"khz", 0}, /* default */
+ {"mhz", 3},
+ {"ghz", 6},
+ {"thz", 9},
+ {NULL, 0}
+};
+
+static void print_unknown_arg(void)
+{
+ printf(_("invalid or unknown argument\n"));
+ freq_set_help();
+}
+
+static unsigned long string_to_frequency(const char *str)
+{
+ char normalized[NORM_FREQ_LEN];
+ const struct freq_units *unit;
+ const char *scan;
+ char *end;
+ unsigned long freq;
+ int power = 0, match_count = 0, i, cp, pad;
+
+ while (*str == '0')
+ str++;
+
+ for (scan = str; isdigit(*scan) || *scan == '.'; scan++) {
+ if (*scan == '.' && match_count == 0)
+ match_count = 1;
+ else if (*scan == '.' && match_count == 1)
+ return 0;
+ }
+
+ if (*scan) {
+ match_count = 0;
+ for (unit = def_units; unit->str_unit; unit++) {
+ for (i = 0;
+ scan[i] && tolower(scan[i]) == unit->str_unit[i];
+ ++i)
+ continue;
+ if (scan[i])
+ continue;
+ match_count++;
+ power = unit->power_of_ten;
+ }
+ if (match_count != 1)
+ return 0;
+ }
+
+ /* count the number of digits to be copied */
+ for (cp = 0; isdigit(str[cp]); cp++)
+ continue;
+
+ if (str[cp] == '.') {
+ while (power > -1 && isdigit(str[cp+1]))
+ cp++, power--;
+ }
+ if (power >= -1) /* not enough => pad */
+ pad = power + 1;
+ else /* to much => strip */
+ pad = 0, cp += power + 1;
+ /* check bounds */
+ if (cp <= 0 || cp + pad > NORM_FREQ_LEN - 1)
+ return 0;
+
+ /* copy digits */
+ for (i = 0; i < cp; i++, str++) {
+ if (*str == '.')
+ str++;
+ normalized[i] = *str;
+ }
+ /* and pad */
+ for (; i < cp + pad; i++)
+ normalized[i] = '0';
+
+ /* round up, down ? */
+ match_count = (normalized[i-1] >= '5');
+ /* and drop the decimal part */
+ normalized[i-1] = 0; /* cp > 0 && pad >= 0 ==> i > 0 */
+
+ /* final conversion (and applying rounding) */
+ errno = 0;
+ freq = strtoul(normalized, &end, 10);
+ if (errno)
+ return 0;
+ else {
+ if (match_count && freq != ULONG_MAX)
+ freq++;
+ return freq;
+ }
+}
+
+static int do_new_policy(unsigned int cpu, struct cpufreq_policy *new_pol)
+{
+ struct cpufreq_policy *cur_pol = cpufreq_get_policy(cpu);
+ int ret;
+
+ if (!cur_pol) {
+ printf(_("wrong, unknown or unhandled CPU?\n"));
+ return -EINVAL;
+ }
+
+ if (!new_pol->min)
+ new_pol->min = cur_pol->min;
+
+ if (!new_pol->max)
+ new_pol->max = cur_pol->max;
+
+ if (!new_pol->governor)
+ new_pol->governor = cur_pol->governor;
+
+ ret = cpufreq_set_policy(cpu, new_pol);
+
+ cpufreq_put_policy(cur_pol);
+
+ return ret;
+}
+
+
+static int do_one_cpu(unsigned int cpu, struct cpufreq_policy *new_pol,
+ unsigned long freq, unsigned int pc)
+{
+ switch (pc) {
+ case 0:
+ return cpufreq_set_frequency(cpu, freq);
+
+ case 1:
+ /* if only one value of a policy is to be changed, we can
+ * use a "fast path".
+ */
+ if (new_pol->min)
+ return cpufreq_modify_policy_min(cpu, new_pol->min);
+ else if (new_pol->max)
+ return cpufreq_modify_policy_max(cpu, new_pol->max);
+ else if (new_pol->governor)
+ return cpufreq_modify_policy_governor(cpu, new_pol->governor);
+
+ default:
+ /* slow path */
+ return do_new_policy(cpu, new_pol);
+ }
+}
+
+int cmd_freq_set(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind, opterr, optopt;
+ int ret = 0, cont = 1;
+ int double_parm = 0, related = 0, policychange = 0;
+ unsigned long freq = 0;
+ char gov[20];
+ unsigned int cpu;
+
+ struct cpufreq_policy new_pol = {
+ .min = 0,
+ .max = 0,
+ .governor = NULL,
+ };
+
+ /* parameter parsing */
+ do {
+ ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
+ switch (ret) {
+ case '?':
+ print_unknown_arg();
+ return -EINVAL;
+ case 'h':
+ freq_set_help();
+ return 0;
+ case -1:
+ cont = 0;
+ break;
+ case 'r':
+ if (related)
+ double_parm++;
+ related++;
+ break;
+ case 'd':
+ if (new_pol.min)
+ double_parm++;
+ policychange++;
+ new_pol.min = string_to_frequency(optarg);
+ if (new_pol.min == 0) {
+ print_unknown_arg();
+ return -EINVAL;
+ }
+ break;
+ case 'u':
+ if (new_pol.max)
+ double_parm++;
+ policychange++;
+ new_pol.max = string_to_frequency(optarg);
+ if (new_pol.max == 0) {
+ print_unknown_arg();
+ return -EINVAL;
+ }
+ break;
+ case 'f':
+ if (freq)
+ double_parm++;
+ freq = string_to_frequency(optarg);
+ if (freq == 0) {
+ print_unknown_arg();
+ return -EINVAL;
+ }
+ break;
+ case 'g':
+ if (new_pol.governor)
+ double_parm++;
+ policychange++;
+ if ((strlen(optarg) < 3) || (strlen(optarg) > 18)) {
+ print_unknown_arg();
+ return -EINVAL;
+ }
+ if ((s