diff options
author | ShuoX Liu <shuox.liu@intel.com> | 2012-03-28 18:19:11 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2012-03-30 01:52:58 -0400 |
commit | 3a53396b0381ec9d5180fd8fe7a681c8ce95fd9a (patch) | |
tree | 60a0770554c64250900ccf827ff868b483ae92fe /drivers/cpuidle | |
parent | 6a6ea0acc9375571a13aa8c4e105a0807e1c16a4 (diff) |
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>
Diffstat (limited to 'drivers/cpuidle')
-rw-r--r-- | drivers/cpuidle/cpuidle.c | 1 | ||||
-rw-r--r-- | drivers/cpuidle/governors/menu.c | 5 | ||||
-rw-r--r-- | drivers/cpuidle/sysfs.c | 40 |
3 files changed, 45 insertions, 1 deletions
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 4869b5500234..77304b6b8aef 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c | |||
@@ -245,6 +245,7 @@ static void poll_idle_init(struct cpuidle_driver *drv) | |||
245 | state->power_usage = -1; | 245 | state->power_usage = -1; |
246 | state->flags = 0; | 246 | state->flags = 0; |
247 | state->enter = poll_idle; | 247 | state->enter = poll_idle; |
248 | state->disable = 0; | ||
248 | } | 249 | } |
249 | #else | 250 | #else |
250 | static void poll_idle_init(struct cpuidle_driver *drv) {} | 251 | static void poll_idle_init(struct cpuidle_driver *drv) {} |
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index ad0952601ae2..5c17ca112fc2 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c | |||
@@ -280,7 +280,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
280 | * We want to default to C1 (hlt), not to busy polling | 280 | * We want to default to C1 (hlt), not to busy polling |
281 | * unless the timer is happening really really soon. | 281 | * unless the timer is happening really really soon. |
282 | */ | 282 | */ |
283 | if (data->expected_us > 5) | 283 | if (data->expected_us > 5 && |
284 | drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0) | ||
284 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START; | 285 | data->last_state_idx = CPUIDLE_DRIVER_STATE_START; |
285 | 286 | ||
286 | /* | 287 | /* |
@@ -290,6 +291,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) | |||
290 | for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { | 291 | for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { |
291 | struct cpuidle_state *s = &drv->states[i]; | 292 | struct cpuidle_state *s = &drv->states[i]; |
292 | 293 | ||
294 | if (s->disable) | ||
295 | continue; | ||
293 | if (s->target_residency > data->predicted_us) | 296 | if (s->target_residency > data->predicted_us) |
294 | continue; | 297 | continue; |
295 | if (s->exit_latency > latency_req) | 298 | if (s->exit_latency > latency_req) |
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 3fe41fe4851a..88032b4dc6d2 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/sysfs.h> | 11 | #include <linux/sysfs.h> |
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/cpu.h> | 13 | #include <linux/cpu.h> |
14 | #include <linux/capability.h> | ||
14 | 15 | ||
15 | #include "cpuidle.h" | 16 | #include "cpuidle.h" |
16 | 17 | ||
@@ -222,6 +223,9 @@ struct cpuidle_state_attr { | |||
222 | #define define_one_state_ro(_name, show) \ | 223 | #define define_one_state_ro(_name, show) \ |
223 | static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) | 224 | static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) |
224 | 225 | ||
226 | #define define_one_state_rw(_name, show, store) \ | ||
227 | static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store) | ||
228 | |||
225 | #define define_show_state_function(_name) \ | 229 | #define define_show_state_function(_name) \ |
226 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ | 230 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ |
227 | struct cpuidle_state_usage *state_usage, char *buf) \ | 231 | struct cpuidle_state_usage *state_usage, char *buf) \ |
@@ -229,6 +233,24 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ | |||
229 | return sprintf(buf, "%u\n", state->_name);\ | 233 | return sprintf(buf, "%u\n", state->_name);\ |
230 | } | 234 | } |
231 | 235 | ||
236 | #define define_store_state_function(_name) \ | ||
237 | static ssize_t store_state_##_name(struct cpuidle_state *state, \ | ||
238 | const char *buf, size_t size) \ | ||
239 | { \ | ||
240 | long value; \ | ||
241 | int err; \ | ||
242 | if (!capable(CAP_SYS_ADMIN)) \ | ||
243 | return -EPERM; \ | ||
244 | err = kstrtol(buf, 0, &value); \ | ||
245 | if (err) \ | ||
246 | return err; \ | ||
247 | if (value) \ | ||
248 | state->disable = 1; \ | ||
249 | else \ | ||
250 | state->disable = 0; \ | ||
251 | return size; \ | ||
252 | } | ||
253 | |||
232 | #define define_show_state_ull_function(_name) \ | 254 | #define define_show_state_ull_function(_name) \ |
233 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ | 255 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ |
234 | struct cpuidle_state_usage *state_usage, char *buf) \ | 256 | struct cpuidle_state_usage *state_usage, char *buf) \ |
@@ -251,6 +273,8 @@ define_show_state_ull_function(usage) | |||
251 | define_show_state_ull_function(time) | 273 | define_show_state_ull_function(time) |
252 | define_show_state_str_function(name) | 274 | define_show_state_str_function(name) |
253 | define_show_state_str_function(desc) | 275 | define_show_state_str_function(desc) |
276 | define_show_state_function(disable) | ||
277 | define_store_state_function(disable) | ||
254 | 278 | ||
255 | define_one_state_ro(name, show_state_name); | 279 | define_one_state_ro(name, show_state_name); |
256 | define_one_state_ro(desc, show_state_desc); | 280 | define_one_state_ro(desc, show_state_desc); |
@@ -258,6 +282,7 @@ define_one_state_ro(latency, show_state_exit_latency); | |||
258 | define_one_state_ro(power, show_state_power_usage); | 282 | define_one_state_ro(power, show_state_power_usage); |
259 | define_one_state_ro(usage, show_state_usage); | 283 | define_one_state_ro(usage, show_state_usage); |
260 | define_one_state_ro(time, show_state_time); | 284 | define_one_state_ro(time, show_state_time); |
285 | define_one_state_rw(disable, show_state_disable, store_state_disable); | ||
261 | 286 | ||
262 | static struct attribute *cpuidle_state_default_attrs[] = { | 287 | static struct attribute *cpuidle_state_default_attrs[] = { |
263 | &attr_name.attr, | 288 | &attr_name.attr, |
@@ -266,6 +291,7 @@ static struct attribute *cpuidle_state_default_attrs[] = { | |||
266 | &attr_power.attr, | 291 | &attr_power.attr, |
267 | &attr_usage.attr, | 292 | &attr_usage.attr, |
268 | &attr_time.attr, | 293 | &attr_time.attr, |
294 | &attr_disable.attr, | ||
269 | NULL | 295 | NULL |
270 | }; | 296 | }; |
271 | 297 | ||
@@ -287,8 +313,22 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, | |||
287 | return ret; | 313 | return ret; |
288 | } | 314 | } |
289 | 315 | ||
316 | static ssize_t cpuidle_state_store(struct kobject *kobj, | ||
317 | struct attribute *attr, const char *buf, size_t size) | ||
318 | { | ||
319 | int ret = -EIO; | ||
320 | struct cpuidle_state *state = kobj_to_state(kobj); | ||
321 | struct cpuidle_state_attr *cattr = attr_to_stateattr(attr); | ||
322 | |||
323 | if (cattr->store) | ||
324 | ret = cattr->store(state, buf, size); | ||
325 | |||
326 | return ret; | ||
327 | } | ||
328 | |||
290 | static const struct sysfs_ops cpuidle_state_sysfs_ops = { | 329 | static const struct sysfs_ops cpuidle_state_sysfs_ops = { |
291 | .show = cpuidle_state_show, | 330 | .show = cpuidle_state_show, |
331 | .store = cpuidle_state_store, | ||
292 | }; | 332 | }; |
293 | 333 | ||
294 | static void cpuidle_state_sysfs_release(struct kobject *kobj) | 334 | static void cpuidle_state_sysfs_release(struct kobject *kobj) |