* [cpu idle 1/3] fix cpuidle sysfs related issue
@ 2007-04-26 2:40 Shaohua Li
2007-04-29 4:42 ` Len Brown
0 siblings, 1 reply; 2+ messages in thread
From: Shaohua Li @ 2007-04-26 2:40 UTC (permalink / raw)
To: Len Brown; +Cc: linux acpi
resend the three patches per Len's request. No real change except adding
patch description and diffstat.
Fix the cpuidle sysfs issue.
a. make kobject dynamicaly allocated
b. fixed sysfs init issue to avoid suspend/resume issue
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
---
drivers/acpi/processor_idle.c | 2 -
drivers/cpuidle/cpuidle.c | 29 ++++++++++++++++-----
drivers/cpuidle/sysfs.c | 57 +++++++++++++++++++++++++++++++++---------
include/linux/cpuidle.h | 13 +++++----
4 files changed, 76 insertions(+), 25 deletions(-)
Index: 21-rc6-mm1/drivers/acpi/processor_idle.c
===================================================================
--- 21-rc6-mm1.orig/drivers/acpi/processor_idle.c 2007-04-26 10:03:49.000000000 +0800
+++ 21-rc6-mm1/drivers/acpi/processor_idle.c 2007-04-26 10:05:55.000000000 +0800
@@ -624,7 +624,7 @@ int acpi_processor_cst_has_changed(struc
return -ENODEV;
acpi_processor_get_power_info(pr);
- return cpuidle_force_redetect(&per_cpu(cpuidle_devices, pr->id));
+ return cpuidle_force_redetect(per_cpu(cpuidle_devices, pr->id));
}
/* proc interface */
Index: 21-rc6-mm1/drivers/cpuidle/cpuidle.c
===================================================================
--- 21-rc6-mm1.orig/drivers/cpuidle/cpuidle.c 2007-04-26 10:03:49.000000000 +0800
+++ 21-rc6-mm1/drivers/cpuidle/cpuidle.c 2007-04-26 10:05:55.000000000 +0800
@@ -18,7 +18,7 @@
#include "cpuidle.h"
-DEFINE_PER_CPU(struct cpuidle_device, cpuidle_devices);
+DEFINE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
EXPORT_PER_CPU_SYMBOL_GPL(cpuidle_devices);
DEFINE_MUTEX(cpuidle_lock);
@@ -34,13 +34,13 @@ static void (*pm_idle_old)(void);
*/
static void cpuidle_idle_call(void)
{
- struct cpuidle_device *dev = &__get_cpu_var(cpuidle_devices);
+ struct cpuidle_device *dev = __get_cpu_var(cpuidle_devices);
struct cpuidle_state *target_state;
int next_state;
/* check if the device is ready */
- if (dev->status != CPUIDLE_STATUS_DOIDLE) {
+ if (!dev || dev->status != CPUIDLE_STATUS_DOIDLE) {
if (pm_idle_old)
pm_idle_old();
return;
@@ -117,19 +117,32 @@ static int cpuidle_add_device(struct sys
int cpu = sys_dev->id;
struct cpuidle_device *dev;
- dev = &per_cpu(cpuidle_devices, cpu);
+ dev = per_cpu(cpuidle_devices, cpu);
- dev->cpu = cpu;
mutex_lock(&cpuidle_lock);
if (cpu_is_offline(cpu)) {
mutex_unlock(&cpuidle_lock);
return 0;
}
+ if (!dev) {
+ dev = kzalloc(sizeof(struct cpuidle_device), GFP_KERNEL);
+ if (!dev) {
+ mutex_unlock(&cpuidle_lock);
+ return -ENOMEM;
+ }
+ init_completion(&dev->kobj_unregister);
+ per_cpu(cpuidle_devices, cpu) = dev;
+ }
+ dev->cpu = cpu;
+
if (dev->status & CPUIDLE_STATUS_DETECTED) {
mutex_unlock(&cpuidle_lock);
return 0;
}
+
+ cpuidle_add_sysfs(sys_dev);
+
if (cpuidle_curr_driver) {
if (cpuidle_attach_driver(dev))
goto err_ret;
@@ -146,7 +159,6 @@ static int cpuidle_add_device(struct sys
cpuidle_install_idle_handler();
list_add(&dev->device_list, &cpuidle_detected_devices);
- cpuidle_add_sysfs(sys_dev);
dev->status |= CPUIDLE_STATUS_DETECTED;
err_ret:
@@ -165,7 +177,7 @@ static int __cpuidle_remove_device(struc
{
struct cpuidle_device *dev;
- dev = &per_cpu(cpuidle_devices, sys_dev->id);
+ dev = per_cpu(cpuidle_devices, sys_dev->id);
if (!(dev->status & CPUIDLE_STATUS_DETECTED)) {
return 0;
@@ -178,6 +190,9 @@ static int __cpuidle_remove_device(struc
cpuidle_detach_driver(dev);
cpuidle_remove_sysfs(sys_dev);
list_del(&dev->device_list);
+ wait_for_completion(&dev->kobj_unregister);
+ per_cpu(cpuidle_devices, sys_dev->id) = NULL;
+ kfree(dev);
return 0;
}
Index: 21-rc6-mm1/drivers/cpuidle/sysfs.c
===================================================================
--- 21-rc6-mm1.orig/drivers/cpuidle/sysfs.c 2007-04-26 10:03:49.000000000 +0800
+++ 21-rc6-mm1/drivers/cpuidle/sysfs.c 2007-04-26 10:05:55.000000000 +0800
@@ -210,8 +210,16 @@ static struct sysfs_ops cpuidle_sysfs_op
.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 {
@@ -246,7 +254,8 @@ static struct attribute *cpuidle_state_d
NULL
};
-#define kobj_to_state(k) container_of(k, struct cpuidle_state, kobj)
+#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 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)
@@ -265,11 +274,27 @@ static struct sysfs_ops cpuidle_state_sy
.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 void inline cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
+{
+ kobject_unregister(&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
@@ -277,24 +302,32 @@ static struct kobj_type ktype_state_cpui
int cpuidle_add_driver_sysfs(struct cpuidle_device *device)
{
int i, ret;
- struct cpuidle_state *state;
+ struct cpuidle_state_kobj *kobj;
/* state statistics */
for (i = 0; i < device->state_count; i++) {
- state = &device->states[i];
- state->kobj.parent = &device->kobj;
- state->kobj.ktype = &ktype_state_cpuidle;
- kobject_set_name(&state->kobj, "state%d", i);
- ret = kobject_register(&state->kobj);
- if (ret)
+ kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
+ if (!kobj)
+ goto error_state;
+ kobj->state = &device->states[i];
+ init_completion(&kobj->kobj_unregister);
+
+ kobj->kobj.parent = &device->kobj;
+ kobj->kobj.ktype = &ktype_state_cpuidle;
+ kobject_set_name(&kobj->kobj, "state%d", i);
+ ret = kobject_register(&kobj->kobj);
+ if (ret) {
+ kfree(kobj);
goto error_state;
+ }
+ device->kobjs[i] = kobj;
}
return 0;
error_state:
for (i = i - 1; i >= 0; i--)
- kobject_unregister(&device->states[i].kobj);
+ cpuidle_free_state_kobj(device, i);
return ret;
}
@@ -307,7 +340,7 @@ void cpuidle_remove_driver_sysfs(struct
int i;
for (i = 0; i < device->state_count; i++)
- kobject_unregister(&device->states[i].kobj);
+ cpuidle_free_state_kobj(device, i);
}
/**
@@ -319,7 +352,7 @@ int cpuidle_add_sysfs(struct sys_device
int cpu = sysdev->id;
struct cpuidle_device *dev;
- dev = &per_cpu(cpuidle_devices, cpu);
+ dev = per_cpu(cpuidle_devices, cpu);
dev->kobj.parent = &sysdev->kobj;
dev->kobj.ktype = &ktype_cpuidle;
kobject_set_name(&dev->kobj, "%s", "cpuidle");
@@ -335,6 +368,6 @@ void cpuidle_remove_sysfs(struct sys_dev
int cpu = sysdev->id;
struct cpuidle_device *dev;
- dev = &per_cpu(cpuidle_devices, cpu);
+ dev = per_cpu(cpuidle_devices, cpu);
kobject_unregister(&dev->kobj);
}
Index: 21-rc6-mm1/include/linux/cpuidle.h
===================================================================
--- 21-rc6-mm1.orig/include/linux/cpuidle.h 2007-04-26 10:03:49.000000000 +0800
+++ 21-rc6-mm1/include/linux/cpuidle.h 2007-04-26 10:05:55.000000000 +0800
@@ -41,8 +41,6 @@ struct cpuidle_state {
int (*enter) (struct cpuidle_device *dev,
struct cpuidle_state *state);
-
- struct kobject kobj;
};
/* Idle State Flags */
@@ -74,6 +72,12 @@ cpuidle_set_statedata(struct cpuidle_sta
state->driver_data = data;
}
+struct cpuidle_state_kobj {
+ struct cpuidle_state *state;
+ struct completion kobj_unregister;
+ struct kobject kobj;
+};
+
struct cpuidle_device {
unsigned int status;
int cpu;
@@ -81,6 +85,7 @@ struct cpuidle_device {
int last_residency;
int state_count;
struct cpuidle_state states[CPUIDLE_STATE_MAX];
+ struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
struct cpuidle_state *last_state;
struct list_head device_list;
@@ -89,9 +94,7 @@ struct cpuidle_device {
void *governor_data;
};
-#define to_cpuidle_device(n) container_of(n, struct cpuidle_device, kobj);
-
-DECLARE_PER_CPU(struct cpuidle_device, cpuidle_devices);
+DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
/* Device Status Flags */
#define CPUIDLE_STATUS_DETECTED (0x1)
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [cpu idle 1/3] fix cpuidle sysfs related issue
2007-04-26 2:40 [cpu idle 1/3] fix cpuidle sysfs related issue Shaohua Li
@ 2007-04-29 4:42 ` Len Brown
0 siblings, 0 replies; 2+ messages in thread
From: Len Brown @ 2007-04-29 4:42 UTC (permalink / raw)
To: Shaohua Li; +Cc: linux acpi
On Wednesday 25 April 2007 22:40, Shaohua Li wrote:
> resend the three patches per Len's request. No real change except adding
> patch description and diffstat.
Thanks, and next time when you break the text lines to fit into 80 columns,
it will be even better:-)
1,2,3 applied to acpi-test -- though I don't like the max_cstate patch,
it seemed better to stumble forward...
thanks,
-Len
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-04-29 4:42 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-26 2:40 [cpu idle 1/3] fix cpuidle sysfs related issue Shaohua Li
2007-04-29 4:42 ` Len Brown
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox