From a9cd442efcf76a8dde6e3693f35be0bc4cb285360a2e44f81b71278bcbef75f3 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Mon, 1 Jul 2013 09:14:16 +0000 Subject: [PATCH] - Add disable C-state capability and support for latest Haswell CPUs OBS-URL: https://build.opensuse.org/package/show/hardware/cpupower?expand=0&rev=26 --- cpupower-haswell_support.patch | 15 +- cpupower.changes | 5 + cpupower.spec | 11 +- cpupower_disable_cstates.patch | 188 ++++++++++++++ cpupower_hsw_special.patch | 233 +++++++++++++++++ ...er_make_get_idlestate_count_unsigned.patch | 79 ++++++ introduce_cpupower_idle_set.patch | 242 ++++++++++++++++++ 7 files changed, 767 insertions(+), 6 deletions(-) create mode 100644 cpupower_disable_cstates.patch create mode 100644 cpupower_hsw_special.patch create mode 100644 cpupower_make_get_idlestate_count_unsigned.patch create mode 100644 introduce_cpupower_idle_set.patch diff --git a/cpupower-haswell_support.patch b/cpupower-haswell_support.patch index 67fd54f..420b545 100644 --- a/cpupower-haswell_support.patch +++ b/cpupower-haswell_support.patch @@ -1,14 +1,19 @@ -Index: cpupower-3.8/utils/idle_monitor/snb_idle.c -=================================================================== ---- cpupower-3.8.orig/utils/idle_monitor/snb_idle.c -+++ cpupower-3.8/utils/idle_monitor/snb_idle.c -@@ -155,6 +155,9 @@ static struct cpuidle_monitor *snb_regis +cpupower: Haswell also supports the C-states introduced with SandyBridge + +Signed-off-by: Thomas Renninger + +diff --git a/utils/idle_monitor/snb_idle.c b/utils/idle_monitor/snb_idle.c +index a99b43b..efc8a69 100644 +--- a/utils/idle_monitor/snb_idle.c ++++ b/utils/idle_monitor/snb_idle.c +@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void) case 0x2D: /* SNB Xeon */ case 0x3A: /* IVB */ case 0x3E: /* IVB Xeon */ + case 0x3C: /* HSW */ + case 0x3F: /* HSW */ + case 0x45: /* HSW */ ++ case 0x46: /* HSW */ break; default: return NULL; diff --git a/cpupower.changes b/cpupower.changes index 6223583..068bf95 100644 --- a/cpupower.changes +++ b/cpupower.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Mon Jul 1 08:55:52 UTC 2013 - trenn@suse.de + +- Add disable C-state capability and support for latest Haswell CPUs + ------------------------------------------------------------------- Fri May 31 15:57:02 UTC 2013 - varkoly@suse.com diff --git a/cpupower.spec b/cpupower.spec index 5ebe9da..e22d9f6 100644 --- a/cpupower.spec +++ b/cpupower.spec @@ -17,6 +17,7 @@ # + Name: cpupower Url: http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html # Use this as version when things are in mainline kernel @@ -28,7 +29,11 @@ License: GPL-2.0 Group: System/Base Source: %{name}-%{version}.tar.bz2 Source1: cpupower_export_tarball_from_git.sh -Patch1: cpupower-haswell_support.patch +Patch1: cpupower_make_get_idlestate_count_unsigned.patch +Patch2: cpupower_disable_cstates.patch +Patch3: introduce_cpupower_idle_set.patch +Patch4: cpupower-haswell_support.patch +Patch5: cpupower_hsw_special.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: gettext-tools BuildRequires: pciutils @@ -74,6 +79,10 @@ powersave module. %prep %setup -q %patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 %build # This package failed when testing with -Wl,-as-needed being default. diff --git a/cpupower_disable_cstates.patch b/cpupower_disable_cstates.patch new file mode 100644 index 0000000..3ff6840 --- /dev/null +++ b/cpupower_disable_cstates.patch @@ -0,0 +1,188 @@ +cpupower: Implement disabling of cstate interface + +Latest kernel allows to disable C-states via: +/sys/devices/system/cpu/cpuX/cpuidle/stateY/disable + +This patch provides lower level sysfs access functions to make use of this +interface. +A later patch will implement the higher level stuff. + +Signed-off-by: Thomas Renninger + +diff --git a/utils/helpers/sysfs.c b/utils/helpers/sysfs.c +index 891f671..5cdc600 100644 +--- a/utils/helpers/sysfs.c ++++ b/utils/helpers/sysfs.c +@@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu) + + /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ + ++ ++/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ ++ ++/* ++ * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir ++ * exists. ++ * For example the functionality to disable c-states was introduced in later ++ * kernel versions, this function can be used to explicitly check for this ++ * feature. ++ * ++ * returns 1 if the file exists, 0 otherwise. ++ */ ++unsigned int sysfs_idlestate_file_exists(unsigned int cpu, ++ unsigned int idlestate, ++ const char *fname) ++{ ++ char path[SYSFS_PATH_MAX]; ++ struct stat statbuf; ++ ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", ++ cpu, idlestate, fname); ++ if (stat(path, &statbuf) != 0) ++ return 0; ++ return 1; ++} ++ + /* + * helper function to read file from /sys into given buffer + * 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, + return (unsigned int) numread; + } + ++/* ++ * helper function to write a new value to a /sys file ++ * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir ++ * ++ * Returns the number of bytes written or 0 on error ++ */ ++static ++unsigned int sysfs_idlestate_write_file(unsigned int cpu, ++ unsigned int idlestate, ++ const char *fname, ++ const char *value, size_t len) ++{ ++ char path[SYSFS_PATH_MAX]; ++ int fd; ++ ssize_t numwrite; ++ ++ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", ++ cpu, idlestate, fname); ++ ++ fd = open(path, O_WRONLY); ++ if (fd == -1) ++ return 0; ++ ++ numwrite = write(fd, value, len); ++ if (numwrite < 1) { ++ close(fd); ++ return 0; ++ } ++ ++ close(fd); ++ ++ return (unsigned int) numwrite; ++} ++ + /* read access to files which contain one numeric value */ + + enum idlestate_value { +@@ -128,6 +189,7 @@ enum idlestate_value { + IDLESTATE_POWER, + IDLESTATE_LATENCY, + IDLESTATE_TIME, ++ IDLESTATE_DISABLE, + MAX_IDLESTATE_VALUE_FILES + }; + +@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { + [IDLESTATE_POWER] = "power", + [IDLESTATE_LATENCY] = "latency", + [IDLESTATE_TIME] = "time", ++ [IDLESTATE_DISABLE] = "disable", + }; + + static 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, + return result; + } + ++/* ++ * Returns: ++ * 1 if disabled ++ * 0 if enabled ++ * -1 if idlestate is not available ++ * -2 if disabling is not supported by the kernel ++ */ ++int sysfs_is_idlestate_disabled(unsigned int cpu, ++ unsigned int idlestate) ++{ ++ if (sysfs_get_idlestate_count(cpu) < idlestate) ++ return -1; ++ ++ if (!sysfs_idlestate_file_exists(cpu, idlestate, ++ idlestate_value_files[IDLESTATE_DISABLE])) ++ return -2; ++ return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); ++} ++ ++/* ++ * Pass 1 as last argument to disable or 0 to enable the state ++ * Returns: ++ * 0 on success ++ * negative values on error, for example: ++ * -1 if idlestate is not available ++ * -2 if disabling is not supported by the kernel ++ * -3 No write access to disable/enable C-states ++ */ ++int sysfs_idlestate_disable(unsigned int cpu, ++ unsigned int idlestate, ++ unsigned int disable) ++{ ++ char value[SYSFS_PATH_MAX]; ++ int bytes_written; ++ ++ if (sysfs_get_idlestate_count(cpu) < idlestate) ++ return -1; ++ ++ if (!sysfs_idlestate_file_exists(cpu, idlestate, ++ idlestate_value_files[IDLESTATE_DISABLE])) ++ return -2; ++ ++ snprintf(value, SYSFS_PATH_MAX, "%u", disable); ++ ++ bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable", ++ value, sizeof(disable)); ++ if (bytes_written) ++ return 0; ++ return -3; ++} ++ + unsigned long sysfs_get_idlestate_latency(unsigned int cpu, +- unsigned int idlestate) ++ unsigned int idlestate) + { + return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); + } +diff --git a/utils/helpers/sysfs.h b/utils/helpers/sysfs.h +index 0401a97..d28f11f 100644 +--- a/utils/helpers/sysfs.h ++++ b/utils/helpers/sysfs.h +@@ -7,8 +7,16 @@ + + extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); + ++extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu, ++ unsigned int idlestate, ++ const char *fname); ++ + extern int sysfs_is_cpu_online(unsigned int cpu); + ++extern int sysfs_is_idlestate_disabled(unsigned int cpu, ++ unsigned int idlestate); ++extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate, ++ unsigned int disable); + extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, + unsigned int idlestate); + extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, diff --git a/cpupower_hsw_special.patch b/cpupower_hsw_special.patch new file mode 100644 index 0000000..c8773fa --- /dev/null +++ b/cpupower_hsw_special.patch @@ -0,0 +1,233 @@ +cpupower: Add Haswell family 0x45 specific idle monitor to show PC8,9,10 states + +This specific processor supports 3 new package sleep states. +Provide a monitor, so that the user can see their usage. + +Signed-off-by: Thomas Renninger + +diff --git a/Makefile b/Makefile +index ce17f30..cbfec92 100644 +--- a/Makefile ++++ b/Makefile +@@ -128,6 +128,7 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ + utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ + utils/helpers/pci.o utils/helpers/bitmask.o \ + utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ ++ utils/idle_monitor/hsw_ext_idle.o \ + utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ + utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ + utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ +diff --git a/utils/idle_monitor/hsw_ext_idle.c b/utils/idle_monitor/hsw_ext_idle.c +new file mode 100644 +index 0000000..ebeaba6 +--- /dev/null ++++ b/utils/idle_monitor/hsw_ext_idle.c +@@ -0,0 +1,196 @@ ++/* ++ * (C) 2010,2011 Thomas Renninger , Novell Inc. ++ * ++ * Licensed under the terms of the GNU GPL License version 2. ++ * ++ * Based on SandyBridge monitor. Implements the new package C-states ++ * (PC8, PC9, PC10) coming with a specific Haswell (family 0x45) CPU. ++ */ ++ ++#if defined(__i386__) || defined(__x86_64__) ++ ++#include ++#include ++#include ++#include ++ ++#include "helpers/helpers.h" ++#include "idle_monitor/cpupower-monitor.h" ++ ++#define MSR_PKG_C8_RESIDENCY 0x00000630 ++#define MSR_PKG_C9_RESIDENCY 0x00000631 ++#define MSR_PKG_C10_RESIDENCY 0x00000632 ++ ++#define MSR_TSC 0x10 ++ ++enum intel_hsw_ext_id { PC8 = 0, PC9, PC10, HSW_EXT_CSTATE_COUNT, ++ TSC = 0xFFFF }; ++ ++static int hsw_ext_get_count_percent(unsigned int self_id, double *percent, ++ unsigned int cpu); ++ ++static cstate_t hsw_ext_cstates[HSW_EXT_CSTATE_COUNT] = { ++ { ++ .name = "PC8", ++ .desc = N_("Processor Package C8"), ++ .id = PC8, ++ .range = RANGE_PACKAGE, ++ .get_count_percent = hsw_ext_get_count_percent, ++ }, ++ { ++ .name = "PC9", ++ .desc = N_("Processor Package C9"), ++ .desc = N_("Processor Package C2"), ++ .id = PC9, ++ .range = RANGE_PACKAGE, ++ .get_count_percent = hsw_ext_get_count_percent, ++ }, ++ { ++ .name = "PC10", ++ .desc = N_("Processor Package C10"), ++ .id = PC10, ++ .range = RANGE_PACKAGE, ++ .get_count_percent = hsw_ext_get_count_percent, ++ }, ++}; ++ ++static unsigned long long tsc_at_measure_start; ++static unsigned long long tsc_at_measure_end; ++static unsigned long long *previous_count[HSW_EXT_CSTATE_COUNT]; ++static unsigned long long *current_count[HSW_EXT_CSTATE_COUNT]; ++/* valid flag for all CPUs. If a MSR read failed it will be zero */ ++static int *is_valid; ++ ++static int hsw_ext_get_count(enum intel_hsw_ext_id id, unsigned long long *val, ++ unsigned int cpu) ++{ ++ int msr; ++ ++ switch (id) { ++ case PC8: ++ msr = MSR_PKG_C8_RESIDENCY; ++ break; ++ case PC9: ++ msr = MSR_PKG_C9_RESIDENCY; ++ break; ++ case PC10: ++ msr = MSR_PKG_C10_RESIDENCY; ++ break; ++ case TSC: ++ msr = MSR_TSC; ++ break; ++ default: ++ return -1; ++ }; ++ if (read_msr(cpu, msr, val)) ++ return -1; ++ return 0; ++} ++ ++static int hsw_ext_get_count_percent(unsigned int id, double *percent, ++ unsigned int cpu) ++{ ++ *percent = 0.0; ++ ++ if (!is_valid[cpu]) ++ return -1; ++ ++ *percent = (100.0 * ++ (current_count[id][cpu] - previous_count[id][cpu])) / ++ (tsc_at_measure_end - tsc_at_measure_start); ++ ++ dprint("%s: previous: %llu - current: %llu - (%u)\n", ++ hsw_ext_cstates[id].name, previous_count[id][cpu], ++ current_count[id][cpu], cpu); ++ ++ dprint("%s: tsc_diff: %llu - count_diff: %llu - percent: %2.f (%u)\n", ++ hsw_ext_cstates[id].name, ++ (unsigned long long) tsc_at_measure_end - tsc_at_measure_start, ++ current_count[id][cpu] - previous_count[id][cpu], ++ *percent, cpu); ++ ++ return 0; ++} ++ ++static int hsw_ext_start(void) ++{ ++ int num, cpu; ++ unsigned long long val; ++ ++ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { ++ for (cpu = 0; cpu < cpu_count; cpu++) { ++ hsw_ext_get_count(num, &val, cpu); ++ previous_count[num][cpu] = val; ++ } ++ } ++ hsw_ext_get_count(TSC, &tsc_at_measure_start, 0); ++ return 0; ++} ++ ++static int hsw_ext_stop(void) ++{ ++ unsigned long long val; ++ int num, cpu; ++ ++ hsw_ext_get_count(TSC, &tsc_at_measure_end, 0); ++ ++ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { ++ for (cpu = 0; cpu < cpu_count; cpu++) { ++ is_valid[cpu] = !hsw_ext_get_count(num, &val, cpu); ++ current_count[num][cpu] = val; ++ } ++ } ++ return 0; ++} ++ ++struct cpuidle_monitor intel_hsw_ext_monitor; ++ ++static struct cpuidle_monitor *hsw_ext_register(void) ++{ ++ int num; ++ ++ if (cpupower_cpu_info.vendor != X86_VENDOR_INTEL ++ || cpupower_cpu_info.family != 6) ++ return NULL; ++ ++ switch (cpupower_cpu_info.model) { ++ case 0x45: /* HSW */ ++ break; ++ default: ++ return NULL; ++ } ++ ++ is_valid = calloc(cpu_count, sizeof(int)); ++ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { ++ previous_count[num] = calloc(cpu_count, ++ sizeof(unsigned long long)); ++ current_count[num] = calloc(cpu_count, ++ sizeof(unsigned long long)); ++ } ++ intel_hsw_ext_monitor.name_len = strlen(intel_hsw_ext_monitor.name); ++ return &intel_hsw_ext_monitor; ++} ++ ++void hsw_ext_unregister(void) ++{ ++ int num; ++ free(is_valid); ++ for (num = 0; num < HSW_EXT_CSTATE_COUNT; num++) { ++ free(previous_count[num]); ++ free(current_count[num]); ++ } ++} ++ ++struct cpuidle_monitor intel_hsw_ext_monitor = { ++ .name = "HaswellExtended", ++ .hw_states = hsw_ext_cstates, ++ .hw_states_num = HSW_EXT_CSTATE_COUNT, ++ .start = hsw_ext_start, ++ .stop = hsw_ext_stop, ++ .do_register = hsw_ext_register, ++ .unregister = hsw_ext_unregister, ++ .needs_root = 1, ++ .overflow_s = 922000000 /* 922337203 seconds TSC overflow ++ at 20GHz */ ++}; ++#endif /* defined(__i386__) || defined(__x86_64__) */ +diff --git a/utils/idle_monitor/idle_monitors.def b/utils/idle_monitor/idle_monitors.def +index e3f8d9b..0d6ba4d 100644 +--- a/utils/idle_monitor/idle_monitors.def ++++ b/utils/idle_monitor/idle_monitors.def +@@ -2,6 +2,7 @@ + DEF(amd_fam14h) + DEF(intel_nhm) + DEF(intel_snb) ++DEF(intel_hsw_ext) + DEF(mperf) + #endif + DEF(cpuidle_sysfs) diff --git a/cpupower_make_get_idlestate_count_unsigned.patch b/cpupower_make_get_idlestate_count_unsigned.patch new file mode 100644 index 0000000..eca94ae --- /dev/null +++ b/cpupower_make_get_idlestate_count_unsigned.patch @@ -0,0 +1,79 @@ +cpupower: Make idlestate usage unsigned + +Signed-off-by: Thomas Renninger + +diff --git a/utils/cpuidle-info.c b/utils/cpuidle-info.c +index 8145af5..edd5dba 100644 +--- a/utils/cpuidle-info.c ++++ b/utils/cpuidle-info.c +@@ -22,7 +22,7 @@ + + static void cpuidle_cpu_output(unsigned int cpu, int verbose) + { +- int idlestates, idlestate; ++ unsigned int idlestates, idlestate; + char *tmp; + + printf(_ ("Analyzing CPU %d:\n"), cpu); +@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) + if (idlestates == 0) { + printf(_("CPU %u: No idle states\n"), cpu); + return; +- } else if (idlestates <= 0) { +- printf(_("CPU %u: Can't read idle state info\n"), cpu); +- return; + } ++ + printf(_("Number of idle states: %d\n"), idlestates); + printf(_("Available idle states:")); + for (idlestate = 0; idlestate < idlestates; idlestate++) { +@@ -98,21 +96,13 @@ static void cpuidle_general_output(void) + static void proc_cpuidle_cpu_output(unsigned int cpu) + { + long max_allowed_cstate = 2000000000; +- int cstates, cstate; ++ unsigned int cstate, cstates; + + cstates = sysfs_get_idlestate_count(cpu); + if (cstates == 0) { +- /* +- * Go on and print same useless info as you'd see with +- * cat /proc/acpi/processor/../power +- * printf(_("CPU %u: No C-states available\n"), cpu); +- * return; +- */ +- } else if (cstates <= 0) { +- printf(_("CPU %u: Can't read C-state info\n"), cpu); ++ printf(_("CPU %u: No C-states info\n"), cpu); + return; + } +- /* printf("Cstates: %d\n", cstates); */ + + printf(_("active state: C0\n")); + printf(_("max_cstate: C%u\n"), cstates-1); +diff --git a/utils/helpers/sysfs.c b/utils/helpers/sysfs.c +index 38ab916..891f671 100644 +--- a/utils/helpers/sysfs.c ++++ b/utils/helpers/sysfs.c +@@ -238,7 +238,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate) + * Negativ in error case + * Zero if cpuidle does not export any C-states + */ +-int sysfs_get_idlestate_count(unsigned int cpu) ++unsigned int sysfs_get_idlestate_count(unsigned int cpu) + { + char file[SYSFS_PATH_MAX]; + struct stat statbuf; +diff --git a/utils/helpers/sysfs.h b/utils/helpers/sysfs.h +index 8cb797b..0401a97 100644 +--- a/utils/helpers/sysfs.h ++++ b/utils/helpers/sysfs.h +@@ -19,7 +19,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu, + unsigned int idlestate); + extern char *sysfs_get_idlestate_desc(unsigned int cpu, + unsigned int idlestate); +-extern int sysfs_get_idlestate_count(unsigned int cpu); ++extern unsigned int sysfs_get_idlestate_count(unsigned int cpu); + + extern char *sysfs_get_cpuidle_governor(void); + extern char *sysfs_get_cpuidle_driver(void); diff --git a/introduce_cpupower_idle_set.patch b/introduce_cpupower_idle_set.patch new file mode 100644 index 0000000..eb3f6f4 --- /dev/null +++ b/introduce_cpupower_idle_set.patch @@ -0,0 +1,242 @@ +cpupower: Introduce cpupower idle-set subcommand and C-state enabling/disabling + +Example: +cpupower idle-set -d 3 +will disable C-state 3 on all processors (set commands are active on all cpus +by default), same as: +cpupower -c all idle-set -d 3 + +Signed-off-by: Thomas Renninger + +diff --git a/Makefile b/Makefile +index d875a74..ce17f30 100644 +--- a/Makefile ++++ b/Makefile +@@ -131,7 +131,8 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ + utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ + utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ + utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ +- utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o ++ utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o \ ++ utils/cpuidle-set.o + + UTIL_SRC := $(UTIL_OBJS:.o=.c) + +diff --git a/man/cpupower-monitor.1 b/man/cpupower-monitor.1 +index e01c35d..914cbb9 100644 +--- a/man/cpupower-monitor.1 ++++ b/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 + kernel frequency driver periodically cleared aperf/mperf registers in those + kernels. + +-.SS "Nehalem" "SandyBridge" ++.SS "Nehalem" "SandyBridge" "HaswellExtended" + Intel Core and Package sleep state counters. + Threads (hyperthreaded cores) may not be able to enter deeper core states if + its sibling is utilized. + Deepest package sleep states may in reality show up as machine/platform wide + sleep states and can only be entered if all cores are idle. Look up Intel + manuals (some are provided in the References section) for further details. ++The monitors are named after the CPU family where the sleep state capabilities ++got introduced and may not match exactly the CPU name of the platform. ++For example an IvyBridge processor has sleep state capabilities which got ++introduced in Nehalem and SandyBridge processor families. ++Thus on an IvyBridge processor one will get Nehalem and SandyBridge sleep ++state monitors. ++HaswellExtended extra package sleep state capabilities are available only in a ++specific Haswell (family 0x45) and probably also other future processors. + + .SS "Fam_12h" "Fam_14h" + AMD laptop and desktop processor (family 12h and 14h) sleep state counters. +diff --git a/utils/builtin.h b/utils/builtin.h +index c10496f..2284c8e 100644 +--- a/utils/builtin.h ++++ b/utils/builtin.h +@@ -5,6 +5,7 @@ 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_set(int argc, const char **argv); + extern int cmd_idle_info(int argc, const char **argv); + extern int cmd_monitor(int argc, const char **argv); + +diff --git a/utils/cpuidle-info.c b/utils/cpuidle-info.c +index edd5dba..75e66de 100644 +--- a/utils/cpuidle-info.c ++++ b/utils/cpuidle-info.c +@@ -48,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) + return; + + for (idlestate = 0; idlestate < idlestates; idlestate++) { ++ int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); ++ /* Disabled interface not supported on older kernels */ ++ if (disabled < 0) ++ disabled = 0; + tmp = sysfs_get_idlestate_name(cpu, idlestate); + if (!tmp) + continue; +- printf("%s:\n", tmp); ++ printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); + free(tmp); + + tmp = sysfs_get_idlestate_desc(cpu, idlestate); +diff --git a/utils/cpuidle-set.c b/utils/cpuidle-set.c +new file mode 100644 +index 0000000..c78141c +--- /dev/null ++++ b/utils/cpuidle-set.c +@@ -0,0 +1,118 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "cpufreq.h" ++#include "helpers/helpers.h" ++#include "helpers/sysfs.h" ++ ++static struct option info_opts[] = { ++ { .name = "disable", .has_arg = required_argument, .flag = NULL, .val = 'd'}, ++ { .name = "enable", .has_arg = required_argument, .flag = NULL, .val = 'e'}, ++ { }, ++}; ++ ++ ++int cmd_idle_set(int argc, char **argv) ++{ ++ extern char *optarg; ++ extern int optind, opterr, optopt; ++ int ret = 0, cont = 1, param = 0, idlestate = 0; ++ unsigned int cpu = 0; ++ ++ do { ++ ret = getopt_long(argc, argv, "d:e:", info_opts, NULL); ++ if (ret == -1) ++ break; ++ switch (ret) { ++ case '?': ++ param = '?'; ++ cont = 0; ++ break; ++ case 'd': ++ if (param) { ++ param = -1; ++ cont = 0; ++ break; ++ } ++ param = ret; ++ idlestate = atoi(optarg); ++ break; ++ case 'e': ++ if (param) { ++ param = -1; ++ cont = 0; ++ break; ++ } ++ param = ret; ++ idlestate = atoi(optarg); ++ break; ++ case -1: ++ cont = 0; ++ break; ++ } ++ } while (cont); ++ ++ switch (param) { ++ case -1: ++ printf(_("You can't specify more than one " ++ "output-specific argument\n")); ++ exit(EXIT_FAILURE); ++ case '?': ++ printf(_("invalid or unknown argument\n")); ++ exit(EXIT_FAILURE); ++ } ++ ++ /* Default is: set all CPUs */ ++ if (bitmask_isallclear(cpus_chosen)) ++ bitmask_setall(cpus_chosen); ++ ++ for (cpu = bitmask_first(cpus_chosen); ++ cpu <= bitmask_last(cpus_chosen); cpu++) { ++ ++ if (!bitmask_isbitset(cpus_chosen, cpu)) ++ continue; ++ ++ switch (param) { ++ ++ case 'd': ++ ret = sysfs_idlestate_disable(cpu, idlestate, 1); ++ if (ret == 0) ++ printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); ++ else if (ret == -1) ++ printf(_("Idlestate %u not available on CPU %u\n"), ++ idlestate, cpu); ++ else if (ret == -2) ++ printf(_("Idlestate disabling not supported by kernel\n")); ++ else ++ printf(_("Idlestate %u not disabled on CPU %u\n"), ++ idlestate, cpu); ++ break; ++ case 'e': ++ ret = sysfs_idlestate_disable(cpu, idlestate, 0); ++ if (ret == 0) ++ printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); ++ else if (ret == -1) ++ printf(_("Idlestate %u not available on CPU %u\n"), ++ idlestate, cpu); ++ else if (ret == -2) ++ printf(_("Idlestate enabling not supported by kernel\n")); ++ else ++ printf(_("Idlestate %u not enabled on CPU %u\n"), ++ idlestate, cpu); ++ break; ++ default: ++ /* Not reachable with proper args checking */ ++ printf(_("Invalid or unknown argument\n")); ++ exit(EXIT_FAILURE); ++ break; ++ } ++ } ++ return EXIT_SUCCESS; ++} +diff --git a/utils/cpupower.c b/utils/cpupower.c +index 52bee59..7efc570 100644 +--- a/utils/cpupower.c ++++ b/utils/cpupower.c +@@ -17,12 +17,6 @@ + #include "helpers/helpers.h" + #include "helpers/bitmask.h" + +-struct cmd_struct { +- const char *cmd; +- int (*main)(int, const char **); +- int needs_root; +-}; +- + #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) + + static int cmd_help(int argc, const char **argv); +@@ -43,10 +37,17 @@ int be_verbose; + + static void print_help(void); + ++struct cmd_struct { ++ const char *cmd; ++ int (*main)(int, const char **); ++ int needs_root; ++}; ++ + static struct cmd_struct commands[] = { + { "frequency-info", cmd_freq_info, 0 }, + { "frequency-set", cmd_freq_set, 1 }, + { "idle-info", cmd_idle_info, 0 }, ++ { "idle-set", cmd_idle_set, 1 }, + { "set", cmd_set, 1 }, + { "info", cmd_info, 0 }, + { "monitor", cmd_monitor, 0 },