Commit 7728f036 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 8cbd0eef d8851b4b
...@@ -324,14 +324,27 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) ...@@ -324,14 +324,27 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p)
if (result) if (result)
return result; return result;
if (state == ACPI_STATE_UNKNOWN) if (state == ACPI_STATE_UNKNOWN) {
state = ACPI_STATE_D0; state = ACPI_STATE_D0;
result = acpi_device_set_power(device, state); result = acpi_device_set_power(device, state);
if (!result && state_p) if (result)
return result;
} else {
if (device->power.flags.power_resources) {
/*
* We don't need to really switch the state, bu we need
* to update the power resources' reference counters.
*/
result = acpi_power_transition(device, state);
if (result)
return result;
}
device->power.state = state;
}
if (state_p)
*state_p = state; *state_p = state;
return result; return 0;
} }
EXPORT_SYMBOL_GPL(acpi_bus_update_power); EXPORT_SYMBOL_GPL(acpi_bus_update_power);
......
...@@ -1064,10 +1064,10 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -1064,10 +1064,10 @@ find_dock_and_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
return AE_OK; return AE_OK;
} }
int __init acpi_dock_init(void) void __init acpi_dock_init(void)
{ {
if (acpi_disabled) if (acpi_disabled)
return 0; return;
/* look for dock stations and bays */ /* look for dock stations and bays */
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
...@@ -1075,11 +1075,10 @@ int __init acpi_dock_init(void) ...@@ -1075,11 +1075,10 @@ int __init acpi_dock_init(void)
if (!dock_station_count) { if (!dock_station_count) {
pr_info(PREFIX "No dock devices found.\n"); pr_info(PREFIX "No dock devices found.\n");
return 0; return;
} }
register_acpi_bus_notifier(&dock_acpi_notifier); register_acpi_bus_notifier(&dock_acpi_notifier);
pr_info(PREFIX "%s: %d docks/bays found\n", pr_info(PREFIX "%s: %d docks/bays found\n",
ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count); ACPI_DOCK_DRIVER_DESCRIPTION, dock_station_count);
return 0;
} }
...@@ -84,7 +84,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long ...@@ -84,7 +84,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
{ {
struct acpi_device *device = cdev->devdata; struct acpi_device *device = cdev->devdata;
int result; int result;
int acpi_state; int acpi_state = ACPI_STATE_D0;
if (!device) if (!device)
return -EINVAL; return -EINVAL;
......
...@@ -279,7 +279,7 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource) ...@@ -279,7 +279,7 @@ static int acpi_power_on_unlocked(struct acpi_power_resource *resource)
if (resource->ref_count++) { if (resource->ref_count++) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Power resource [%s] already on", "Power resource [%s] already on\n",
resource->name)); resource->name));
} else { } else {
result = __acpi_power_on(resource); result = __acpi_power_on(resource);
...@@ -325,7 +325,7 @@ static int acpi_power_off_unlocked(struct acpi_power_resource *resource) ...@@ -325,7 +325,7 @@ static int acpi_power_off_unlocked(struct acpi_power_resource *resource)
if (!resource->ref_count) { if (!resource->ref_count) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Power resource [%s] already off", "Power resource [%s] already off\n",
resource->name)); resource->name));
return 0; return 0;
} }
......
...@@ -35,7 +35,6 @@ bool acpi_force_hot_remove; ...@@ -35,7 +35,6 @@ bool acpi_force_hot_remove;
static const char *dummy_hid = "device"; static const char *dummy_hid = "device";
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list); static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock); static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list); static LIST_HEAD(acpi_scan_handlers_list);
......
...@@ -312,11 +312,12 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, ...@@ -312,11 +312,12 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
switch (state) { switch (state) {
case CPUFREQ_PRECHANGE: case CPUFREQ_PRECHANGE:
if (WARN(policy->transition_ongoing, if (WARN(policy->transition_ongoing ==
cpumask_weight(policy->cpus),
"In middle of another frequency transition\n")) "In middle of another frequency transition\n"))
return; return;
policy->transition_ongoing = true; policy->transition_ongoing++;
/* detect if the driver reported a value as "old frequency" /* detect if the driver reported a value as "old frequency"
* which is not equal to what the cpufreq core thinks is * which is not equal to what the cpufreq core thinks is
...@@ -341,7 +342,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, ...@@ -341,7 +342,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
"No frequency transition in progress\n")) "No frequency transition in progress\n"))
return; return;
policy->transition_ongoing = false; policy->transition_ongoing--;
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs); adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new, pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
......
...@@ -119,7 +119,7 @@ struct cpufreq_policy { ...@@ -119,7 +119,7 @@ struct cpufreq_policy {
struct kobject kobj; struct kobject kobj;
struct completion kobj_unregister; struct completion kobj_unregister;
bool transition_ongoing; /* Tracks transition status */ int transition_ongoing; /* Tracks transition status */
}; };
#define CPUFREQ_ADJUST (0) #define CPUFREQ_ADJUST (0)
......
...@@ -128,10 +128,12 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ ...@@ -128,10 +128,12 @@ 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/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \
utils/helpers/pci.o utils/helpers/bitmask.o \ utils/helpers/pci.o utils/helpers/bitmask.o \
utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.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/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \
utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.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.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) UTIL_SRC := $(UTIL_OBJS:.o=.c)
......
...@@ -110,13 +110,21 @@ May work poorly on Linux-2.6.20 through 2.6.29, as the \fBacpi-cpufreq \fP ...@@ -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 kernel frequency driver periodically cleared aperf/mperf registers in those
kernels. kernels.
.SS "Nehalem" "SandyBridge" .SS "Nehalem" "SandyBridge" "HaswellExtended"
Intel Core and Package sleep state counters. Intel Core and Package sleep state counters.
Threads (hyperthreaded cores) may not be able to enter deeper core states if Threads (hyperthreaded cores) may not be able to enter deeper core states if
its sibling is utilized. its sibling is utilized.
Deepest package sleep states may in reality show up as machine/platform wide 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 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. 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" .SS "Fam_12h" "Fam_14h"
AMD laptop and desktop processor (family 12h and 14h) sleep state counters. AMD laptop and desktop processor (family 12h and 14h) sleep state counters.
......
...@@ -5,6 +5,7 @@ extern int cmd_set(int argc, const char **argv); ...@@ -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_info(int argc, const char **argv);
extern int cmd_freq_set(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_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_idle_info(int argc, const char **argv);
extern int cmd_monitor(int argc, const char **argv); extern int cmd_monitor(int argc, const char **argv);
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
static void cpuidle_cpu_output(unsigned int cpu, int verbose) static void cpuidle_cpu_output(unsigned int cpu, int verbose)
{ {
int idlestates, idlestate; unsigned int idlestates, idlestate;
char *tmp; char *tmp;
printf(_ ("Analyzing CPU %d:\n"), cpu); printf(_ ("Analyzing CPU %d:\n"), cpu);
...@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) ...@@ -31,10 +31,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
if (idlestates == 0) { if (idlestates == 0) {
printf(_("CPU %u: No idle states\n"), cpu); printf(_("CPU %u: No idle states\n"), cpu);
return; 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(_("Number of idle states: %d\n"), idlestates);
printf(_("Available idle states:")); printf(_("Available idle states:"));
for (idlestate = 0; idlestate < idlestates; idlestate++) { for (idlestate = 0; idlestate < idlestates; idlestate++) {
...@@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) ...@@ -50,10 +48,14 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
return; return;
for (idlestate = 0; idlestate < idlestates; idlestate++) { 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); tmp = sysfs_get_idlestate_name(cpu, idlestate);
if (!tmp) if (!tmp)
continue; continue;
printf("%s:\n", tmp); printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : "");
free(tmp); free(tmp);
tmp = sysfs_get_idlestate_desc(cpu, idlestate); tmp = sysfs_get_idlestate_desc(cpu, idlestate);
...@@ -98,21 +100,13 @@ static void cpuidle_general_output(void) ...@@ -98,21 +100,13 @@ static void cpuidle_general_output(void)
static void proc_cpuidle_cpu_output(unsigned int cpu) static void proc_cpuidle_cpu_output(unsigned int cpu)
{ {
long max_allowed_cstate = 2000000000; long max_allowed_cstate = 2000000000;
int cstates, cstate; unsigned int cstate, cstates;
cstates = sysfs_get_idlestate_count(cpu); cstates = sysfs_get_idlestate_count(cpu);
if (cstates == 0) { if (cstates == 0) {
/* printf(_("CPU %u: No C-states info\n"), cpu);
* 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);
return; return;
} }
/* printf("Cstates: %d\n", cstates); */
printf(_("active state: C0\n")); printf(_("active state: C0\n"));
printf(_("max_cstate: C%u\n"), cstates-1); printf(_("max_cstate: C%u\n"), cstates-1);
......
#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"
#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;
}
...@@ -17,12 +17,6 @@ ...@@ -17,12 +17,6 @@
#include "helpers/helpers.h" #include "helpers/helpers.h"
#include "helpers/bitmask.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])) #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
static int cmd_help(int argc, const char **argv); static int cmd_help(int argc, const char **argv);
...@@ -43,10 +37,17 @@ int be_verbose; ...@@ -43,10 +37,17 @@ int be_verbose;
static void print_help(void); static void print_help(void);
struct cmd_struct {
const char *cmd;
int (*main)(int, const char **);
int needs_root;
};
static struct cmd_struct commands[] = { static struct cmd_struct commands[] = {
{ "frequency-info", cmd_freq_info, 0 }, { "frequency-info", cmd_freq_info, 0 },
{ "frequency-set", cmd_freq_set, 1 }, { "frequency-set", cmd_freq_set, 1 },
{ "idle-info", cmd_idle_info, 0 }, { "idle-info", cmd_idle_info, 0 },
{ "idle-set", cmd_idle_set, 1 },
{ "set", cmd_set, 1 }, { "set", cmd_set, 1 },
{ "info", cmd_info, 0 }, { "info", cmd_info, 0 },
{ "monitor", cmd_monitor, 0 }, { "monitor", cmd_monitor, 0 },
......
...@@ -87,8 +87,35 @@ int sysfs_is_cpu_online(unsigned int cpu) ...@@ -87,8 +87,35 @@ int sysfs_is_cpu_online(unsigned int cpu)
return value; return value;
} }
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/* 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 * helper function to read file from /sys into given buffer
* fname is a relative path under "cpuX/cpuidle/stateX/" dir * 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,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
return (unsigned int) numread; 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 */ /* read access to files which contain one numeric value */
enum idlestate_value { enum idlestate_value {
...@@ -128,6 +189,7 @@ enum idlestate_value { ...@@ -128,6 +189,7 @@ enum idlestate_value {
IDLESTATE_POWER, IDLESTATE_POWER,
IDLESTATE_LATENCY, IDLESTATE_LATENCY,
IDLESTATE_TIME, IDLESTATE_TIME,
IDLESTATE_DISABLE,
MAX_IDLESTATE_VALUE_FILES MAX_IDLESTATE_VALUE_FILES
}; };
...@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { ...@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_POWER] = "power", [IDLESTATE_POWER] = "power",
[IDLESTATE_LATENCY] = "latency", [IDLESTATE_LATENCY] = "latency",
[IDLESTATE_TIME] = "time", [IDLESTATE_TIME] = "time",
[IDLESTATE_DISABLE] = "disable",
}; };
static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
...@@ -205,6 +268,57 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu, ...@@ -205,6 +268,57 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
return result; 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 long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate) unsigned int idlestate)
{ {
...@@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate) ...@@ -238,7 +352,7 @@ char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
* Negativ in error case * Negativ in error case
* Zero if cpuidle does not export any C-states * 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]; char file[SYSFS_PATH_MAX];
struct stat statbuf; struct stat statbuf;
......
...@@ -7,8 +7,16 @@ ...@@ -7,8 +7,16 @@
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); 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_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, extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate); unsigned int idlestate);
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
...@@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu, ...@@ -19,7 +27,7 @@ extern char *sysfs_get_idlestate_name(unsigned int cpu,
unsigned int idlestate); unsigned int idlestate);
extern char *sysfs_get_idlestate_desc(unsigned int cpu, extern char *sysfs_get_idlestate_desc(unsigned int cpu,
unsigned int idlestate); 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_governor(void);
extern char *sysfs_get_cpuidle_driver(void); extern char *sysfs_get_cpuidle_driver(void);
......
/*
* (C) 2010,2011 Thomas Renninger <trenn@suse.de>, 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 <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#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__) */
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
DEF(amd_fam14h) DEF(amd_fam14h)
DEF(intel_nhm) DEF(intel_nhm)
DEF(intel_snb) DEF(intel_snb)
DEF(intel_hsw_ext)
DEF(mperf) DEF(mperf)
#endif #endif
DEF(cpuidle_sysfs) DEF(cpuidle_sysfs)
...@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void) ...@@ -155,6 +155,10 @@ static struct cpuidle_monitor *snb_register(void)
case 0x2D: /* SNB Xeon */ case 0x2D: /* SNB Xeon */
case 0x3A: /* IVB */ case 0x3A: /* IVB */
case 0x3E: /* IVB Xeon */ case 0x3E: /* IVB Xeon */
case 0x3C: /* HSW */
case 0x3F: /* HSW */
case 0x45: /* HSW */
case 0x46: /* HSW */
break; break;
default: default:
return NULL; return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment