aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cpuidle/sysfs.c
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2013-06-12 09:08:51 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-07-14 20:09:47 -0400
commit728ce22b696f9f1404a74d7b2279a65933553a1b (patch)
tree29b441b10a0e67d937b88f82a1b789ae194f4f20 /drivers/cpuidle/sysfs.c
parentf89ae89e2790341587f7132f0552c941342115e9 (diff)
cpuidle: Make cpuidle's sysfs directory dynamically allocated
The cpuidle sysfs code is designed to have a single instance of per CPU cpuidle directory. It is not possible to remove the sysfs entry and create it again. This is not a problem with the current code but future changes will add CPU hotplug support to enable/disable the device, so it will need to remove the sysfs entry like other subsystems do. That won't be possible without this change, because the kobj is a static object which can't be reused for kobj_init_and_add(). Add cpuidle_device_kobj to be allocated dynamically when adding/removing a sysfs entry which is consistent with the other cpuidle's sysfs entries. An added benefit is that the sysfs code is now more self-contained and the includes needed for sysfs can be moved from cpuidle.h directly into sysfs.c so as to reduce the total number of headers dragged along with cpuidle.h. [rjw: Changelog] Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpuidle/sysfs.c')
-rw-r--r--drivers/cpuidle/sysfs.c63
1 files changed, 48 insertions, 15 deletions
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 7d4448a9fbbd..8739cc05228c 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -11,8 +11,10 @@
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/completion.h>
14#include <linux/capability.h> 15#include <linux/capability.h>
15#include <linux/device.h> 16#include <linux/device.h>
17#include <linux/kobject.h>
16 18
17#include "cpuidle.h" 19#include "cpuidle.h"
18 20
@@ -167,14 +169,27 @@ struct cpuidle_attr {
167#define define_one_rw(_name, show, store) \ 169#define define_one_rw(_name, show, store) \
168 static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store) 170 static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
169 171
170#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
171#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) 172#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
172 173
174struct cpuidle_device_kobj {
175 struct cpuidle_device *dev;
176 struct completion kobj_unregister;
177 struct kobject kobj;
178};
179
180static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj)
181{
182 struct cpuidle_device_kobj *kdev =
183 container_of(kobj, struct cpuidle_device_kobj, kobj);
184
185 return kdev->dev;
186}
187
173static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, 188static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr,
174 char *buf) 189 char *buf)
175{ 190{
176 int ret = -EIO; 191 int ret = -EIO;
177 struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); 192 struct cpuidle_device *dev = to_cpuidle_device(kobj);
178 struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); 193 struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
179 194
180 if (cattr->show) { 195 if (cattr->show) {
@@ -189,7 +204,7 @@ static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr,
189 const char *buf, size_t count) 204 const char *buf, size_t count)
190{ 205{
191 int ret = -EIO; 206 int ret = -EIO;
192 struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); 207 struct cpuidle_device *dev = to_cpuidle_device(kobj);
193 struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); 208 struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);
194 209
195 if (cattr->store) { 210 if (cattr->store) {
@@ -207,9 +222,10 @@ static const struct sysfs_ops cpuidle_sysfs_ops = {
207 222
208static void cpuidle_sysfs_release(struct kobject *kobj) 223static void cpuidle_sysfs_release(struct kobject *kobj)
209{ 224{
210 struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); 225 struct cpuidle_device_kobj *kdev =
226 container_of(kobj, struct cpuidle_device_kobj, kobj);
211 227
212 complete(&dev->kobj_unregister); 228 complete(&kdev->kobj_unregister);
213} 229}
214 230
215static struct kobj_type ktype_cpuidle = { 231static struct kobj_type ktype_cpuidle = {
@@ -377,6 +393,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
377{ 393{
378 int i, ret = -ENOMEM; 394 int i, ret = -ENOMEM;
379 struct cpuidle_state_kobj *kobj; 395 struct cpuidle_state_kobj *kobj;
396 struct cpuidle_device_kobj *kdev = device->kobj_dev;
380 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); 397 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
381 398
382 /* state statistics */ 399 /* state statistics */
@@ -389,7 +406,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
389 init_completion(&kobj->kobj_unregister); 406 init_completion(&kobj->kobj_unregister);
390 407
391 ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, 408 ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
392 &device->kobj, "state%d", i); 409 &kdev->kobj, "state%d", i);
393 if (ret) { 410 if (ret) {
394 kfree(kobj); 411 kfree(kobj);
395 goto error_state; 412 goto error_state;
@@ -506,6 +523,7 @@ static struct kobj_type ktype_driver_cpuidle = {
506static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) 523static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
507{ 524{
508 struct cpuidle_driver_kobj *kdrv; 525 struct cpuidle_driver_kobj *kdrv;
526 struct cpuidle_device_kobj *kdev = dev->kobj_dev;
509 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); 527 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
510 int ret; 528 int ret;
511 529
@@ -517,7 +535,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
517 init_completion(&kdrv->kobj_unregister); 535 init_completion(&kdrv->kobj_unregister);
518 536
519 ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, 537 ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
520 &dev->kobj, "driver"); 538 &kdev->kobj, "driver");
521 if (ret) { 539 if (ret) {
522 kfree(kdrv); 540 kfree(kdrv);
523 return ret; 541 return ret;
@@ -586,16 +604,28 @@ void cpuidle_remove_device_sysfs(struct cpuidle_device *device)
586 */ 604 */
587int cpuidle_add_sysfs(struct cpuidle_device *dev) 605int cpuidle_add_sysfs(struct cpuidle_device *dev)
588{ 606{
607 struct cpuidle_device_kobj *kdev;
589 struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); 608 struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
590 int error; 609 int error;
591 610
592 init_completion(&dev->kobj_unregister); 611 kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);
612 if (!kdev)
613 return -ENOMEM;
614 kdev->dev = dev;
615 dev->kobj_dev = kdev;
616
617 init_completion(&kdev->kobj_unregister);
618
619 error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
620 "cpuidle");
621 if (error) {
622 kfree(kdev);
623 return error;
624 }
593 625
594 error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, 626 kobject_uevent(&kdev->kobj, KOBJ_ADD);
595 "cpuidle"); 627
596 if (!error) 628 return 0;
597 kobject_uevent(&dev->kobj, KOBJ_ADD);
598 return error;
599} 629}
600 630
601/** 631/**
@@ -604,6 +634,9 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev)
604 */ 634 */
605void cpuidle_remove_sysfs(struct cpuidle_device *dev) 635void cpuidle_remove_sysfs(struct cpuidle_device *dev)
606{ 636{
607 kobject_put(&dev->kobj); 637 struct cpuidle_device_kobj *kdev = dev->kobj_dev;
608 wait_for_completion(&dev->kobj_unregister); 638
639 kobject_put(&kdev->kobj);
640 wait_for_completion(&kdev->kobj_unregister);
641 kfree(kdev);
609} 642}