Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+502 -43
+18 -5
drivers/acpi/device_pm.c
··· 324 324 if (result) 325 325 return result; 326 326 327 - if (state == ACPI_STATE_UNKNOWN) 327 + if (state == ACPI_STATE_UNKNOWN) { 328 328 state = ACPI_STATE_D0; 329 - 330 - result = acpi_device_set_power(device, state); 331 - if (!result && state_p) 329 + result = acpi_device_set_power(device, state); 330 + if (result) 331 + return result; 332 + } else { 333 + if (device->power.flags.power_resources) { 334 + /* 335 + * We don't need to really switch the state, bu we need 336 + * to update the power resources' reference counters. 337 + */ 338 + result = acpi_power_transition(device, state); 339 + if (result) 340 + return result; 341 + } 342 + device->power.state = state; 343 + } 344 + if (state_p) 332 345 *state_p = state; 333 346 334 - return result; 347 + return 0; 335 348 } 336 349 EXPORT_SYMBOL_GPL(acpi_bus_update_power); 337 350
+3 -4
drivers/acpi/dock.c
··· 1064 1064 return AE_OK; 1065 1065 } 1066 1066 1067 - int __init acpi_dock_init(void) 1067 + void __init acpi_dock_init(void) 1068 1068 { 1069 1069 if (acpi_disabled) 1070 - return 0; 1070 + return; 1071 1071 1072 1072 /* look for dock stations and bays */ 1073 1073 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ··· 1075 1075 1076 1076 if (!dock_station_count) { 1077 1077 pr_info(PREFIX "No dock devices found.\n"); 1078 - return 0; 1078 + return; 1079 1079 } 1080 1080 1081 1081 register_acpi_bus_notifier(&dock_acpi_notifier); 1082 1082 pr_info(PREFIX "%s: %d docks/bays found\n", 1083 1083 ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); 1084 - return 0; 1085 1084 }
+1 -1
drivers/acpi/fan.c
··· 84 84 { 85 85 struct acpi_device *device = cdev->devdata; 86 86 int result; 87 - int acpi_state; 87 + int acpi_state = ACPI_STATE_D0; 88 88 89 89 if (!device) 90 90 return -EINVAL;
+2 -2
drivers/acpi/power.c
··· 279 279 280 280 if (resource->ref_count++) { 281 281 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 282 - "Power resource [%s] already on", 282 + "Power resource [%s] already on\n", 283 283 resource->name)); 284 284 } else { 285 285 result = __acpi_power_on(resource); ··· 325 325 326 326 if (!resource->ref_count) { 327 327 ACPI_DEBUG_PRINT((ACPI_DB_INFO, 328 - "Power resource [%s] already off", 328 + "Power resource [%s] already off\n", 329 329 resource->name)); 330 330 return 0; 331 331 }
-1
drivers/acpi/scan.c
··· 35 35 36 36 static const char *dummy_hid = "device"; 37 37 38 - static LIST_HEAD(acpi_device_list); 39 38 static LIST_HEAD(acpi_bus_id_list); 40 39 static DEFINE_MUTEX(acpi_scan_lock); 41 40 static LIST_HEAD(acpi_scan_handlers_list);
+4 -3
drivers/cpufreq/cpufreq.c
··· 312 312 switch (state) { 313 313 314 314 case CPUFREQ_PRECHANGE: 315 - if (WARN(policy->transition_ongoing, 315 + if (WARN(policy->transition_ongoing == 316 + cpumask_weight(policy->cpus), 316 317 "In middle of another frequency transition\n")) 317 318 return; 318 319 319 - policy->transition_ongoing = true; 320 + policy->transition_ongoing++; 320 321 321 322 /* detect if the driver reported a value as "old frequency" 322 323 * which is not equal to what the cpufreq core thinks is ··· 342 341 "No frequency transition in progress\n")) 343 342 return; 344 343 345 - policy->transition_ongoing = false; 344 + policy->transition_ongoing--; 346 345 347 346 adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); 348 347 pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
+1 -1
include/linux/cpufreq.h
··· 119 119 120 120 struct kobject kobj; 121 121 struct completion kobj_unregister; 122 - bool transition_ongoing; /* Tracks transition status */ 122 + int transition_ongoing; /* Tracks transition status */ 123 123 }; 124 124 125 125 #define CPUFREQ_ADJUST (0)
+3 -1
tools/power/cpupower/Makefile
··· 128 128 utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ 129 129 utils/helpers/pci.o utils/helpers/bitmask.o \ 130 130 utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ 131 + utils/idle_monitor/hsw_ext_idle.o \ 131 132 utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ 132 133 utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ 133 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 136 138 UTIL_SRC := $(UTIL_OBJS:.o=.c) 137 139
+9 -1
tools/power/cpupower/man/cpupower-monitor.1
··· 110 110 kernel frequency driver periodically cleared aperf/mperf registers in those 111 111 kernels. 112 112 113 - .SS "Nehalem" "SandyBridge" 113 + .SS "Nehalem" "SandyBridge" "HaswellExtended" 114 114 Intel Core and Package sleep state counters. 115 115 Threads (hyperthreaded cores) may not be able to enter deeper core states if 116 116 its sibling is utilized. 117 117 Deepest package sleep states may in reality show up as machine/platform wide 118 118 sleep states and can only be entered if all cores are idle. Look up Intel 119 119 manuals (some are provided in the References section) for further details. 120 + The monitors are named after the CPU family where the sleep state capabilities 121 + got introduced and may not match exactly the CPU name of the platform. 122 + For example an IvyBridge processor has sleep state capabilities which got 123 + introduced in Nehalem and SandyBridge processor families. 124 + Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep 125 + state monitors. 126 + HaswellExtended extra package sleep state capabilities are available only in a 127 + specific Haswell (family 0x45) and probably also other future processors. 120 128 121 129 .SS "Fam_12h" "Fam_14h" 122 130 AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
+1
tools/power/cpupower/utils/builtin.h
··· 5 5 extern int cmd_info(int argc, const char **argv); 6 6 extern int cmd_freq_set(int argc, const char **argv); 7 7 extern int cmd_freq_info(int argc, const char **argv); 8 + extern int cmd_idle_set(int argc, const char **argv); 8 9 extern int cmd_idle_info(int argc, const char **argv); 9 10 extern int cmd_monitor(int argc, const char **argv); 10 11
+9 -15
tools/power/cpupower/utils/cpuidle-info.c
··· 22 22 23 23 static void cpuidle_cpu_output(unsigned int cpu, int verbose) 24 24 { 25 - int idlestates, idlestate; 25 + unsigned int idlestates, idlestate; 26 26 char *tmp; 27 27 28 28 printf(_ ("Analyzing CPU %d:\n"), cpu); ··· 31 31 if (idlestates == 0) { 32 32 printf(_("CPU %u: No idle states\n"), cpu); 33 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 36 printf(_("Number of idle states: %d\n"), idlestates); 39 37 printf(_("Available idle states:")); 40 38 for (idlestate = 0; idlestate < idlestates; idlestate++) { ··· 48 50 return; 49 51 50 52 for (idlestate = 0; idlestate < idlestates; idlestate++) { 53 + int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); 54 + /* Disabled interface not supported on older kernels */ 55 + if (disabled < 0) 56 + disabled = 0; 51 57 tmp = sysfs_get_idlestate_name(cpu, idlestate); 52 58 if (!tmp) 53 59 continue; 54 - printf("%s:\n", tmp); 60 + printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); 55 61 free(tmp); 56 62 57 63 tmp = sysfs_get_idlestate_desc(cpu, idlestate); ··· 100 98 static void proc_cpuidle_cpu_output(unsigned int cpu) 101 99 { 102 100 long max_allowed_cstate = 2000000000; 103 - int cstates, cstate; 101 + unsigned int cstate, cstates; 104 102 105 103 cstates = sysfs_get_idlestate_count(cpu); 106 104 if (cstates == 0) { 107 - /* 108 - * Go on and print same useless info as you'd see with 109 - * cat /proc/acpi/processor/../power 110 - * printf(_("CPU %u: No C-states available\n"), cpu); 111 - * return; 112 - */ 113 - } else if (cstates <= 0) { 114 - printf(_("CPU %u: Can't read C-state info\n"), cpu); 105 + printf(_("CPU %u: No C-states info\n"), cpu); 115 106 return; 116 107 } 117 - /* printf("Cstates: %d\n", cstates); */ 118 108 119 109 printf(_("active state: C0\n")); 120 110 printf(_("max_cstate: C%u\n"), cstates-1);
+118
tools/power/cpupower/utils/cpuidle-set.c
··· 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 + 15 + static 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 + 22 + int 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 + }
+7 -6
tools/power/cpupower/utils/cpupower.c
··· 17 17 #include "helpers/helpers.h" 18 18 #include "helpers/bitmask.h" 19 19 20 - struct cmd_struct { 21 - const char *cmd; 22 - int (*main)(int, const char **); 23 - int needs_root; 24 - }; 25 - 26 20 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 27 21 28 22 static int cmd_help(int argc, const char **argv); ··· 37 43 38 44 static void print_help(void); 39 45 46 + struct cmd_struct { 47 + const char *cmd; 48 + int (*main)(int, const char **); 49 + int needs_root; 50 + }; 51 + 40 52 static struct cmd_struct commands[] = { 41 53 { "frequency-info", cmd_freq_info, 0 }, 42 54 { "frequency-set", cmd_freq_set, 1 }, 43 55 { "idle-info", cmd_idle_info, 0 }, 56 + { "idle-set", cmd_idle_set, 1 }, 44 57 { "set", cmd_set, 1 }, 45 58 { "info", cmd_info, 0 }, 46 59 { "monitor", cmd_monitor, 0 },
+116 -2
tools/power/cpupower/utils/helpers/sysfs.c
··· 89 89 90 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 + */ 104 + unsigned 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 120 * helper function to read file from /sys into given buffer 94 121 * fname is a relative path under "cpuX/cpuidle/stateX/" dir ··· 148 121 return (unsigned int) numread; 149 122 } 150 123 124 + /* 125 + * helper function to write a new value to a /sys file 126 + * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir 127 + * 128 + * Returns the number of bytes written or 0 on error 129 + */ 130 + static 131 + unsigned int sysfs_idlestate_write_file(unsigned int cpu, 132 + unsigned int idlestate, 133 + const char *fname, 134 + const char *value, size_t len) 135 + { 136 + char path[SYSFS_PATH_MAX]; 137 + int fd; 138 + ssize_t numwrite; 139 + 140 + snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", 141 + cpu, idlestate, fname); 142 + 143 + fd = open(path, O_WRONLY); 144 + if (fd == -1) 145 + return 0; 146 + 147 + numwrite = write(fd, value, len); 148 + if (numwrite < 1) { 149 + close(fd); 150 + return 0; 151 + } 152 + 153 + close(fd); 154 + 155 + return (unsigned int) numwrite; 156 + } 157 + 151 158 /* read access to files which contain one numeric value */ 152 159 153 160 enum idlestate_value { ··· 189 128 IDLESTATE_POWER, 190 129 IDLESTATE_LATENCY, 191 130 IDLESTATE_TIME, 131 + IDLESTATE_DISABLE, 192 132 MAX_IDLESTATE_VALUE_FILES 193 133 }; 194 134 ··· 198 136 [IDLESTATE_POWER] = "power", 199 137 [IDLESTATE_LATENCY] = "latency", 200 138 [IDLESTATE_TIME] = "time", 139 + [IDLESTATE_DISABLE] = "disable", 201 140 }; 202 141 203 142 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, ··· 268 205 return result; 269 206 } 270 207 208 + /* 209 + * Returns: 210 + * 1 if disabled 211 + * 0 if enabled 212 + * -1 if idlestate is not available 213 + * -2 if disabling is not supported by the kernel 214 + */ 215 + int sysfs_is_idlestate_disabled(unsigned int cpu, 216 + unsigned int idlestate) 217 + { 218 + if (sysfs_get_idlestate_count(cpu) < idlestate) 219 + return -1; 220 + 221 + if (!sysfs_idlestate_file_exists(cpu, idlestate, 222 + idlestate_value_files[IDLESTATE_DISABLE])) 223 + return -2; 224 + return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); 225 + } 226 + 227 + /* 228 + * Pass 1 as last argument to disable or 0 to enable the state 229 + * Returns: 230 + * 0 on success 231 + * negative values on error, for example: 232 + * -1 if idlestate is not available 233 + * -2 if disabling is not supported by the kernel 234 + * -3 No write access to disable/enable C-states 235 + */ 236 + int sysfs_idlestate_disable(unsigned int cpu, 237 + unsigned int idlestate, 238 + unsigned int disable) 239 + { 240 + char value[SYSFS_PATH_MAX]; 241 + int bytes_written; 242 + 243 + if (sysfs_get_idlestate_count(cpu) < idlestate) 244 + return -1; 245 + 246 + if (!sysfs_idlestate_file_exists(cpu, idlestate, 247 + idlestate_value_files[IDLESTATE_DISABLE])) 248 + return -2; 249 + 250 + snprintf(value, SYSFS_PATH_MAX, "%u", disable); 251 + 252 + bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable", 253 + value, sizeof(disable)); 254 + if (bytes_written) 255 + return 0; 256 + return -3; 257 + } 258 + 271 259 unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 272 - unsigned int idlestate) 260 + unsigned int idlestate) 273 261 { 274 262 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); 275 263 } ··· 352 238 * Negativ in error case 353 239 * Zero if cpuidle does not export any C-states 354 240 */ 355 - int sysfs_get_idlestate_count(unsigned int cpu) 241 + unsigned int sysfs_get_idlestate_count(unsigned int cpu) 356 242 { 357 243 char file[SYSFS_PATH_MAX]; 358 244 struct stat statbuf;
+9 -1
tools/power/cpupower/utils/helpers/sysfs.h
··· 7 7 8 8 extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); 9 9 10 + extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu, 11 + unsigned int idlestate, 12 + const char *fname); 13 + 10 14 extern int sysfs_is_cpu_online(unsigned int cpu); 11 15 16 + extern int sysfs_is_idlestate_disabled(unsigned int cpu, 17 + unsigned int idlestate); 18 + extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate, 19 + unsigned int disable); 12 20 extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, 13 21 unsigned int idlestate); 14 22 extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, ··· 27 19 unsigned int idlestate); 28 20 extern char *sysfs_get_idlestate_desc(unsigned int cpu, 29 21 unsigned int idlestate); 30 - extern int sysfs_get_idlestate_count(unsigned int cpu); 22 + extern unsigned int sysfs_get_idlestate_count(unsigned int cpu); 31 23 32 24 extern char *sysfs_get_cpuidle_governor(void); 33 25 extern char *sysfs_get_cpuidle_driver(void);
+196
tools/power/cpupower/utils/idle_monitor/hsw_ext_idle.c
··· 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 + 26 + enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT, 27 + TSC = 0xFFFF }; 28 + 29 + static int hsw_ext_get_count_percent(unsigned int self_id, double *percent, 30 + unsigned int cpu); 31 + 32 + static 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 + 57 + static unsigned long long tsc_at_measure_start; 58 + static unsigned long long tsc_at_measure_end; 59 + static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT]; 60 + static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT]; 61 + /* valid flag for all CPUs. If a MSR read failed it will be zero */ 62 + static int *is_valid; 63 + 64 + static 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 + 90 + static 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 + 115 + static 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 + 130 + static 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 + 146 + struct cpuidle_monitor intel_hsw_ext_monitor; 147 + 148 + static 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 + 174 + void 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 + 184 + struct 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__) */
+1
tools/power/cpupower/utils/idle_monitor/idle_monitors.def
··· 2 2 DEF(amd_fam14h) 3 3 DEF(intel_nhm) 4 4 DEF(intel_snb) 5 + DEF(intel_hsw_ext) 5 6 DEF(mperf) 6 7 #endif 7 8 DEF(cpuidle_sysfs)
+4
tools/power/cpupower/utils/idle_monitor/snb_idle.c
··· 155 155 case 0x2D: /* SNB Xeon */ 156 156 case 0x3A: /* IVB */ 157 157 case 0x3E: /* IVB Xeon */ 158 + case 0x3C: /* HSW */ 159 + case 0x3F: /* HSW */ 160 + case 0x45: /* HSW */ 161 + case 0x46: /* HSW */ 158 162 break; 159 163 default: 160 164 return NULL;