aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-11 15:28:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-11 15:28:17 -0400
commit7728f036adb25f8f7f8e36ffa9cecf6ba3ddae91 (patch)
treeb37f71e5fd0d0bdd8919b294889c51f53320c513 /tools
parent8cbd0eefcaf8cc32ded2bf229f0fc379b2ad69f2 (diff)
parentd8851b4b0c1e7cf6cae829d060510437d2d320ee (diff)
Merge tag 'pm+acpi-3.11-rc1-more' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull more power management and ACPI updates from Rafael Wysocki: - Fix for a recent cpufreq regression that caused WARN() to trigger overzealously in a couple of places and spam the kernel log with useless garbage as a result. From Viresh Kumar. - ACPI dock fix removing a discrepancy between the definition of acpi_dock_init(), which says that the function returns int, and its header in the header file, which says that it is a void function. The function is now defined as void too. - ACPI PM fix for failures to update device power states as needed, for example, during resume from system suspend, because the old state was deeper than the new one, but the new one is not D0. - Fix for two debug messages in the ACPI power resources code that don't have a newline at the end and make the kernel log difficult to read. From Mika Westerberg. - Two ACPI cleanups from Naresh Bhat and Haicheng Li. - cpupower updates from Thomas Renninger, including Intel Haswell support improvements and a new idle-set subcommand among other things. * tag 'pm+acpi-3.11-rc1-more' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / power: add missing newline to debug messages cpupower: Add Haswell family 0x45 specific idle monitor to show PC8,9,10 states cpupower: Haswell also supports the C-states introduced with SandyBridge cpupower: Introduce idle-set subcommand and C-state enabling/disabling cpupower: Implement disabling of cstate interface cpupower: Make idlestate usage unsigned ACPI / fan: Initialize acpi_state variable ACPI / scan: remove unused LIST_HEAD(acpi_device_list) ACPI / dock: Actually define acpi_dock_init() as void ACPI / PM: Fix corner case in acpi_bus_update_power() cpufreq: Fix serialization of frequency transitions
Diffstat (limited to 'tools')
-rw-r--r--tools/power/cpupower/Makefile4
-rw-r--r--tools/power/cpupower/man/cpupower-monitor.110
-rw-r--r--tools/power/cpupower/utils/builtin.h1
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c24
-rw-r--r--tools/power/cpupower/utils/cpuidle-set.c118
-rw-r--r--tools/power/cpupower/utils/cpupower.c13
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.c118
-rw-r--r--tools/power/cpupower/utils/helpers/sysfs.h10
-rw-r--r--tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c196
-rw-r--r--tools/power/cpupower/utils/idle_monitor/idle_monitors.def1
-rw-r--r--tools/power/cpupower/utils/idle_monitor/snb_idle.c4
11 files changed, 473 insertions, 26 deletions
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index d875a74a3bdf..cbfec92af327 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -128,10 +128,12 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \
128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ 128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
129 utils/helpers/pci.o utils/helpers/bitmask.o \ 129 utils/helpers/pci.o utils/helpers/bitmask.o \
130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ 130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \
131 utils/idle_monitor/hsw_ext_idle.o \
131 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ 132 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
132 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ 133 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \
133 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ 134 utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \
134 utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o 135 utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \
136 utils/cpuidle-set.o
135 137
136UTIL_SRC := $(UTIL_OBJS:.o=.c) 138UTIL_SRC := $(UTIL_OBJS:.o=.c)
137 139
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1
index e01c35d13b6e..914cbb9d9cd0 100644
--- a/tools/power/cpupower/man/cpupower-monitor.1
+++ b/tools/power/cpupower/man/cpupower-monitor.1
@@ -110,13 +110,21 @@ May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP
110kernel frequency driver periodically cleared aperf/mperf registers in those 110kernel frequency driver periodically cleared aperf/mperf registers in those
111kernels. 111kernels.
112 112
113.SS "Nehalem" "SandyBridge" 113.SS "Nehalem" "SandyBridge" "HaswellExtended"
114Intel Core and Package sleep state counters. 114Intel Core and Package sleep state counters.
115Threads (hyperthreaded cores) may not be able to enter deeper core states if 115Threads (hyperthreaded cores) may not be able to enter deeper core states if
116its sibling is utilized. 116its sibling is utilized.
117Deepest package sleep states may in reality show up as machine/platform wide 117Deepest package sleep states may in reality show up as machine/platform wide
118sleep states and can only be entered if all cores are idle. Look up Intel 118sleep states and can only be entered if all cores are idle. Look up Intel
119manuals (some are provided in the References section) for further details. 119manuals (some are provided in the References section) for further details.
120The monitors are named after the CPU family where the sleep state capabilities
121got introduced and may not match exactly the CPU name of the platform.
122For example an IvyBridge processor has sleep state capabilities which got
123introduced in Nehalem and SandyBridge processor families.
124Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep
125state monitors.
126HaswellExtended extra package sleep state capabilities are available only in a
127specific Haswell (family 0x45) and probably also other future processors.
120 128
121.SS "Fam_12h" "Fam_14h" 129.SS "Fam_12h" "Fam_14h"
122AMD laptop and desktop processor (family 12h and 14h) sleep state counters. 130AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index c10496fbe3c6..2284c8ea4e2a 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -5,6 +5,7 @@ extern int cmd_set(int argc, const char **argv);
5extern int cmd_info(int argc, const char **argv); 5extern int cmd_info(int argc, const char **argv);
6extern int cmd_freq_set(int argc, const char **argv); 6extern int cmd_freq_set(int argc, const char **argv);
7extern int cmd_freq_info(int argc, const char **argv); 7extern int cmd_freq_info(int argc, const char **argv);
8extern int cmd_idle_set(int argc, const char **argv);
8extern int cmd_idle_info(int argc, const char **argv); 9extern int cmd_idle_info(int argc, const char **argv);
9extern int cmd_monitor(int argc, const char **argv); 10extern int cmd_monitor(int argc, const char **argv);
10 11
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 8145af5f93a6..75e66de7e7a7 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -22,7 +22,7 @@
22 22
23static void cpuidle_cpu_output(unsigned int cpu, int verbose) 23static void cpuidle_cpu_output(unsigned int cpu, int verbose)
24{ 24{
25 int idlestates, idlestate; 25 unsigned int idlestates, idlestate;
26 char *tmp; 26 char *tmp;
27 27
28 printf(_ ("Analyzing CPU %d:\n"), cpu); 28 printf(_ ("Analyzing CPU %d:\n"), cpu);
@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
31 if (idlestates == 0) { 31 if (idlestates == 0) {
32 printf(_("CPU %u: No idle states\n"), cpu); 32 printf(_("CPU %u: No idle states\n"), cpu);
33 return; 33 return;
34 } else if (idlestates <= 0) {
35 printf(_("CPU %u: Can't read idle state info\n"), cpu);
36 return;
37 } 34 }
35
38 printf(_("Number of idle states: %d\n"), idlestates); 36 printf(_("Number of idle states: %d\n"), idlestates);
39 printf(_("Available idle states:")); 37 printf(_("Available idle states:"));
40 for (idlestate = 0; idlestate < idlestates; idlestate++) { 38 for (idlestate = 0; idlestate < idlestates; idlestate++) {
@@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
50 return; 48 return;
51 49
52 for (idlestate = 0; idlestate < idlestates; idlestate++) { 50 for (idlestate = 0; idlestate < idlestates; idlestate++) {
51 int disabled = sysfs_is_idlestate_disabled(cpu, idlestate);
52 /* Disabled interface not supported on older kernels */
53 if (disabled < 0)
54 disabled = 0;
53 tmp = sysfs_get_idlestate_name(cpu, idlestate); 55 tmp = sysfs_get_idlestate_name(cpu, idlestate);
54 if (!tmp) 56 if (!tmp)
55 continue; 57 continue;
56 printf("%s:\n", tmp); 58 printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
57 free(tmp); 59 free(tmp);
58 60
59 tmp = sysfs_get_idlestate_desc(cpu, idlestate); 61 tmp = sysfs_get_idlestate_desc(cpu, idlestate);
@@ -98,21 +100,13 @@ static void cpuidle_general_output(void)
98static void proc_cpuidle_cpu_output(unsigned int cpu) 100static void proc_cpuidle_cpu_output(unsigned int cpu)
99{ 101{
100 long max_allowed_cstate = 2000000000; 102 long max_allowed_cstate = 2000000000;
101 int cstates, cstate; 103 unsigned int cstate, cstates;
102 104
103 cstates = sysfs_get_idlestate_count(cpu); 105 cstates = sysfs_get_idlestate_count(cpu);
104 if (cstates == 0) { 106 if (cstates == 0) {
105 /* 107 printf(_("CPU %u: No C-states info\n"), cpu);
106 * Go on and print same useless info as you'd see with
107 * cat /proc/acpi/processor/../power
108 * printf(_("CPU %u: No C-states available\n"), cpu);
109 * return;
110 */
111 } else if (cstates <= 0) {
112 printf(_("CPU %u: Can't read C-state info\n"), cpu);
113 return; 108 return;
114 } 109 }
115 /* printf("Cstates: %d\n", cstates); */
116 110
117 printf(_("active state: C0\n")); 111 printf(_("active state: C0\n"));
118 printf(_("max_cstate: C%u\n"), cstates-1); 112 printf(_("max_cstate: C%u\n"), cstates-1);
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c
new file mode 100644
index 000000000000..c78141c5dfac
--- /dev/null
+++ b/tools/power/cpupower/utils/cpuidle-set.c
@@ -0,0 +1,118 @@
1#include <unistd.h>
2#include <stdio.h>
3#include <errno.h>
4#include <stdlib.h>
5#include <limits.h>
6#include <string.h>
7#include <ctype.h>
8
9#include <getopt.h>
10
11#include "cpufreq.h"
12#include "helpers/helpers.h"
13#include "helpers/sysfs.h"
14
15static struct option info_opts[] = {
16 { .name = "disable", .has_arg = required_argument, .flag = NULL, .val = 'd'},
17 { .name = "enable", .has_arg = required_argument, .flag = NULL, .val = 'e'},
18 { },
19};
20
21
22int cmd_idle_set(int argc, char **argv)
23{
24 extern char *optarg;
25 extern int optind, opterr, optopt;
26 int ret = 0, cont = 1, param = 0, idlestate = 0;
27 unsigned int cpu = 0;
28
29 do {
30 ret = getopt_long(argc, argv, "d:e:", info_opts, NULL);
31 if (ret == -1)
32 break;
33 switch (ret) {
34 case '?':
35 param = '?';
36 cont = 0;
37 break;
38 case 'd':
39 if (param) {
40 param = -1;
41 cont = 0;
42 break;
43 }
44 param = ret;
45 idlestate = atoi(optarg);
46 break;
47 case 'e':
48 if (param) {
49 param = -1;
50 cont = 0;
51 break;
52 }
53 param = ret;
54 idlestate = atoi(optarg);
55 break;
56 case -1:
57 cont = 0;
58 break;
59 }
60 } while (cont);
61
62 switch (param) {
63 case -1:
64 printf(_("You can't specify more than one "
65 "output-specific argument\n"));
66 exit(EXIT_FAILURE);
67 case '?':
68 printf(_("invalid or unknown argument\n"));
69 exit(EXIT_FAILURE);
70 }
71
72 /* Default is: set all CPUs */
73 if (bitmask_isallclear(cpus_chosen))
74 bitmask_setall(cpus_chosen);
75
76 for (cpu = bitmask_first(cpus_chosen);
77 cpu <= bitmask_last(cpus_chosen); cpu++) {
78
79 if (!bitmask_isbitset(cpus_chosen, cpu))
80 continue;
81
82 switch (param) {
83
84 case 'd':
85 ret = sysfs_idlestate_disable(cpu, idlestate, 1);
86 if (ret == 0)
87 printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
88 else if (ret == -1)
89 printf(_("Idlestate %u not available on CPU %u\n"),
90 idlestate, cpu);
91 else if (ret == -2)
92 printf(_("Idlestate disabling not supported by kernel\n"));
93 else
94 printf(_("Idlestate %u not disabled on CPU %u\n"),
95 idlestate, cpu);
96 break;
97 case 'e':
98 ret = sysfs_idlestate_disable(cpu, idlestate, 0);
99 if (ret == 0)
100 printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
101 else if (ret == -1)
102 printf(_("Idlestate %u not available on CPU %u\n"),
103 idlestate, cpu);
104 else if (ret == -2)
105 printf(_("Idlestate enabling not supported by kernel\n"));
106 else
107 printf(_("Idlestate %u not enabled on CPU %u\n"),
108 idlestate, cpu);
109 break;
110 default:
111 /* Not reachable with proper args checking */
112 printf(_("Invalid or unknown argument\n"));
113 exit(EXIT_FAILURE);
114 break;
115 }
116 }
117 return EXIT_SUCCESS;
118}
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 52bee591c1c5..7efc570ffbaa 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -17,12 +17,6 @@
17#include "helpers/helpers.h" 17#include "helpers/helpers.h"
18#include "helpers/bitmask.h" 18#include "helpers/bitmask.h"
19 19
20struct cmd_struct {
21 const char *cmd;
22 int (*main)(int, const char **);
23 int needs_root;
24};
25
26#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 20#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
27 21
28static int cmd_help(int argc, const char **argv); 22static int cmd_help(int argc, const char **argv);
@@ -43,10 +37,17 @@ int be_verbose;
43 37
44static void print_help(void); 38static void print_help(void);
45 39
40struct cmd_struct {
41 const char *cmd;
42 int (*main)(int, const char **);
43 int needs_root;
44};
45
46static struct cmd_struct commands[] = { 46static struct cmd_struct commands[] = {
47 { "frequency-info", cmd_freq_info, 0 }, 47 { "frequency-info", cmd_freq_info, 0 },
48 { "frequency-set", cmd_freq_set, 1 }, 48 { "frequency-set", cmd_freq_set, 1 },
49 { "idle-info", cmd_idle_info, 0 }, 49 { "idle-info", cmd_idle_info, 0 },
50 { "idle-set", cmd_idle_set, 1 },
50 { "set", cmd_set, 1 }, 51 { "set", cmd_set, 1 },
51 { "info", cmd_info, 0 }, 52 { "info", cmd_info, 0 },
52 { "monitor", cmd_monitor, 0 }, 53 { "monitor", cmd_monitor, 0 },
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 38ab91629463..5cdc600e8152 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu)
89 89
90/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ 90/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
91 91
92
93/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
94
95/*
96 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
97 * exists.
98 * For example the functionality to disable c-states was introduced in later
99 * kernel versions, this function can be used to explicitly check for this
100 * feature.
101 *
102 * returns 1 if the file exists, 0 otherwise.
103 */
104unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
105 unsigned int idlestate,
106 const char *fname)
107{
108 char path[SYSFS_PATH_MAX];
109 struct stat statbuf;
110
111
112 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
113 cpu, idlestate, fname);
114 if (stat(path, &statbuf) != 0)
115 return 0;
116 return 1;
117}
118
92/* 119/*
93 * helper function to read file from /sys into given buffer 120 * helper function to read file from /sys into given buffer
94 * fname is a relative path under "cpuX/cpuidle/stateX/" dir 121 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
@@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
121 return (unsigned int) numread; 148 return (unsigned int) numread;
122} 149}
123 150
151/*
152 * helper function to write a new value to a /sys file
153 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
154 *
155 * Returns the number of bytes written or 0 on error
156 */
157static
158unsigned int sysfs_idlestate_write_file(unsigned int cpu,
159 unsigned int idlestate,
160 const char *fname,
161 const char *value, size_t len)
162{
163 char path[SYSFS_PATH_MAX];
164 int fd;
165 ssize_t numwrite;
166
167 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
168 cpu, idlestate, fname);
169
170 fd = open(path, O_WRONLY);
171 if (fd == -1)
172 return 0;
173
174 numwrite = write(fd, value, len);
175 if (numwrite < 1) {
176 close(fd);
177 return 0;
178 }
179
180 close(fd);
181
182 return (unsigned int) numwrite;
183}
184
124/* read access to files which contain one numeric value */ 185/* read access to files which contain one numeric value */
125 186
126enum idlestate_value { 187enum idlestate_value {
@@ -128,6 +189,7 @@ enum idlestate_value {
128 IDLESTATE_POWER, 189 IDLESTATE_POWER,
129 IDLESTATE_LATENCY, 190 IDLESTATE_LATENCY,
130 IDLESTATE_TIME, 191 IDLESTATE_TIME,
192 IDLESTATE_DISABLE,
131 MAX_IDLESTATE_VALUE_FILES 193 MAX_IDLESTATE_VALUE_FILES
132}; 194};
133 195
@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
136 [IDLESTATE_POWER] = "power", 198 [IDLESTATE_POWER] = "power",
137 [IDLESTATE_LATENCY] = "latency", 199 [IDLESTATE_LATENCY] = "latency",
138 [IDLESTATE_TIME] = "time", 200 [IDLESTATE_TIME] = "time",
201 [IDLESTATE_DISABLE] = "disable",
139}; 202};
140 203
141static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, 204static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
@@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
205 return result; 268 return result;
206} 269}
207 270
271/*
272 * Returns:
273 * 1 if disabled
274 * 0 if enabled
275 * -1 if idlestate is not available
276 * -2 if disabling is not supported by the kernel
277 */
278int sysfs_is_idlestate_disabled(unsigned int cpu,
279 unsigned int idlestate)
280{
281 if (sysfs_get_idlestate_count(cpu) < idlestate)
282 return -1;
283
284 if (!sysfs_idlestate_file_exists(cpu, idlestate,
285 idlestate_value_files[IDLESTATE_DISABLE]))
286 return -2;
287 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
288}
289
290/*
291 * Pass 1 as last argument to disable or 0 to enable the state
292 * Returns:
293 * 0 on success
294 * negative values on error, for example:
295 * -1 if idlestate is not available
296 * -2 if disabling is not supported by the kernel
297 * -3 No write access to disable/enable C-states
298 */
299int sysfs_idlestate_disable(unsigned int cpu,
300 unsigned int idlestate,
301 unsigned int disable)
302{
303 char value[SYSFS_PATH_MAX];
304 int bytes_written;
305
306 if (sysfs_get_idlestate_count(cpu) < idlestate)
307 return -1;
308
309 if (!sysfs_idlestate_file_exists(cpu, idlestate,
310 idlestate_value_files[IDLESTATE_DISABLE]))
311 return -2;
312
313 snprintf(value, SYSFS_PATH_MAX, "%u", disable);
314
315 bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
316 value, sizeof(disable));
317 if (bytes_written)
318 return 0;
319 return -3;
320}
321
208unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 322unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
209 unsigned int idlestate) 323 unsigned int idlestate)
210{ 324{
211 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); 325 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
212} 326}
@@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
238 * Negativ in error case 352 * Negativ in error case
239 * Zero if cpuidle does not export any C-states 353 * Zero if cpuidle does not export any C-states
240 */ 354 */
241int sysfs_get_idlestate_count(unsigned int cpu) 355unsigned int sysfs_get_idlestate_count(unsigned int cpu)
242{ 356{
243 char file[SYSFS_PATH_MAX]; 357 char file[SYSFS_PATH_MAX];
244 struct stat statbuf; 358 struct stat statbuf;
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
index 8cb797bbceb0..d28f11fedbda 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.h
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -7,8 +7,16 @@
7 7
8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); 8extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
9 9
10extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
11 unsigned int idlestate,
12 const char *fname);
13
10extern int sysfs_is_cpu_online(unsigned int cpu); 14extern int sysfs_is_cpu_online(unsigned int cpu);
11 15
16extern int sysfs_is_idlestate_disabled(unsigned int cpu,
17 unsigned int idlestate);
18extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate,
19 unsigned int disable);
12extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 20extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
13 unsigned int idlestate); 21 unsigned int idlestate);
14extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, 22extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
@@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu,
19 unsigned int idlestate); 27 unsigned int idlestate);
20extern char *sysfs_get_idlestate_desc(unsigned int cpu, 28extern char *sysfs_get_idlestate_desc(unsigned int cpu,
21 unsigned int idlestate); 29 unsigned int idlestate);
22extern int sysfs_get_idlestate_count(unsigned int cpu); 30extern unsigned int sysfs_get_idlestate_count(unsigned int cpu);
23 31
24extern char *sysfs_get_cpuidle_governor(void); 32extern char *sysfs_get_cpuidle_governor(void);
25extern char *sysfs_get_cpuidle_driver(void); 33extern char *sysfs_get_cpuidle_driver(void);
diff --git a/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
new file mode 100644
index 000000000000..ebeaba6571a3
--- /dev/null
+++ b/tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
@@ -0,0 +1,196 @@
1/*
2 * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3 *
4 * Licensed under the terms of the GNU GPL License version 2.
5 *
6 * Based on SandyBridge monitor. Implements the new package C-states
7 * (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU.
8 */
9
10#if defined(__i386__) || defined(__x86_64__)
11
12#include <stdio.h>
13#include <stdint.h>
14#include <stdlib.h>
15#include <string.h>
16
17#include "helpers/helpers.h"
18#include "idle_monitor/cpupower-monitor.h"
19
20#define MSR_PKG_C8_RESIDENCY 0x00000630
21#define MSR_PKG_C9_RESIDENCY 0x00000631
22#define MSR_PKG_C10_RESIDENCY 0x00000632
23
24#define MSR_TSC 0x10
25
26enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT,
27 TSC = 0xFFFF };
28
29static int hsw_ext_get_count_percent(unsigned int self_id, double *percent,
30 unsigned int cpu);
31
32static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = {
33 {
34 .name = "PC8",
35 .desc = N_("Processor Package C8"),
36 .id = PC8,
37 .range = RANGE_PACKAGE,
38 .get_count_percent = hsw_ext_get_count_percent,
39 },
40 {
41 .name = "PC9",
42 .desc = N_("Processor Package C9"),
43 .desc = N_("Processor Package C2"),
44 .id = PC9,
45 .range = RANGE_PACKAGE,
46 .get_count_percent = hsw_ext_get_count_percent,
47 },
48 {
49 .name = "PC10",
50 .desc = N_("Processor Package C10"),
51 .id = PC10,
52 .range = RANGE_PACKAGE,
53 .get_count_percent = hsw_ext_get_count_percent,
54 },
55};
56
57static unsigned long long tsc_at_measure_start;
58static unsigned long long tsc_at_measure_end;
59static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT];
60static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT];
61/* valid flag for all CPUs. If a MSR read failed it will be zero */
62static int *is_valid;
63
64static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val,
65 unsigned int cpu)
66{
67 int msr;
68
69 switch (id) {
70 case PC8:
71 msr = MSR_PKG_C8_RESIDENCY;
72 break;
73 case PC9:
74 msr = MSR_PKG_C9_RESIDENCY;
75 break;
76 case PC10:
77 msr = MSR_PKG_C10_RESIDENCY;
78 break;
79 case TSC:
80 msr = MSR_TSC;
81 break;
82 default:
83 return -1;
84 };
85 if (read_msr(cpu, msr, val))
86 return -1;
87 return 0;
88}
89
90static int hsw_ext_get_count_percent(unsigned int id, double *percent,
91 unsigned int cpu)
92{
93 *percent = 0.0;
94
95 if (!is_valid[cpu])
96 return -1;
97
98 *percent = (100.0 *
99 (current_count[id][cpu] - previous_count[id][cpu])) /
100 (tsc_at_measure_end - tsc_at_measure_start);
101
102 dprint("%s: previous: %llu - current: %llu - (%u)\n",
103 hsw_ext_cstates[id].name, previous_count[id][cpu],
104 current_count[id][cpu], cpu);
105
106 dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n",
107 hsw_ext_cstates[id].name,
108 (unsigned long long) tsc_at_measure_end - tsc_at_measure_start,
109 current_count[id][cpu] - previous_count[id][cpu],
110 *percent, cpu);
111
112 return 0;
113}
114
115static int hsw_ext_start(void)
116{
117 int num, cpu;
118 unsigned long long val;
119
120 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
121 for (cpu = 0; cpu < cpu_count; cpu++) {
122 hsw_ext_get_count(num, &val, cpu);
123 previous_count[num][cpu] = val;
124 }
125 }
126 hsw_ext_get_count(TSC, &tsc_at_measure_start, 0);
127 return 0;
128}
129
130static int hsw_ext_stop(void)
131{
132 unsigned long long val;
133 int num, cpu;
134
135 hsw_ext_get_count(TSC, &tsc_at_measure_end, 0);
136
137 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
138 for (cpu = 0; cpu < cpu_count; cpu++) {
139 is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu);
140 current_count[num][cpu] = val;
141 }
142 }
143 return 0;
144}
145
146struct cpuidle_monitor intel_hsw_ext_monitor;
147
148static struct cpuidle_monitor *hsw_ext_register(void)
149{
150 int num;
151
152 if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL
153 || cpupower_cpu_info.family != 6)
154 return NULL;
155
156 switch (cpupower_cpu_info.model) {
157 case 0x45: /* HSW */
158 break;
159 default:
160 return NULL;
161 }
162
163 is_valid = calloc(cpu_count, sizeof(int));
164 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
165 previous_count[num] = calloc(cpu_count,
166 sizeof(unsigned long long));
167 current_count[num] = calloc(cpu_count,
168 sizeof(unsigned long long));
169 }
170 intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name);
171 return &intel_hsw_ext_monitor;
172}
173
174void hsw_ext_unregister(void)
175{
176 int num;
177 free(is_valid);
178 for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) {
179 free(previous_count[num]);
180 free(current_count[num]);
181 }
182}
183
184struct cpuidle_monitor intel_hsw_ext_monitor = {
185 .name = "HaswellExtended",
186 .hw_states = hsw_ext_cstates,
187 .hw_states_num = HSW_EXT_CSTATE_COUNT,
188 .start = hsw_ext_start,
189 .stop = hsw_ext_stop,
190 .do_register = hsw_ext_register,
191 .unregister = hsw_ext_unregister,
192 .needs_root = 1,
193 .overflow_s = 922000000 /* 922337203 seconds TSC overflow
194 at 20GHz */
195};
196#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
index e3f8d9b2b18f..0d6ba4dbb9c7 100644
--- a/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
+++ b/tools/power/cpupower/utils/idle_monitor/idle_monitors.def
@@ -2,6 +2,7 @@
2DEF(amd_fam14h) 2DEF(amd_fam14h)
3DEF(intel_nhm) 3DEF(intel_nhm)
4DEF(intel_snb) 4DEF(intel_snb)
5DEF(intel_hsw_ext)
5DEF(mperf) 6DEF(mperf)
6#endif 7#endif
7DEF(cpuidle_sysfs) 8DEF(cpuidle_sysfs)
diff --git a/tools/power/cpupower/utils/idle_monitor/snb_idle.c b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
index a99b43b97d6d..efc8a69c9aba 100644
--- a/tools/power/cpupower/utils/idle_monitor/snb_idle.c
+++ b/tools/power/cpupower/utils/idle_monitor/snb_idle.c
@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void)
155 case 0x2D: /* SNB Xeon */ 155 case 0x2D: /* SNB Xeon */
156 case 0x3A: /* IVB */ 156 case 0x3A: /* IVB */
157 case 0x3E: /* IVB Xeon */ 157 case 0x3E: /* IVB Xeon */
158 case 0x3C: /* HSW */
159 case 0x3F: /* HSW */
160 case 0x45: /* HSW */
161 case 0x46: /* HSW */
158 break; 162 break;
159 default: 163 default:
160 return NULL; 164 return NULL;