Commit 3a53396b authored by ShuoX Liu's avatar ShuoX Liu Committed by Len Brown

cpuidle: add a sysfs entry to disable specific C state for debug purpose.

Some C states of new CPU might be not good.  One reason is BIOS might
configure them incorrectly.  To help developers root cause it quickly, the
patch adds a new sysfs entry, so developers could disable specific C state
manually.

In addition, C state might have much impact on performance tuning, as it
takes much time to enter/exit C states, which might delay interrupt
processing.  With the new debug option, developers could check if a deep C
state could impact performance and how much impact it could cause.

Also add this option in Documentation/cpuidle/sysfs.txt.

[akpm@linux-foundation.org: check kstrtol return value]
Signed-off-by: default avatarShuoX Liu <shuox.liu@intel.com>
Reviewed-by: default avatarYanmin Zhang <yanmin_zhang@intel.com>
Reviewed-and-Tested-by: default avatarDeepthi Dharwar <deepthi@linux.vnet.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 6a6ea0ac
...@@ -36,6 +36,7 @@ drwxr-xr-x 2 root root 0 Feb 8 10:42 state3 ...@@ -36,6 +36,7 @@ drwxr-xr-x 2 root root 0 Feb 8 10:42 state3
/sys/devices/system/cpu/cpu0/cpuidle/state0: /sys/devices/system/cpu/cpu0/cpuidle/state0:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
...@@ -45,6 +46,7 @@ total 0 ...@@ -45,6 +46,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state1: /sys/devices/system/cpu/cpu0/cpuidle/state1:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
...@@ -54,6 +56,7 @@ total 0 ...@@ -54,6 +56,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state2: /sys/devices/system/cpu/cpu0/cpuidle/state2:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
...@@ -63,6 +66,7 @@ total 0 ...@@ -63,6 +66,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state3: /sys/devices/system/cpu/cpu0/cpuidle/state3:
total 0 total 0
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc -r--r--r-- 1 root root 4096 Feb 8 10:42 desc
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency -r--r--r-- 1 root root 4096 Feb 8 10:42 latency
-r--r--r-- 1 root root 4096 Feb 8 10:42 name -r--r--r-- 1 root root 4096 Feb 8 10:42 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power -r--r--r-- 1 root root 4096 Feb 8 10:42 power
...@@ -72,6 +76,7 @@ total 0 ...@@ -72,6 +76,7 @@ total 0
* desc : Small description about the idle state (string) * desc : Small description about the idle state (string)
* disable : Option to disable this idle state (bool)
* latency : Latency to exit out of this idle state (in microseconds) * latency : Latency to exit out of this idle state (in microseconds)
* name : Name of the idle state (string) * name : Name of the idle state (string)
* power : Power consumed while in this idle state (in milliwatts) * power : Power consumed while in this idle state (in milliwatts)
......
...@@ -245,6 +245,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) ...@@ -245,6 +245,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
state->power_usage = -1; state->power_usage = -1;
state->flags = 0; state->flags = 0;
state->enter = poll_idle; state->enter = poll_idle;
state->disable = 0;
} }
#else #else
static void poll_idle_init(struct cpuidle_driver *drv) {} static void poll_idle_init(struct cpuidle_driver *drv) {}
......
...@@ -280,7 +280,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) ...@@ -280,7 +280,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* We want to default to C1 (hlt), not to busy polling * We want to default to C1 (hlt), not to busy polling
* unless the timer is happening really really soon. * unless the timer is happening really really soon.
*/ */
if (data->expected_us > 5) if (data->expected_us > 5 &&
drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
data->last_state_idx = CPUIDLE_DRIVER_STATE_START; data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
/* /*
...@@ -290,6 +291,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) ...@@ -290,6 +291,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i]; struct cpuidle_state *s = &drv->states[i];
if (s->disable)
continue;
if (s->target_residency > data->predicted_us) if (s->target_residency > data->predicted_us)
continue; continue;
if (s->exit_latency > latency_req) if (s->exit_latency > latency_req)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/capability.h>
#include "cpuidle.h" #include "cpuidle.h"
...@@ -222,6 +223,9 @@ struct cpuidle_state_attr { ...@@ -222,6 +223,9 @@ struct cpuidle_state_attr {
#define define_one_state_ro(_name, show) \ #define define_one_state_ro(_name, show) \
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
#define define_one_state_rw(_name, show, store) \
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
#define define_show_state_function(_name) \ #define define_show_state_function(_name) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \ static ssize_t show_state_##_name(struct cpuidle_state *state, \
struct cpuidle_state_usage *state_usage, char *buf) \ struct cpuidle_state_usage *state_usage, char *buf) \
...@@ -229,6 +233,24 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ ...@@ -229,6 +233,24 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \
return sprintf(buf, "%u\n", state->_name);\ return sprintf(buf, "%u\n", state->_name);\
} }
#define define_store_state_function(_name) \
static ssize_t store_state_##_name(struct cpuidle_state *state, \
const char *buf, size_t size) \
{ \
long value; \
int err; \
if (!capable(CAP_SYS_ADMIN)) \
return -EPERM; \
err = kstrtol(buf, 0, &value); \
if (err) \
return err; \
if (value) \
state->disable = 1; \
else \
state->disable = 0; \
return size; \
}
#define define_show_state_ull_function(_name) \ #define define_show_state_ull_function(_name) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \ static ssize_t show_state_##_name(struct cpuidle_state *state, \
struct cpuidle_state_usage *state_usage, char *buf) \ struct cpuidle_state_usage *state_usage, char *buf) \
...@@ -251,6 +273,8 @@ define_show_state_ull_function(usage) ...@@ -251,6 +273,8 @@ define_show_state_ull_function(usage)
define_show_state_ull_function(time) define_show_state_ull_function(time)
define_show_state_str_function(name) define_show_state_str_function(name)
define_show_state_str_function(desc) define_show_state_str_function(desc)
define_show_state_function(disable)
define_store_state_function(disable)
define_one_state_ro(name, show_state_name); define_one_state_ro(name, show_state_name);
define_one_state_ro(desc, show_state_desc); define_one_state_ro(desc, show_state_desc);
...@@ -258,6 +282,7 @@ define_one_state_ro(latency, show_state_exit_latency); ...@@ -258,6 +282,7 @@ define_one_state_ro(latency, show_state_exit_latency);
define_one_state_ro(power, show_state_power_usage); define_one_state_ro(power, show_state_power_usage);
define_one_state_ro(usage, show_state_usage); define_one_state_ro(usage, show_state_usage);
define_one_state_ro(time, show_state_time); define_one_state_ro(time, show_state_time);
define_one_state_rw(disable, show_state_disable, store_state_disable);
static struct attribute *cpuidle_state_default_attrs[] = { static struct attribute *cpuidle_state_default_attrs[] = {
&attr_name.attr, &attr_name.attr,
...@@ -266,6 +291,7 @@ static struct attribute *cpuidle_state_default_attrs[] = { ...@@ -266,6 +291,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
&attr_power.attr, &attr_power.attr,
&attr_usage.attr, &attr_usage.attr,
&attr_time.attr, &attr_time.attr,
&attr_disable.attr,
NULL NULL
}; };
...@@ -287,8 +313,22 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, ...@@ -287,8 +313,22 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
return ret; return ret;
} }
static ssize_t cpuidle_state_store(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t size)
{
int ret = -EIO;
struct cpuidle_state *state = kobj_to_state(kobj);
struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
if (cattr->store)
ret = cattr->store(state, buf, size);
return ret;
}
static const struct sysfs_ops cpuidle_state_sysfs_ops = { static const struct sysfs_ops cpuidle_state_sysfs_ops = {
.show = cpuidle_state_show, .show = cpuidle_state_show,
.store = cpuidle_state_store,
}; };
static void cpuidle_state_sysfs_release(struct kobject *kobj) static void cpuidle_state_sysfs_release(struct kobject *kobj)
......
...@@ -46,6 +46,7 @@ struct cpuidle_state { ...@@ -46,6 +46,7 @@ struct cpuidle_state {
unsigned int exit_latency; /* in US */ unsigned int exit_latency; /* in US */
unsigned int power_usage; /* in mW */ unsigned int power_usage; /* in mW */
unsigned int target_residency; /* in US */ unsigned int target_residency; /* in US */
unsigned int disable;
int (*enter) (struct cpuidle_device *dev, int (*enter) (struct cpuidle_device *dev,
struct cpuidle_driver *drv, struct cpuidle_driver *drv,
......
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