mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
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: ShuoX Liu <shuox.liu@intel.com> Reviewed-by: Yanmin Zhang <yanmin_zhang@intel.com> Reviewed-and-Tested-by: Deepthi Dharwar <deepthi@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
6a6ea0acc9
commit
3a53396b03
5 changed files with 51 additions and 1 deletions
|
@ -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
|
||||||
/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
|
||||||
/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
|
||||||
/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
|
||||||
|
|
||||||
|
|
||||||
* 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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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 @@
|
||||||
#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 {
|
||||||
#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, \
|
||||||
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)
|
||||||
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);
|
||||||
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[] = {
|
||||||
&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,
|
||||||
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 {
|
||||||
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,
|
||||||
|
|
Loading…
Reference in a new issue