[PATCH 1/3] cpuidle: Move cpuidle sysfs entry of each cpu to debugfs.

From: ShuoX Liu
Date: Mon Mar 12 2012 - 05:19:51 EST


On 2012å03æ09æ 02:01, Greg KH wrote:
On Wed, Mar 07, 2012 at 09:00:51AM +0800, Yanmin Zhang wrote:
On Tue, 2012-03-06 at 06:39 -0800, Greg KH wrote:
On Tue, Mar 06, 2012 at 01:51:18PM +0800, Yanmin Zhang wrote:
On Mon, 2012-03-05 at 21:22 -0800, Greg KH wrote:
On Tue, Mar 06, 2012 at 09:54:45AM +0800, Yanmin Zhang wrote:
On Mon, 2012-03-05 at 14:20 +0200, Valentin, Eduardo wrote:
Hello,


On Mon, Mar 5, 2012 at 12:18 PM, Henrique de Moraes Holschuh
<hmh@xxxxxxxxxx> wrote:
On Mon, 05 Mar 2012, ShuoX Liu wrote:
@@ -45,6 +46,7 @@ total 0
/sys/devices/system/cpu/cpu0/cpuidle/state1:
total 0
-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 name
-r--r--r-- 1 root root 4096 Feb 8 10:42 power

...

diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 3fe41fe..1eae29a 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -222,6 +222,9 @@ struct cpuidle_state_attr {
#define define_one_state_ro(_name, show) \
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) \
static ssize_t show_state_##_name(struct cpuidle_state *state, \
struct cpuidle_state_usage *state_usage, char *buf) \
@@ -229,6 +232,19 @@ static ssize_t show_state_##_name(struct
cpuidle_state *state, \
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) \
+{ \
+ int value; \
+ sscanf(buf, "%d",&value); \
+ if (value) \
+ state->disable = 1; \
+ else \
+ state->disable = 0; \
+ return size; \
+}

Isn't this missing a check for capabilities? Disabling cpuidle states is
not something random Joe (and IMHO that does mean random capability-
restricted Joe root) should be doing...

Also, maybe it would be best to use one of the lib helpers to parse that
value, so that it will be less annoying to userspace (trim blanks, complain
if there is trailing junk after trimming, etc)?

I may be jumping the thread in the middle but, if it is for debug
purposes, as states the subject, shouldn't this entry go to debugfs
instead of sysfs? I know cpuidle has all the infrastructure there to
simply add another sysfs entry, but if the intent is to create a debug
capability, then I'd say it fits under debugfs instead. Adding Greg
KH here, as I suppose he may have strong opinion on using sysfs for
debugging.
Thanks for the comments.

IMHO, all entries under cpuidle directory are for debug purpose. End users
shouldn't care about them. If we rewrite codes around all the entries, I strongly
agree that we need move them to debugfs.

I totally agree, they all need to move out of sysfs.

Here, we just add a new entry under same directory. If we create it under debugfs,
we need create the similar directory tree, which is a duplicate effort. In addition,
users might be confused that why we separate the entries under sysfs and debugfs.

They should all be moved there, that will remove any confusion :)
Greg,

Sorry. I might mislead you.

Basically, we could move all the entries of cpuidle from sysfs to debugfs. But such
moving would change KBI. There might be many scripts used by end users to parse the
data. If we change them to debugfs, the scripts wouldn't work and users would
complain.

What's your opinion about the KBI consistence?

These files all are debugging files, right? So they should be moved,
especially as the violate the "one value per file" rule of sysfs.

Do you know of any tools using these files? I have never heard of them,
and I was told we should move these files years ago. So I don't think
there should be any api issues.

But, if there are, we need to know what they are, and work to preserve
them. The only way to find out is to move them :)
We would move all cpuidle entries to debugfs firstly.
1) Create the similar directory tree on debugfs: cpu/cpuXXX, but just have cpuidle subdirectory;
2) Move our cpuidle->disable patch to debugfs;
sysfs cpuXXX has other sub directories. We don't move them this time.

The new directory under debugfs becomes:
cpu---cpu0---cpuidle
|
|
cpu1---cpuidle
|

Is it ok?

Looks fine to me.

greg k-h

I created a series to do this.

[PATCH 1/3] cpuidle: Move cpuidle sysfs entry of each cpu to debugfs.
[PATCH 2/3] cpuidle: Add a debugfs entry to disable specific C state for debug purpose.
[PATCH 3/3] cpupower: Update the cpupower tool for new debugfs entries of cpuidle.

Below are patches.
---
From: ShuoX Liu <shuox.liu@xxxxxxxxx>

This patch move cpuidle sysfs entry into debugfs. That is
/sys/devices/system/cpu/cpuXX/cpuidle will be changed to
$(debugfs_mount_dir)/cpu/cpuXX/cpuidle.

Signed-off-by: ShuoX Liu <shuox.liu@xxxxxxxxx>
Reviewed-by: Yanmin Zhang <yanmin_zhang@xxxxxxxxx>
---
Documentation/cpuidle/debugfs.txt | 63 ++++++++++
Documentation/cpuidle/sysfs.txt | 59 ---------
drivers/base/cpu.c | 14 ++
drivers/cpuidle/Makefile | 1 +
drivers/cpuidle/cpuidle.c | 23 +---
drivers/cpuidle/cpuidle.h | 29 ++++-
drivers/cpuidle/debugfs.c | 176 +++++++++++++++++++++++++++
drivers/cpuidle/sysfs.c | 239 -------------------------------------
include/linux/cpuidle.h | 10 +-
9 files changed, 292 insertions(+), 322 deletions(-)
create mode 100644 Documentation/cpuidle/debugfs.txt
create mode 100644 drivers/cpuidle/debugfs.c

diff --git a/Documentation/cpuidle/debugfs.txt b/Documentation/cpuidle/debugfs.txt
new file mode 100644
index 0000000..7724a69
--- /dev/null
+++ b/Documentation/cpuidle/debugfs.txt
@@ -0,0 +1,63 @@
+
+ Supporting multiple CPU idle levels in kernel
+
+ cpuidle debugfs
+
+Per logical CPU specific cpuidle information are under
+/sys/kernel/debug/cpu/cpuX/cpuidle
+(when your system mounted debugfs at /sys/kernel/debug)
+for each online cpu X
+
+--------------------------------------------------------------------------------
+# ls -lR /sys/kernel/debug/cpu/cpu0/cpuidle/
+/sys/kernel/debug/cpu/cpu0/cpuidle/:
+total 0
+drwxr-xr-x 2 root root 0 Feb 8 10:42 state0
+drwxr-xr-x 2 root root 0 Feb 8 10:42 state1
+drwxr-xr-x 2 root root 0 Feb 8 10:42 state2
+drwxr-xr-x 2 root root 0 Feb 8 10:42 state3
+
+/sys/kernel/debug/cpu/cpu0/cpuidle/state0:
+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 latency
+-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 time
+-r--r--r-- 1 root root 4096 Feb 8 10:42 usage
+
+/sys/kernel/debug/cpu/cpu0/cpuidle/state1:
+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 latency
+-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 time
+-r--r--r-- 1 root root 4096 Feb 8 10:42 usage
+
+/sys/kernel/debug/cpu/cpu0/cpuidle/state2:
+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 latency
+-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 time
+-r--r--r-- 1 root root 4096 Feb 8 10:42 usage
+
+/sys/kernel/debug/cpu/cpu0/cpuidle/state3:
+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 latency
+-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 time
+-r--r--r-- 1 root root 4096 Feb 8 10:42 usage
+--------------------------------------------------------------------------------
+
+
+* desc : Small description about the idle state (string)
+* latency : Latency to exit out of this idle state (in microseconds)
+* name : Name of the idle state (string)
+* power : Power consumed while in this idle state (in milliwatts)
+* time : Total time spent in this idle state (in microseconds)
+* usage : Number of times this state was entered (count)
diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt
index 50d7b16..588e40b 100644
--- a/Documentation/cpuidle/sysfs.txt
+++ b/Documentation/cpuidle/sysfs.txt
@@ -18,62 +18,3 @@ following objects are visible instead.
* current_governor
In this case users can switch the governor at run time by writing
to current_governor.
-
-
-Per logical CPU specific cpuidle information are under
-/sys/devices/system/cpu/cpuX/cpuidle
-for each online cpu X
-
---------------------------------------------------------------------------------
-# ls -lR /sys/devices/system/cpu/cpu0/cpuidle/
-/sys/devices/system/cpu/cpu0/cpuidle/:
-total 0
-drwxr-xr-x 2 root root 0 Feb 8 10:42 state0
-drwxr-xr-x 2 root root 0 Feb 8 10:42 state1
-drwxr-xr-x 2 root root 0 Feb 8 10:42 state2
-drwxr-xr-x 2 root root 0 Feb 8 10:42 state3
-
-/sys/devices/system/cpu/cpu0/cpuidle/state0:
-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 latency
--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 time
--r--r--r-- 1 root root 4096 Feb 8 10:42 usage
-
-/sys/devices/system/cpu/cpu0/cpuidle/state1:
-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 latency
--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 time
--r--r--r-- 1 root root 4096 Feb 8 10:42 usage
-
-/sys/devices/system/cpu/cpu0/cpuidle/state2:
-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 latency
--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 time
--r--r--r-- 1 root root 4096 Feb 8 10:42 usage
-
-/sys/devices/system/cpu/cpu0/cpuidle/state3:
-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 latency
--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 time
--r--r--r-- 1 root root 4096 Feb 8 10:42 usage
---------------------------------------------------------------------------------
-
-
-* desc : Small description about the idle state (string)
-* latency : Latency to exit out of this idle state (in microseconds)
-* name : Name of the idle state (string)
-* power : Power consumed while in this idle state (in milliwatts)
-* time : Total time spent in this idle state (in microseconds)
-* usage : Number of times this state was entered (count)
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 4dabf50..cc4fa6f 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -12,6 +12,7 @@
#include <linux/node.h>
#include <linux/gfp.h>
#include <linux/percpu.h>
+#include <linux/debugfs.h>

#include "base.h"

@@ -22,6 +23,9 @@ struct bus_type cpu_subsys = {
EXPORT_SYMBOL_GPL(cpu_subsys);

static DEFINE_PER_CPU(struct device *, cpu_sys_devices);
+static struct dentry *cpu_debugfs_root;
+DEFINE_PER_CPU(struct dentry *, cpu_debugfs);
+EXPORT_PER_CPU_SYMBOL_GPL(cpu_debugfs);

#ifdef CONFIG_HOTPLUG_CPU
static ssize_t show_online(struct device *dev,
@@ -71,6 +75,8 @@ void unregister_cpu(struct cpu *cpu)
{
int logical_cpu = cpu->dev.id;

+ debugfs_remove_recursive(per_cpu(cpu_debugfs, logical_cpu));
+
unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));

device_remove_file(&cpu->dev, &dev_attr_online);
@@ -238,6 +244,7 @@ static void cpu_device_release(struct device *dev)
int __cpuinit register_cpu(struct cpu *cpu, int num)
{
int error;
+ struct dentry **debugfs = &per_cpu(cpu_debugfs, num);

cpu->node_id = cpu_to_node(num);
memset(&cpu->dev, 0x00, sizeof(struct device));
@@ -251,6 +258,9 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
per_cpu(cpu_sys_devices, num) = &cpu->dev;
if (!error)
register_cpu_under_node(num, cpu_to_node(num));
+ if (!error && cpu_debugfs_root)
+ *debugfs = debugfs_create_dir(dev_name(&cpu->dev),
+ cpu_debugfs_root);

#ifdef CONFIG_KEXEC
if (!error)
@@ -323,4 +333,8 @@ void __init cpu_dev_init(void)
#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root);
#endif
+
+ cpu_debugfs_root = debugfs_create_dir("cpu", NULL);
+ if (cpu_debugfs_root == ERR_PTR(-ENODEV))
+ cpu_debugfs_root = NULL;
}
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index 5634f88..a4640ed 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -3,3 +3,4 @@
#

obj-y += cpuidle.o driver.o governor.o sysfs.o governors/
+obj-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 59f4261..b4946bc 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -228,12 +228,9 @@ int cpuidle_enable_device(struct cpuidle_device *dev)

poll_idle_init(cpuidle_get_driver());

- if ((ret = cpuidle_add_state_sysfs(dev)))
- return ret;
-
if (cpuidle_curr_governor->enable &&
(ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev)))
- goto fail_sysfs;
+ return ret;

for (i = 0; i < dev->state_count; i++) {
dev->states_usage[i].usage = 0;
@@ -243,15 +240,13 @@ int cpuidle_enable_device(struct cpuidle_device *dev)

smp_wmb();

+ cpuidle_add_state_debugfs(dev);
+
dev->enabled = 1;

enabled_devices++;
- return 0;

-fail_sysfs:
- cpuidle_remove_state_sysfs(dev);
-
- return ret;
+ return 0;
}

EXPORT_SYMBOL_GPL(cpuidle_enable_device);
@@ -275,7 +270,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
if (cpuidle_curr_governor->disable)
cpuidle_curr_governor->disable(cpuidle_get_driver(), dev);

- cpuidle_remove_state_sysfs(dev);
+ cpuidle_remove_state_debugfs(dev);
enabled_devices--;
}

@@ -290,7 +285,6 @@ EXPORT_SYMBOL_GPL(cpuidle_disable_device);
*/
static int __cpuidle_register_device(struct cpuidle_device *dev)
{
- int ret;
struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();

@@ -303,10 +297,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)

per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);
- if ((ret = cpuidle_add_sysfs(cpu_dev))) {
- module_put(cpuidle_driver->owner);
- return ret;
- }
+ cpuidle_add_debugfs(cpu_dev);

dev->registered = 1;
return 0;
@@ -354,7 +345,7 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)

cpuidle_disable_device(dev);

- cpuidle_remove_sysfs(cpu_dev);
+ cpuidle_remove_debugfs(cpu_dev);
list_del(&dev->device_list);
wait_for_completion(&dev->kobj_unregister);
per_cpu(cpuidle_devices, dev->cpu) = NULL;
diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h
index 7db1866..890545c 100644
--- a/drivers/cpuidle/cpuidle.h
+++ b/drivers/cpuidle/cpuidle.h
@@ -25,9 +25,30 @@ extern int cpuidle_switch_governor(struct cpuidle_governor *gov);
/* sysfs */
extern int cpuidle_add_interface(struct device *dev);
extern void cpuidle_remove_interface(struct device *dev);
-extern int cpuidle_add_state_sysfs(struct cpuidle_device *device);
-extern void cpuidle_remove_state_sysfs(struct cpuidle_device *device);
-extern int cpuidle_add_sysfs(struct device *dev);
-extern void cpuidle_remove_sysfs(struct device *dev);
+
+/* debugfs */
+#ifdef CONFIG_DEBUG_FS
+DECLARE_PER_CPU(struct dentry *, cpu_debugfs);
+extern int cpuidle_add_state_debugfs(struct cpuidle_device *device);
+extern void cpuidle_remove_state_debugfs(struct cpuidle_device *device);
+extern int cpuidle_add_debugfs(struct device *dev);
+extern void cpuidle_remove_debugfs(struct device *dev);
+#else
+static inline int cpuidle_add_state_debugfs(struct cpuidle_device *device)
+{
+ return 0;
+}
+static inline
+void cpuidle_remove_state_debugfs(struct cpuidle_device *device)
+{
+}
+static inline int cpuidle_add_debugfs(struct device *cpu_dev)
+{
+ return 0;
+}
+static inline void cpuidle_remove_debugfs(struct device *cpu_dev)
+{
+}
+#endif

#endif /* __DRIVER_CPUIDLE_H */
diff --git a/drivers/cpuidle/debugfs.c b/drivers/cpuidle/debugfs.c
new file mode 100644
index 0000000..67ddc44
--- /dev/null
+++ b/drivers/cpuidle/debugfs.c
@@ -0,0 +1,176 @@
+/*
+ * debugfs.c - debugfs support
+ *
+ * (C) 2006-2007 Shaohua Li <shaohua.li@xxxxxxxxx>
+ * (C) 2012 ShuoX Liu <shuox.liu@xxxxxxxxx>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpuidle.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+
+#include "cpuidle.h"
+
+static int state_open_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t state_name_read(struct file *f, char __user *buf,
+ size_t count, loff_t *off)
+{
+ struct cpuidle_state *state = f->private_data;
+ char buffer[CPUIDLE_NAME_LEN];
+ int len;
+
+ len = snprintf(buffer, sizeof(buffer), "%s\n", state->name);
+
+ return simple_read_from_buffer(buf, count, off, buffer, len);
+}
+
+static const struct file_operations state_name_fops = {
+ .open = state_open_generic,
+ .read = state_name_read,
+};
+
+static ssize_t state_desc_read(struct file *f, char __user *buf,
+ size_t count, loff_t *off)
+{
+ struct cpuidle_state *state = f->private_data;
+ char buffer[CPUIDLE_DESC_LEN];
+ int len;
+
+ len = snprintf(buffer, sizeof(buffer), "%s\n", state->desc);
+
+ return simple_read_from_buffer(buf, count, off, buffer, len);
+}
+
+static const struct file_operations state_desc_fops = {
+ .open = state_open_generic,
+ .read = state_desc_read,
+};
+
+static void debugfs_add_state_attrs(struct cpuidle_dev_state *dev_state)
+{
+ struct dentry *parent = dev_state->debugfs;
+ struct cpuidle_state *state = dev_state->state;
+ struct cpuidle_state_usage *state_usage = dev_state->state_usage;
+
+ if (!parent)
+ return;
+
+ if (!debugfs_create_file("name", S_IRUGO,
+ parent, state, &state_name_fops))
+ goto error;
+
+ if (!debugfs_create_file("desc", S_IRUGO,
+ parent, state, &state_desc_fops))
+ goto error;
+
+ if (!debugfs_create_u32("latency", S_IRUGO,
+ parent, &state->exit_latency))
+ goto error;
+
+ if (!debugfs_create_u32("power", S_IRUGO,
+ parent, &state->power_usage))
+ goto error;
+
+ if (!debugfs_create_u64("usage", S_IRUGO,
+ parent, &state_usage->usage))
+ goto error;
+
+ if (!debugfs_create_u64("time", S_IRUGO,
+ parent, &state_usage->time))
+ goto error;
+
+ return;
+error:
+ debugfs_remove_recursive(parent);
+}
+
+static inline void cpuidle_free_dev_state(struct cpuidle_device *device, int i)
+{
+ struct cpuidle_dev_state *dev_state = device->dev_states[i];
+
+ if (!dev_state)
+ return ;
+ debugfs_remove_recursive(dev_state->debugfs);
+ kfree(dev_state);
+ dev_state = NULL;
+}
+
+int cpuidle_add_state_debugfs(struct cpuidle_device *device)
+{
+ int i, ret = -ENOMEM;
+ char buf[16];
+ struct cpuidle_dev_state *dev_state;
+ struct cpuidle_driver *drv = cpuidle_get_driver();
+ struct dentry *parent = device->debugfs;
+
+ if (!parent)
+ return -ENOENT;
+ /* state statistics */
+ for (i = 0; i < device->state_count; i++) {
+ dev_state =
+ kzalloc(sizeof(struct cpuidle_dev_state), GFP_KERNEL);
+ if (!dev_state)
+ goto error;
+ dev_state->state = &drv->states[i];
+ dev_state->state_usage = &device->states_usage[i];
+
+ sprintf(buf, "state%d", i);
+ dev_state->debugfs = debugfs_create_dir(buf, parent);
+ if (!dev_state->debugfs) {
+ kfree(dev_state);
+ dev_state = NULL;
+ goto error;
+ }
+ dev_state->dev = device;
+ device->dev_states[i] = dev_state;
+ debugfs_add_state_attrs(dev_state);
+ }
+
+ return 0;
+
+error:
+ for (i = i - 1; i >= 0; i--)
+ cpuidle_free_dev_state(device, i);
+ return ret;
+}
+
+void cpuidle_remove_state_debugfs(struct cpuidle_device *device)
+{
+ int i;
+
+ for (i = 0; i < device->state_count; i++)
+ cpuidle_free_dev_state(device, i);
+}
+
+int cpuidle_add_debugfs(struct device *cpu_dev)
+{
+ int cpu = cpu_dev->id;
+ struct cpuidle_device *device;
+ struct dentry *parent = per_cpu(cpu_debugfs, cpu);
+
+ if (!parent)
+ return -ENOENT;
+ device = per_cpu(cpuidle_devices, cpu);
+ device->debugfs = debugfs_create_dir("cpuidle", parent);
+ if (!device->debugfs)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void cpuidle_remove_debugfs(struct device *cpu_dev)
+{
+ int cpu = cpu_dev->id;
+ struct cpuidle_device *dev;
+
+ dev = per_cpu(cpuidle_devices, cpu);
+ debugfs_remove_recursive(dev->debugfs);
+}
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 3fe41fe..dd597a9 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -152,242 +152,3 @@ void cpuidle_remove_interface(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &cpuidle_attr_group);
}
-
-struct cpuidle_attr {
- struct attribute attr;
- ssize_t (*show)(struct cpuidle_device *, char *);
- ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);
-};
-
-#define define_one_ro(_name, show) \
- static struct cpuidle_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
-#define define_one_rw(_name, show, store) \
- static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
-
-#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
-#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
-static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
-{
- int ret = -EIO;
- struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
- struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
-
- if (cattr->show) {
- mutex_lock(&cpuidle_lock);
- ret = cattr->show(dev, buf);
- mutex_unlock(&cpuidle_lock);
- }
- return ret;
-}
-
-static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
- const char * buf, size_t count)
-{
- int ret = -EIO;
- struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
- struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
-
- if (cattr->store) {
- mutex_lock(&cpuidle_lock);
- ret = cattr->store(dev, buf, count);
- mutex_unlock(&cpuidle_lock);
- }
- return ret;
-}
-
-static const struct sysfs_ops cpuidle_sysfs_ops = {
- .show = cpuidle_show,
- .store = cpuidle_store,
-};
-
-static void cpuidle_sysfs_release(struct kobject *kobj)
-{
- struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
-
- complete(&dev->kobj_unregister);
-}
-
-static struct kobj_type ktype_cpuidle = {
- .sysfs_ops = &cpuidle_sysfs_ops,
- .release = cpuidle_sysfs_release,
-};
-
-struct cpuidle_state_attr {
- struct attribute attr;
- ssize_t (*show)(struct cpuidle_state *, \
- struct cpuidle_state_usage *, char *);
- ssize_t (*store)(struct cpuidle_state *, const char *, size_t);
-};
-
-#define define_one_state_ro(_name, show) \
-static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
-
-#define define_show_state_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, \
- struct cpuidle_state_usage *state_usage, char *buf) \
-{ \
- return sprintf(buf, "%u\n", state->_name);\
-}
-
-#define define_show_state_ull_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, \
- struct cpuidle_state_usage *state_usage, char *buf) \
-{ \
- return sprintf(buf, "%llu\n", state_usage->_name);\
-}
-
-#define define_show_state_str_function(_name) \
-static ssize_t show_state_##_name(struct cpuidle_state *state, \
- struct cpuidle_state_usage *state_usage, char *buf) \
-{ \
- if (state->_name[0] == '\0')\
- return sprintf(buf, "<null>\n");\
- return sprintf(buf, "%s\n", state->_name);\
-}
-
-define_show_state_function(exit_latency)
-define_show_state_function(power_usage)
-define_show_state_ull_function(usage)
-define_show_state_ull_function(time)
-define_show_state_str_function(name)
-define_show_state_str_function(desc)
-
-define_one_state_ro(name, show_state_name);
-define_one_state_ro(desc, show_state_desc);
-define_one_state_ro(latency, show_state_exit_latency);
-define_one_state_ro(power, show_state_power_usage);
-define_one_state_ro(usage, show_state_usage);
-define_one_state_ro(time, show_state_time);
-
-static struct attribute *cpuidle_state_default_attrs[] = {
- &attr_name.attr,
- &attr_desc.attr,
- &attr_latency.attr,
- &attr_power.attr,
- &attr_usage.attr,
- &attr_time.attr,
- NULL
-};
-
-#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
-#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
-#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
-#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
-static ssize_t cpuidle_state_show(struct kobject * kobj,
- struct attribute * attr ,char * buf)
-{
- int ret = -EIO;
- struct cpuidle_state *state = kobj_to_state(kobj);
- struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
- struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
-
- if (cattr->show)
- ret = cattr->show(state, state_usage, buf);
-
- return ret;
-}
-
-static const struct sysfs_ops cpuidle_state_sysfs_ops = {
- .show = cpuidle_state_show,
-};
-
-static void cpuidle_state_sysfs_release(struct kobject *kobj)
-{
- struct cpuidle_state_kobj *state_obj = kobj_to_state_obj(kobj);
-
- complete(&state_obj->kobj_unregister);
-}
-
-static struct kobj_type ktype_state_cpuidle = {
- .sysfs_ops = &cpuidle_state_sysfs_ops,
- .default_attrs = cpuidle_state_default_attrs,
- .release = cpuidle_state_sysfs_release,
-};
-
-static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
-{
- kobject_put(&device->kobjs[i]->kobj);
- wait_for_completion(&device->kobjs[i]->kobj_unregister);
- kfree(device->kobjs[i]);
- device->kobjs[i] = NULL;
-}
-
-/**
- * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes
- * @device: the target device
- */
-int cpuidle_add_state_sysfs(struct cpuidle_device *device)
-{
- int i, ret = -ENOMEM;
- struct cpuidle_state_kobj *kobj;
- struct cpuidle_driver *drv = cpuidle_get_driver();
-
- /* state statistics */
- for (i = 0; i < device->state_count; i++) {
- kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
- if (!kobj)
- goto error_state;
- kobj->state = &drv->states[i];
- kobj->state_usage = &device->states_usage[i];
- init_completion(&kobj->kobj_unregister);
-
- ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
- "state%d", i);
- if (ret) {
- kfree(kobj);
- goto error_state;
- }
- kobject_uevent(&kobj->kobj, KOBJ_ADD);
- device->kobjs[i] = kobj;
- }
-
- return 0;
-
-error_state:
- for (i = i - 1; i >= 0; i--)
- cpuidle_free_state_kobj(device, i);
- return ret;
-}
-
-/**
- * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes
- * @device: the target device
- */
-void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
-{
- int i;
-
- for (i = 0; i < device->state_count; i++)
- cpuidle_free_state_kobj(device, i);
-}
-
-/**
- * cpuidle_add_sysfs - creates a sysfs instance for the target device
- * @dev: the target device
- */
-int cpuidle_add_sysfs(struct device *cpu_dev)
-{
- int cpu = cpu_dev->id;
- struct cpuidle_device *dev;
- int error;
-
- dev = per_cpu(cpuidle_devices, cpu);
- error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
- "cpuidle");
- if (!error)
- kobject_uevent(&dev->kobj, KOBJ_ADD);
- return error;
-}
-
-/**
- * cpuidle_remove_sysfs - deletes a sysfs instance on the target device
- * @dev: the target device
- */
-void cpuidle_remove_sysfs(struct device *cpu_dev)
-{
- int cpu = cpu_dev->id;
- struct cpuidle_device *dev;
-
- dev = per_cpu(cpuidle_devices, cpu);
- kobject_put(&dev->kobj);
-}
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 712abcc..f605d28 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -76,11 +76,11 @@ cpuidle_set_statedata(struct cpuidle_state_usage *st_usage, void *data)
st_usage->driver_data = data;
}

-struct cpuidle_state_kobj {
+struct cpuidle_dev_state {
struct cpuidle_state *state;
struct cpuidle_state_usage *state_usage;
- struct completion kobj_unregister;
- struct kobject kobj;
+ struct cpuidle_device *dev;
+ struct dentry *debugfs;
};

struct cpuidle_device {
@@ -91,12 +91,14 @@ struct cpuidle_device {
int last_residency;
int state_count;
struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX];
- struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
+ struct cpuidle_dev_state *dev_states[CPUIDLE_STATE_MAX];

struct list_head device_list;
struct kobject kobj;
struct completion kobj_unregister;
void *governor_data;
+
+ struct dentry *debugfs;
};

DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/