Commit 728ce22b696f9f1404a74d7b2279a65933553a1b
Committed by
Rafael J. Wysocki
1 parent
f89ae89e27
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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>
Showing 2 changed files with 51 additions and 19 deletions Side-by-side Diff
drivers/cpuidle/sysfs.c
... | ... | @@ -11,8 +11,10 @@ |
11 | 11 | #include <linux/sysfs.h> |
12 | 12 | #include <linux/slab.h> |
13 | 13 | #include <linux/cpu.h> |
14 | +#include <linux/completion.h> | |
14 | 15 | #include <linux/capability.h> |
15 | 16 | #include <linux/device.h> |
17 | +#include <linux/kobject.h> | |
16 | 18 | |
17 | 19 | #include "cpuidle.h" |
18 | 20 | |
19 | 21 | |
20 | 22 | |
... | ... | @@ -167,14 +169,27 @@ |
167 | 169 | #define define_one_rw(_name, show, store) \ |
168 | 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 | 172 | #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr) |
172 | 173 | |
174 | +struct cpuidle_device_kobj { | |
175 | + struct cpuidle_device *dev; | |
176 | + struct completion kobj_unregister; | |
177 | + struct kobject kobj; | |
178 | +}; | |
179 | + | |
180 | +static 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 | + | |
173 | 188 | static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, |
174 | 189 | char *buf) |
175 | 190 | { |
176 | 191 | int ret = -EIO; |
177 | - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); | |
192 | + struct cpuidle_device *dev = to_cpuidle_device(kobj); | |
178 | 193 | struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); |
179 | 194 | |
180 | 195 | if (cattr->show) { |
... | ... | @@ -189,7 +204,7 @@ |
189 | 204 | const char *buf, size_t count) |
190 | 205 | { |
191 | 206 | int ret = -EIO; |
192 | - struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); | |
207 | + struct cpuidle_device *dev = to_cpuidle_device(kobj); | |
193 | 208 | struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); |
194 | 209 | |
195 | 210 | if (cattr->store) { |
196 | 211 | |
... | ... | @@ -207,9 +222,10 @@ |
207 | 222 | |
208 | 223 | static 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 | |
215 | 231 | static struct kobj_type ktype_cpuidle = { |
... | ... | @@ -377,6 +393,7 @@ |
377 | 393 | { |
378 | 394 | int i, ret = -ENOMEM; |
379 | 395 | struct cpuidle_state_kobj *kobj; |
396 | + struct cpuidle_device_kobj *kdev = device->kobj_dev; | |
380 | 397 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); |
381 | 398 | |
382 | 399 | /* state statistics */ |
... | ... | @@ -389,7 +406,7 @@ |
389 | 406 | init_completion(&kobj->kobj_unregister); |
390 | 407 | |
391 | 408 | ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, |
392 | - &device->kobj, "state%d", i); | |
409 | + &kdev->kobj, "state%d", i); | |
393 | 410 | if (ret) { |
394 | 411 | kfree(kobj); |
395 | 412 | goto error_state; |
... | ... | @@ -506,6 +523,7 @@ |
506 | 523 | static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) |
507 | 524 | { |
508 | 525 | struct cpuidle_driver_kobj *kdrv; |
526 | + struct cpuidle_device_kobj *kdev = dev->kobj_dev; | |
509 | 527 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); |
510 | 528 | int ret; |
511 | 529 | |
... | ... | @@ -517,7 +535,7 @@ |
517 | 535 | init_completion(&kdrv->kobj_unregister); |
518 | 536 | |
519 | 537 | ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, |
520 | - &dev->kobj, "driver"); | |
538 | + &kdev->kobj, "driver"); | |
521 | 539 | if (ret) { |
522 | 540 | kfree(kdrv); |
523 | 541 | return ret; |
524 | 542 | |
525 | 543 | |
... | ... | @@ -586,16 +604,28 @@ |
586 | 604 | */ |
587 | 605 | int cpuidle_add_sysfs(struct cpuidle_device *dev) |
588 | 606 | { |
607 | + struct cpuidle_device_kobj *kdev; | |
589 | 608 | struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); |
590 | 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; | |
593 | 616 | |
594 | - error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, | |
595 | - "cpuidle"); | |
596 | - if (!error) | |
597 | - kobject_uevent(&dev->kobj, KOBJ_ADD); | |
598 | - return error; | |
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 | + } | |
625 | + | |
626 | + kobject_uevent(&kdev->kobj, KOBJ_ADD); | |
627 | + | |
628 | + return 0; | |
599 | 629 | } |
600 | 630 | |
601 | 631 | /** |
... | ... | @@ -604,7 +634,10 @@ |
604 | 634 | */ |
605 | 635 | void cpuidle_remove_sysfs(struct cpuidle_device *dev) |
606 | 636 | { |
607 | - kobject_put(&dev->kobj); | |
608 | - wait_for_completion(&dev->kobj_unregister); | |
637 | + struct cpuidle_device_kobj *kdev = dev->kobj_dev; | |
638 | + | |
639 | + kobject_put(&kdev->kobj); | |
640 | + wait_for_completion(&kdev->kobj_unregister); | |
641 | + kfree(kdev); | |
609 | 642 | } |
include/linux/cpuidle.h
... | ... | @@ -13,8 +13,6 @@ |
13 | 13 | |
14 | 14 | #include <linux/percpu.h> |
15 | 15 | #include <linux/list.h> |
16 | -#include <linux/kobject.h> | |
17 | -#include <linux/completion.h> | |
18 | 16 | #include <linux/hrtimer.h> |
19 | 17 | |
20 | 18 | #define CPUIDLE_STATE_MAX 10 |
... | ... | @@ -61,6 +59,8 @@ |
61 | 59 | |
62 | 60 | #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) |
63 | 61 | |
62 | +struct cpuidle_device_kobj; | |
63 | + | |
64 | 64 | struct cpuidle_device { |
65 | 65 | unsigned int registered:1; |
66 | 66 | unsigned int enabled:1; |
67 | 67 | |
... | ... | @@ -71,9 +71,8 @@ |
71 | 71 | struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; |
72 | 72 | struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; |
73 | 73 | struct cpuidle_driver_kobj *kobj_driver; |
74 | + struct cpuidle_device_kobj *kobj_dev; | |
74 | 75 | struct list_head device_list; |
75 | - struct kobject kobj; | |
76 | - struct completion kobj_unregister; | |
77 | 76 | |
78 | 77 | #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED |
79 | 78 | int safe_state_index; |