Skip to content

Commit 3a53396

Browse files
ShuoX Liulenb
ShuoX Liu
authored andcommittedMar 30, 2012
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>
1 parent 6a6ea0a commit 3a53396

File tree

5 files changed

+51
-1
lines changed

5 files changed

+51
-1
lines changed
 

‎Documentation/cpuidle/sysfs.txt

+5
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ drwxr-xr-x 2 root root 0 Feb 8 10:42 state3
3636
/sys/devices/system/cpu/cpu0/cpuidle/state0:
3737
total 0
3838
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc
39+
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
3940
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency
4041
-r--r--r-- 1 root root 4096 Feb 8 10:42 name
4142
-r--r--r-- 1 root root 4096 Feb 8 10:42 power
@@ -45,6 +46,7 @@ total 0
4546
/sys/devices/system/cpu/cpu0/cpuidle/state1:
4647
total 0
4748
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc
49+
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
4850
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency
4951
-r--r--r-- 1 root root 4096 Feb 8 10:42 name
5052
-r--r--r-- 1 root root 4096 Feb 8 10:42 power
@@ -54,6 +56,7 @@ total 0
5456
/sys/devices/system/cpu/cpu0/cpuidle/state2:
5557
total 0
5658
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc
59+
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
5760
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency
5861
-r--r--r-- 1 root root 4096 Feb 8 10:42 name
5962
-r--r--r-- 1 root root 4096 Feb 8 10:42 power
@@ -63,6 +66,7 @@ total 0
6366
/sys/devices/system/cpu/cpu0/cpuidle/state3:
6467
total 0
6568
-r--r--r-- 1 root root 4096 Feb 8 10:42 desc
69+
-rw-r--r-- 1 root root 4096 Feb 8 10:42 disable
6670
-r--r--r-- 1 root root 4096 Feb 8 10:42 latency
6771
-r--r--r-- 1 root root 4096 Feb 8 10:42 name
6872
-r--r--r-- 1 root root 4096 Feb 8 10:42 power
@@ -72,6 +76,7 @@ total 0
7276

7377

7478
* desc : Small description about the idle state (string)
79+
* disable : Option to disable this idle state (bool)
7580
* latency : Latency to exit out of this idle state (in microseconds)
7681
* name : Name of the idle state (string)
7782
* power : Power consumed while in this idle state (in milliwatts)

‎drivers/cpuidle/cpuidle.c

+1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ static void poll_idle_init(struct cpuidle_driver *drv)
245245
state->power_usage = -1;
246246
state->flags = 0;
247247
state->enter = poll_idle;
248+
state->disable = 0;
248249
}
249250
#else
250251
static void poll_idle_init(struct cpuidle_driver *drv) {}

‎drivers/cpuidle/governors/menu.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
280280
* We want to default to C1 (hlt), not to busy polling
281281
* unless the timer is happening really really soon.
282282
*/
283-
if (data->expected_us > 5)
283+
if (data->expected_us > 5 &&
284+
drv->states[CPUIDLE_DRIVER_STATE_START].disable == 0)
284285
data->last_state_idx = CPUIDLE_DRIVER_STATE_START;
285286

286287
/*
@@ -290,6 +291,8 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
290291
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
291292
struct cpuidle_state *s = &drv->states[i];
292293

294+
if (s->disable)
295+
continue;
293296
if (s->target_residency > data->predicted_us)
294297
continue;
295298
if (s->exit_latency > latency_req)

‎drivers/cpuidle/sysfs.c

+40
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/sysfs.h>
1212
#include <linux/slab.h>
1313
#include <linux/cpu.h>
14+
#include <linux/capability.h>
1415

1516
#include "cpuidle.h"
1617

@@ -222,13 +223,34 @@ struct cpuidle_state_attr {
222223
#define define_one_state_ro(_name, show) \
223224
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
224225

226+
#define define_one_state_rw(_name, show, store) \
227+
static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
228+
225229
#define define_show_state_function(_name) \
226230
static ssize_t show_state_##_name(struct cpuidle_state *state, \
227231
struct cpuidle_state_usage *state_usage, char *buf) \
228232
{ \
229233
return sprintf(buf, "%u\n", state->_name);\
230234
}
231235

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+
232254
#define define_show_state_ull_function(_name) \
233255
static ssize_t show_state_##_name(struct cpuidle_state *state, \
234256
struct cpuidle_state_usage *state_usage, char *buf) \
@@ -251,13 +273,16 @@ define_show_state_ull_function(usage)
251273
define_show_state_ull_function(time)
252274
define_show_state_str_function(name)
253275
define_show_state_str_function(desc)
276+
define_show_state_function(disable)
277+
define_store_state_function(disable)
254278

255279
define_one_state_ro(name, show_state_name);
256280
define_one_state_ro(desc, show_state_desc);
257281
define_one_state_ro(latency, show_state_exit_latency);
258282
define_one_state_ro(power, show_state_power_usage);
259283
define_one_state_ro(usage, show_state_usage);
260284
define_one_state_ro(time, show_state_time);
285+
define_one_state_rw(disable, show_state_disable, store_state_disable);
261286

262287
static struct attribute *cpuidle_state_default_attrs[] = {
263288
&attr_name.attr,
@@ -266,6 +291,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
266291
&attr_power.attr,
267292
&attr_usage.attr,
268293
&attr_time.attr,
294+
&attr_disable.attr,
269295
NULL
270296
};
271297

@@ -287,8 +313,22 @@ static ssize_t cpuidle_state_show(struct kobject * kobj,
287313
return ret;
288314
}
289315

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+
290329
static const struct sysfs_ops cpuidle_state_sysfs_ops = {
291330
.show = cpuidle_state_show,
331+
.store = cpuidle_state_store,
292332
};
293333

294334
static void cpuidle_state_sysfs_release(struct kobject *kobj)

‎include/linux/cpuidle.h

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ struct cpuidle_state {
4646
unsigned int exit_latency; /* in US */
4747
unsigned int power_usage; /* in mW */
4848
unsigned int target_residency; /* in US */
49+
unsigned int disable;
4950

5051
int (*enter) (struct cpuidle_device *dev,
5152
struct cpuidle_driver *drv,

0 commit comments

Comments
 (0)
Please sign in to comment.