diff options
Diffstat (limited to 'drivers/cpuidle/sysfs.c')
-rw-r--r-- | drivers/cpuidle/sysfs.c | 101 |
1 files changed, 70 insertions, 31 deletions
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 428754af6236..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 | ||
@@ -33,7 +35,8 @@ static ssize_t show_available_governors(struct device *dev, | |||
33 | 35 | ||
34 | mutex_lock(&cpuidle_lock); | 36 | mutex_lock(&cpuidle_lock); |
35 | list_for_each_entry(tmp, &cpuidle_governors, governor_list) { | 37 | list_for_each_entry(tmp, &cpuidle_governors, governor_list) { |
36 | if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2)) | 38 | if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - |
39 | CPUIDLE_NAME_LEN - 2)) | ||
37 | goto out; | 40 | goto out; |
38 | i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name); | 41 | i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name); |
39 | } | 42 | } |
@@ -166,13 +169,28 @@ struct cpuidle_attr { | |||
166 | #define define_one_rw(_name, show, store) \ | 169 | #define define_one_rw(_name, show, store) \ |
167 | static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store) | 170 | static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store) |
168 | 171 | ||
169 | #define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj) | ||
170 | #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) |
171 | static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf) | 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 | |||
188 | static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr, | ||
189 | char *buf) | ||
172 | { | 190 | { |
173 | int ret = -EIO; | 191 | int ret = -EIO; |
174 | struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); | 192 | struct cpuidle_device *dev = to_cpuidle_device(kobj); |
175 | struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr); | 193 | struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); |
176 | 194 | ||
177 | if (cattr->show) { | 195 | if (cattr->show) { |
178 | mutex_lock(&cpuidle_lock); | 196 | mutex_lock(&cpuidle_lock); |
@@ -182,12 +200,12 @@ static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char | |||
182 | return ret; | 200 | return ret; |
183 | } | 201 | } |
184 | 202 | ||
185 | static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr, | 203 | static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr, |
186 | const char * buf, size_t count) | 204 | const char *buf, size_t count) |
187 | { | 205 | { |
188 | int ret = -EIO; | 206 | int ret = -EIO; |
189 | struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); | 207 | struct cpuidle_device *dev = to_cpuidle_device(kobj); |
190 | struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr); | 208 | struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr); |
191 | 209 | ||
192 | if (cattr->store) { | 210 | if (cattr->store) { |
193 | mutex_lock(&cpuidle_lock); | 211 | mutex_lock(&cpuidle_lock); |
@@ -204,9 +222,10 @@ static const struct sysfs_ops cpuidle_sysfs_ops = { | |||
204 | 222 | ||
205 | static void cpuidle_sysfs_release(struct kobject *kobj) | 223 | static void cpuidle_sysfs_release(struct kobject *kobj) |
206 | { | 224 | { |
207 | struct cpuidle_device *dev = kobj_to_cpuidledev(kobj); | 225 | struct cpuidle_device_kobj *kdev = |
226 | container_of(kobj, struct cpuidle_device_kobj, kobj); | ||
208 | 227 | ||
209 | complete(&dev->kobj_unregister); | 228 | complete(&kdev->kobj_unregister); |
210 | } | 229 | } |
211 | 230 | ||
212 | static struct kobj_type ktype_cpuidle = { | 231 | static struct kobj_type ktype_cpuidle = { |
@@ -237,8 +256,8 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, \ | |||
237 | 256 | ||
238 | #define define_store_state_ull_function(_name) \ | 257 | #define define_store_state_ull_function(_name) \ |
239 | static ssize_t store_state_##_name(struct cpuidle_state *state, \ | 258 | static ssize_t store_state_##_name(struct cpuidle_state *state, \ |
240 | struct cpuidle_state_usage *state_usage, \ | 259 | struct cpuidle_state_usage *state_usage, \ |
241 | const char *buf, size_t size) \ | 260 | const char *buf, size_t size) \ |
242 | { \ | 261 | { \ |
243 | unsigned long long value; \ | 262 | unsigned long long value; \ |
244 | int err; \ | 263 | int err; \ |
@@ -256,14 +275,16 @@ static ssize_t store_state_##_name(struct cpuidle_state *state, \ | |||
256 | 275 | ||
257 | #define define_show_state_ull_function(_name) \ | 276 | #define define_show_state_ull_function(_name) \ |
258 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ | 277 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ |
259 | struct cpuidle_state_usage *state_usage, char *buf) \ | 278 | struct cpuidle_state_usage *state_usage, \ |
279 | char *buf) \ | ||
260 | { \ | 280 | { \ |
261 | return sprintf(buf, "%llu\n", state_usage->_name);\ | 281 | return sprintf(buf, "%llu\n", state_usage->_name);\ |
262 | } | 282 | } |
263 | 283 | ||
264 | #define define_show_state_str_function(_name) \ | 284 | #define define_show_state_str_function(_name) \ |
265 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ | 285 | static ssize_t show_state_##_name(struct cpuidle_state *state, \ |
266 | struct cpuidle_state_usage *state_usage, char *buf) \ | 286 | struct cpuidle_state_usage *state_usage, \ |
287 | char *buf) \ | ||
267 | { \ | 288 | { \ |
268 | if (state->_name[0] == '\0')\ | 289 | if (state->_name[0] == '\0')\ |
269 | return sprintf(buf, "<null>\n");\ | 290 | return sprintf(buf, "<null>\n");\ |
@@ -309,8 +330,9 @@ struct cpuidle_state_kobj { | |||
309 | #define kobj_to_state(k) (kobj_to_state_obj(k)->state) | 330 | #define kobj_to_state(k) (kobj_to_state_obj(k)->state) |
310 | #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) | 331 | #define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) |
311 | #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) | 332 | #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) |
312 | static ssize_t cpuidle_state_show(struct kobject * kobj, | 333 | |
313 | struct attribute * attr ,char * buf) | 334 | static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr, |
335 | char * buf) | ||
314 | { | 336 | { |
315 | int ret = -EIO; | 337 | int ret = -EIO; |
316 | struct cpuidle_state *state = kobj_to_state(kobj); | 338 | struct cpuidle_state *state = kobj_to_state(kobj); |
@@ -323,8 +345,8 @@ static ssize_t cpuidle_state_show(struct kobject * kobj, | |||
323 | return ret; | 345 | return ret; |
324 | } | 346 | } |
325 | 347 | ||
326 | static ssize_t cpuidle_state_store(struct kobject *kobj, | 348 | static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr, |
327 | struct attribute *attr, const char *buf, size_t size) | 349 | const char *buf, size_t size) |
328 | { | 350 | { |
329 | int ret = -EIO; | 351 | int ret = -EIO; |
330 | struct cpuidle_state *state = kobj_to_state(kobj); | 352 | struct cpuidle_state *state = kobj_to_state(kobj); |
@@ -371,6 +393,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) | |||
371 | { | 393 | { |
372 | int i, ret = -ENOMEM; | 394 | int i, ret = -ENOMEM; |
373 | struct cpuidle_state_kobj *kobj; | 395 | struct cpuidle_state_kobj *kobj; |
396 | struct cpuidle_device_kobj *kdev = device->kobj_dev; | ||
374 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); | 397 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device); |
375 | 398 | ||
376 | /* state statistics */ | 399 | /* state statistics */ |
@@ -383,7 +406,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) | |||
383 | init_completion(&kobj->kobj_unregister); | 406 | init_completion(&kobj->kobj_unregister); |
384 | 407 | ||
385 | ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, | 408 | ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, |
386 | &device->kobj, "state%d", i); | 409 | &kdev->kobj, "state%d", i); |
387 | if (ret) { | 410 | if (ret) { |
388 | kfree(kobj); | 411 | kfree(kobj); |
389 | goto error_state; | 412 | goto error_state; |
@@ -449,8 +472,8 @@ static void cpuidle_driver_sysfs_release(struct kobject *kobj) | |||
449 | complete(&driver_kobj->kobj_unregister); | 472 | complete(&driver_kobj->kobj_unregister); |
450 | } | 473 | } |
451 | 474 | ||
452 | static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr, | 475 | static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr, |
453 | char * buf) | 476 | char *buf) |
454 | { | 477 | { |
455 | int ret = -EIO; | 478 | int ret = -EIO; |
456 | struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); | 479 | struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj); |
@@ -500,6 +523,7 @@ static struct kobj_type ktype_driver_cpuidle = { | |||
500 | static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) | 523 | static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) |
501 | { | 524 | { |
502 | struct cpuidle_driver_kobj *kdrv; | 525 | struct cpuidle_driver_kobj *kdrv; |
526 | struct cpuidle_device_kobj *kdev = dev->kobj_dev; | ||
503 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); | 527 | struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); |
504 | int ret; | 528 | int ret; |
505 | 529 | ||
@@ -511,7 +535,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) | |||
511 | init_completion(&kdrv->kobj_unregister); | 535 | init_completion(&kdrv->kobj_unregister); |
512 | 536 | ||
513 | ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, | 537 | ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle, |
514 | &dev->kobj, "driver"); | 538 | &kdev->kobj, "driver"); |
515 | if (ret) { | 539 | if (ret) { |
516 | kfree(kdrv); | 540 | kfree(kdrv); |
517 | return ret; | 541 | return ret; |
@@ -580,16 +604,28 @@ void cpuidle_remove_device_sysfs(struct cpuidle_device *device) | |||
580 | */ | 604 | */ |
581 | int cpuidle_add_sysfs(struct cpuidle_device *dev) | 605 | int cpuidle_add_sysfs(struct cpuidle_device *dev) |
582 | { | 606 | { |
607 | struct cpuidle_device_kobj *kdev; | ||
583 | struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); | 608 | struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu); |
584 | int error; | 609 | int error; |
585 | 610 | ||
586 | 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; | ||
587 | 616 | ||
588 | error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj, | 617 | init_completion(&kdev->kobj_unregister); |
589 | "cpuidle"); | 618 | |
590 | if (!error) | 619 | error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj, |
591 | kobject_uevent(&dev->kobj, KOBJ_ADD); | 620 | "cpuidle"); |
592 | return error; | 621 | if (error) { |
622 | kfree(kdev); | ||
623 | return error; | ||
624 | } | ||
625 | |||
626 | kobject_uevent(&kdev->kobj, KOBJ_ADD); | ||
627 | |||
628 | return 0; | ||
593 | } | 629 | } |
594 | 630 | ||
595 | /** | 631 | /** |
@@ -598,6 +634,9 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) | |||
598 | */ | 634 | */ |
599 | void cpuidle_remove_sysfs(struct cpuidle_device *dev) | 635 | void cpuidle_remove_sysfs(struct cpuidle_device *dev) |
600 | { | 636 | { |
601 | kobject_put(&dev->kobj); | 637 | struct cpuidle_device_kobj *kdev = dev->kobj_dev; |
602 | wait_for_completion(&dev->kobj_unregister); | 638 | |
639 | kobject_put(&kdev->kobj); | ||
640 | wait_for_completion(&kdev->kobj_unregister); | ||
641 | kfree(kdev); | ||
603 | } | 642 | } |