748 lines · c
1/*2 * sysfs.c - sysfs support3 *4 * (C) 2006-2007 Shaohua Li <shaohua.li@intel.com>5 *6 * This code is licenced under the GPL.7 */8 9#include <linux/kernel.h>10#include <linux/cpuidle.h>11#include <linux/sysfs.h>12#include <linux/slab.h>13#include <linux/cpu.h>14#include <linux/completion.h>15#include <linux/capability.h>16#include <linux/device.h>17#include <linux/kobject.h>18 19#include "cpuidle.h"20 21static ssize_t show_available_governors(struct device *dev,22 struct device_attribute *attr,23 char *buf)24{25 ssize_t i = 0;26 struct cpuidle_governor *tmp;27 28 mutex_lock(&cpuidle_lock);29 list_for_each_entry(tmp, &cpuidle_governors, governor_list) {30 if (i >= (ssize_t) (PAGE_SIZE - (CPUIDLE_NAME_LEN + 2)))31 goto out;32 33 i += scnprintf(&buf[i], CPUIDLE_NAME_LEN + 1, "%s ", tmp->name);34 }35 36out:37 i+= sprintf(&buf[i], "\n");38 mutex_unlock(&cpuidle_lock);39 return i;40}41 42static ssize_t show_current_driver(struct device *dev,43 struct device_attribute *attr,44 char *buf)45{46 ssize_t ret;47 struct cpuidle_driver *drv;48 49 spin_lock(&cpuidle_driver_lock);50 drv = cpuidle_get_driver();51 if (drv)52 ret = sprintf(buf, "%s\n", drv->name);53 else54 ret = sprintf(buf, "none\n");55 spin_unlock(&cpuidle_driver_lock);56 57 return ret;58}59 60static ssize_t show_current_governor(struct device *dev,61 struct device_attribute *attr,62 char *buf)63{64 ssize_t ret;65 66 mutex_lock(&cpuidle_lock);67 if (cpuidle_curr_governor)68 ret = sprintf(buf, "%s\n", cpuidle_curr_governor->name);69 else70 ret = sprintf(buf, "none\n");71 mutex_unlock(&cpuidle_lock);72 73 return ret;74}75 76static ssize_t store_current_governor(struct device *dev,77 struct device_attribute *attr,78 const char *buf, size_t count)79{80 char gov_name[CPUIDLE_NAME_LEN + 1];81 int ret;82 struct cpuidle_governor *gov;83 84 ret = sscanf(buf, "%" __stringify(CPUIDLE_NAME_LEN) "s", gov_name);85 if (ret != 1)86 return -EINVAL;87 88 mutex_lock(&cpuidle_lock);89 ret = -EINVAL;90 list_for_each_entry(gov, &cpuidle_governors, governor_list) {91 if (!strncmp(gov->name, gov_name, CPUIDLE_NAME_LEN)) {92 ret = cpuidle_switch_governor(gov);93 break;94 }95 }96 mutex_unlock(&cpuidle_lock);97 98 return ret ? ret : count;99}100 101static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL);102static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL);103static DEVICE_ATTR(current_governor, 0644, show_current_governor,104 store_current_governor);105static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL);106 107static struct attribute *cpuidle_attrs[] = {108 &dev_attr_available_governors.attr,109 &dev_attr_current_driver.attr,110 &dev_attr_current_governor.attr,111 &dev_attr_current_governor_ro.attr,112 NULL113};114 115static struct attribute_group cpuidle_attr_group = {116 .attrs = cpuidle_attrs,117 .name = "cpuidle",118};119 120/**121 * cpuidle_add_interface - add CPU global sysfs attributes122 */123int cpuidle_add_interface(void)124{125 struct device *dev_root = bus_get_dev_root(&cpu_subsys);126 int retval;127 128 if (!dev_root)129 return -EINVAL;130 131 retval = sysfs_create_group(&dev_root->kobj, &cpuidle_attr_group);132 put_device(dev_root);133 return retval;134}135 136/**137 * cpuidle_remove_interface - remove CPU global sysfs attributes138 * @dev: the target device139 */140void cpuidle_remove_interface(struct device *dev)141{142 sysfs_remove_group(&dev->kobj, &cpuidle_attr_group);143}144 145struct cpuidle_attr {146 struct attribute attr;147 ssize_t (*show)(struct cpuidle_device *, char *);148 ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);149};150 151#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)152 153struct cpuidle_device_kobj {154 struct cpuidle_device *dev;155 struct completion kobj_unregister;156 struct kobject kobj;157};158 159static inline struct cpuidle_device *to_cpuidle_device(struct kobject *kobj)160{161 struct cpuidle_device_kobj *kdev =162 container_of(kobj, struct cpuidle_device_kobj, kobj);163 164 return kdev->dev;165}166 167static ssize_t cpuidle_show(struct kobject *kobj, struct attribute *attr,168 char *buf)169{170 int ret = -EIO;171 struct cpuidle_device *dev = to_cpuidle_device(kobj);172 struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);173 174 if (cattr->show) {175 mutex_lock(&cpuidle_lock);176 ret = cattr->show(dev, buf);177 mutex_unlock(&cpuidle_lock);178 }179 return ret;180}181 182static ssize_t cpuidle_store(struct kobject *kobj, struct attribute *attr,183 const char *buf, size_t count)184{185 int ret = -EIO;186 struct cpuidle_device *dev = to_cpuidle_device(kobj);187 struct cpuidle_attr *cattr = attr_to_cpuidleattr(attr);188 189 if (cattr->store) {190 mutex_lock(&cpuidle_lock);191 ret = cattr->store(dev, buf, count);192 mutex_unlock(&cpuidle_lock);193 }194 return ret;195}196 197static const struct sysfs_ops cpuidle_sysfs_ops = {198 .show = cpuidle_show,199 .store = cpuidle_store,200};201 202static void cpuidle_sysfs_release(struct kobject *kobj)203{204 struct cpuidle_device_kobj *kdev =205 container_of(kobj, struct cpuidle_device_kobj, kobj);206 207 complete(&kdev->kobj_unregister);208}209 210static const struct kobj_type ktype_cpuidle = {211 .sysfs_ops = &cpuidle_sysfs_ops,212 .release = cpuidle_sysfs_release,213};214 215struct cpuidle_state_attr {216 struct attribute attr;217 ssize_t (*show)(struct cpuidle_state *, \218 struct cpuidle_state_usage *, char *);219 ssize_t (*store)(struct cpuidle_state *, \220 struct cpuidle_state_usage *, const char *, size_t);221};222 223#define define_one_state_ro(_name, show) \224static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)225 226#define define_one_state_rw(_name, show, store) \227static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)228 229#define define_show_state_function(_name) \230static ssize_t show_state_##_name(struct cpuidle_state *state, \231 struct cpuidle_state_usage *state_usage, char *buf) \232{ \233 return sprintf(buf, "%u\n", state->_name);\234}235 236#define define_show_state_ull_function(_name) \237static ssize_t show_state_##_name(struct cpuidle_state *state, \238 struct cpuidle_state_usage *state_usage, \239 char *buf) \240{ \241 return sprintf(buf, "%llu\n", state_usage->_name);\242}243 244#define define_show_state_str_function(_name) \245static ssize_t show_state_##_name(struct cpuidle_state *state, \246 struct cpuidle_state_usage *state_usage, \247 char *buf) \248{ \249 if (state->_name[0] == '\0')\250 return sprintf(buf, "<null>\n");\251 return sprintf(buf, "%s\n", state->_name);\252}253 254#define define_show_state_time_function(_name) \255static ssize_t show_state_##_name(struct cpuidle_state *state, \256 struct cpuidle_state_usage *state_usage, \257 char *buf) \258{ \259 return sprintf(buf, "%llu\n", ktime_to_us(state->_name##_ns)); \260}261 262define_show_state_time_function(exit_latency)263define_show_state_time_function(target_residency)264define_show_state_function(power_usage)265define_show_state_ull_function(usage)266define_show_state_ull_function(rejected)267define_show_state_str_function(name)268define_show_state_str_function(desc)269define_show_state_ull_function(above)270define_show_state_ull_function(below)271 272static ssize_t show_state_time(struct cpuidle_state *state,273 struct cpuidle_state_usage *state_usage,274 char *buf)275{276 return sprintf(buf, "%llu\n", ktime_to_us(state_usage->time_ns));277}278 279static ssize_t show_state_disable(struct cpuidle_state *state,280 struct cpuidle_state_usage *state_usage,281 char *buf)282{283 return sprintf(buf, "%llu\n",284 state_usage->disable & CPUIDLE_STATE_DISABLED_BY_USER);285}286 287static ssize_t store_state_disable(struct cpuidle_state *state,288 struct cpuidle_state_usage *state_usage,289 const char *buf, size_t size)290{291 unsigned int value;292 int err;293 294 if (!capable(CAP_SYS_ADMIN))295 return -EPERM;296 297 err = kstrtouint(buf, 0, &value);298 if (err)299 return err;300 301 if (value)302 state_usage->disable |= CPUIDLE_STATE_DISABLED_BY_USER;303 else304 state_usage->disable &= ~CPUIDLE_STATE_DISABLED_BY_USER;305 306 return size;307}308 309static ssize_t show_state_default_status(struct cpuidle_state *state,310 struct cpuidle_state_usage *state_usage,311 char *buf)312{313 return sprintf(buf, "%s\n",314 state->flags & CPUIDLE_FLAG_OFF ? "disabled" : "enabled");315}316 317define_one_state_ro(name, show_state_name);318define_one_state_ro(desc, show_state_desc);319define_one_state_ro(latency, show_state_exit_latency);320define_one_state_ro(residency, show_state_target_residency);321define_one_state_ro(power, show_state_power_usage);322define_one_state_ro(usage, show_state_usage);323define_one_state_ro(rejected, show_state_rejected);324define_one_state_ro(time, show_state_time);325define_one_state_rw(disable, show_state_disable, store_state_disable);326define_one_state_ro(above, show_state_above);327define_one_state_ro(below, show_state_below);328define_one_state_ro(default_status, show_state_default_status);329 330static struct attribute *cpuidle_state_default_attrs[] = {331 &attr_name.attr,332 &attr_desc.attr,333 &attr_latency.attr,334 &attr_residency.attr,335 &attr_power.attr,336 &attr_usage.attr,337 &attr_rejected.attr,338 &attr_time.attr,339 &attr_disable.attr,340 &attr_above.attr,341 &attr_below.attr,342 &attr_default_status.attr,343 NULL344};345ATTRIBUTE_GROUPS(cpuidle_state_default);346 347struct cpuidle_state_kobj {348 struct cpuidle_state *state;349 struct cpuidle_state_usage *state_usage;350 struct completion kobj_unregister;351 struct kobject kobj;352 struct cpuidle_device *device;353};354 355#ifdef CONFIG_SUSPEND356#define define_show_state_s2idle_ull_function(_name) \357static ssize_t show_state_s2idle_##_name(struct cpuidle_state *state, \358 struct cpuidle_state_usage *state_usage, \359 char *buf) \360{ \361 return sprintf(buf, "%llu\n", state_usage->s2idle_##_name);\362}363 364define_show_state_s2idle_ull_function(usage);365define_show_state_s2idle_ull_function(time);366 367#define define_one_state_s2idle_ro(_name, show) \368static struct cpuidle_state_attr attr_s2idle_##_name = \369 __ATTR(_name, 0444, show, NULL)370 371define_one_state_s2idle_ro(usage, show_state_s2idle_usage);372define_one_state_s2idle_ro(time, show_state_s2idle_time);373 374static struct attribute *cpuidle_state_s2idle_attrs[] = {375 &attr_s2idle_usage.attr,376 &attr_s2idle_time.attr,377 NULL378};379 380static const struct attribute_group cpuidle_state_s2idle_group = {381 .name = "s2idle",382 .attrs = cpuidle_state_s2idle_attrs,383};384 385static void cpuidle_add_s2idle_attr_group(struct cpuidle_state_kobj *kobj)386{387 int ret;388 389 if (!kobj->state->enter_s2idle)390 return;391 392 ret = sysfs_create_group(&kobj->kobj, &cpuidle_state_s2idle_group);393 if (ret)394 pr_debug("%s: sysfs attribute group not created\n", __func__);395}396 397static void cpuidle_remove_s2idle_attr_group(struct cpuidle_state_kobj *kobj)398{399 if (kobj->state->enter_s2idle)400 sysfs_remove_group(&kobj->kobj, &cpuidle_state_s2idle_group);401}402#else403static inline void cpuidle_add_s2idle_attr_group(struct cpuidle_state_kobj *kobj) { }404static inline void cpuidle_remove_s2idle_attr_group(struct cpuidle_state_kobj *kobj) { }405#endif /* CONFIG_SUSPEND */406 407#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)408#define kobj_to_state(k) (kobj_to_state_obj(k)->state)409#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)410#define kobj_to_device(k) (kobj_to_state_obj(k)->device)411#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)412 413static ssize_t cpuidle_state_show(struct kobject *kobj, struct attribute *attr,414 char *buf)415{416 int ret = -EIO;417 struct cpuidle_state *state = kobj_to_state(kobj);418 struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);419 struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);420 421 if (cattr->show)422 ret = cattr->show(state, state_usage, buf);423 424 return ret;425}426 427static ssize_t cpuidle_state_store(struct kobject *kobj, struct attribute *attr,428 const char *buf, size_t size)429{430 int ret = -EIO;431 struct cpuidle_state *state = kobj_to_state(kobj);432 struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);433 struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);434 struct cpuidle_device *dev = kobj_to_device(kobj);435 436 if (cattr->store)437 ret = cattr->store(state, state_usage, buf, size);438 439 /* reset poll time cache */440 dev->poll_limit_ns = 0;441 442 return ret;443}444 445static const struct sysfs_ops cpuidle_state_sysfs_ops = {446 .show = cpuidle_state_show,447 .store = cpuidle_state_store,448};449 450static void cpuidle_state_sysfs_release(struct kobject *kobj)451{452 struct cpuidle_state_kobj *state_obj = kobj_to_state_obj(kobj);453 454 complete(&state_obj->kobj_unregister);455}456 457static const struct kobj_type ktype_state_cpuidle = {458 .sysfs_ops = &cpuidle_state_sysfs_ops,459 .default_groups = cpuidle_state_default_groups,460 .release = cpuidle_state_sysfs_release,461};462 463static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)464{465 cpuidle_remove_s2idle_attr_group(device->kobjs[i]);466 kobject_put(&device->kobjs[i]->kobj);467 wait_for_completion(&device->kobjs[i]->kobj_unregister);468 kfree(device->kobjs[i]);469 device->kobjs[i] = NULL;470}471 472/**473 * cpuidle_add_state_sysfs - adds cpuidle states sysfs attributes474 * @device: the target device475 */476static int cpuidle_add_state_sysfs(struct cpuidle_device *device)477{478 int i, ret = -ENOMEM;479 struct cpuidle_state_kobj *kobj;480 struct cpuidle_device_kobj *kdev = device->kobj_dev;481 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);482 483 /* state statistics */484 for (i = 0; i < drv->state_count; i++) {485 kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);486 if (!kobj) {487 ret = -ENOMEM;488 goto error_state;489 }490 kobj->state = &drv->states[i];491 kobj->state_usage = &device->states_usage[i];492 kobj->device = device;493 init_completion(&kobj->kobj_unregister);494 495 ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,496 &kdev->kobj, "state%d", i);497 if (ret) {498 kobject_put(&kobj->kobj);499 kfree(kobj);500 goto error_state;501 }502 cpuidle_add_s2idle_attr_group(kobj);503 kobject_uevent(&kobj->kobj, KOBJ_ADD);504 device->kobjs[i] = kobj;505 }506 507 return 0;508 509error_state:510 for (i = i - 1; i >= 0; i--)511 cpuidle_free_state_kobj(device, i);512 return ret;513}514 515/**516 * cpuidle_remove_state_sysfs - removes the cpuidle states sysfs attributes517 * @device: the target device518 */519static void cpuidle_remove_state_sysfs(struct cpuidle_device *device)520{521 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);522 int i;523 524 for (i = 0; i < drv->state_count; i++)525 cpuidle_free_state_kobj(device, i);526}527 528#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS529#define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj)530#define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr)531 532#define define_one_driver_ro(_name, show) \533 static struct cpuidle_driver_attr attr_driver_##_name = \534 __ATTR(_name, 0444, show, NULL)535 536struct cpuidle_driver_kobj {537 struct cpuidle_driver *drv;538 struct completion kobj_unregister;539 struct kobject kobj;540};541 542struct cpuidle_driver_attr {543 struct attribute attr;544 ssize_t (*show)(struct cpuidle_driver *, char *);545 ssize_t (*store)(struct cpuidle_driver *, const char *, size_t);546};547 548static ssize_t show_driver_name(struct cpuidle_driver *drv, char *buf)549{550 ssize_t ret;551 552 spin_lock(&cpuidle_driver_lock);553 ret = sprintf(buf, "%s\n", drv ? drv->name : "none");554 spin_unlock(&cpuidle_driver_lock);555 556 return ret;557}558 559static void cpuidle_driver_sysfs_release(struct kobject *kobj)560{561 struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);562 complete(&driver_kobj->kobj_unregister);563}564 565static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute *attr,566 char *buf)567{568 int ret = -EIO;569 struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);570 struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);571 572 if (dattr->show)573 ret = dattr->show(driver_kobj->drv, buf);574 575 return ret;576}577 578static ssize_t cpuidle_driver_store(struct kobject *kobj, struct attribute *attr,579 const char *buf, size_t size)580{581 int ret = -EIO;582 struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);583 struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);584 585 if (dattr->store)586 ret = dattr->store(driver_kobj->drv, buf, size);587 588 return ret;589}590 591define_one_driver_ro(name, show_driver_name);592 593static const struct sysfs_ops cpuidle_driver_sysfs_ops = {594 .show = cpuidle_driver_show,595 .store = cpuidle_driver_store,596};597 598static struct attribute *cpuidle_driver_default_attrs[] = {599 &attr_driver_name.attr,600 NULL601};602ATTRIBUTE_GROUPS(cpuidle_driver_default);603 604static const struct kobj_type ktype_driver_cpuidle = {605 .sysfs_ops = &cpuidle_driver_sysfs_ops,606 .default_groups = cpuidle_driver_default_groups,607 .release = cpuidle_driver_sysfs_release,608};609 610/**611 * cpuidle_add_driver_sysfs - adds the driver name sysfs attribute612 * @dev: the target device613 */614static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)615{616 struct cpuidle_driver_kobj *kdrv;617 struct cpuidle_device_kobj *kdev = dev->kobj_dev;618 struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);619 int ret;620 621 kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL);622 if (!kdrv)623 return -ENOMEM;624 625 kdrv->drv = drv;626 init_completion(&kdrv->kobj_unregister);627 628 ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,629 &kdev->kobj, "driver");630 if (ret) {631 kobject_put(&kdrv->kobj);632 kfree(kdrv);633 return ret;634 }635 636 kobject_uevent(&kdrv->kobj, KOBJ_ADD);637 dev->kobj_driver = kdrv;638 639 return ret;640}641 642/**643 * cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute644 * @dev: the target device645 */646static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)647{648 struct cpuidle_driver_kobj *kdrv = dev->kobj_driver;649 kobject_put(&kdrv->kobj);650 wait_for_completion(&kdrv->kobj_unregister);651 kfree(kdrv);652}653#else654static inline int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)655{656 return 0;657}658 659static inline void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)660{661 ;662}663#endif664 665/**666 * cpuidle_add_device_sysfs - adds device specific sysfs attributes667 * @device: the target device668 */669int cpuidle_add_device_sysfs(struct cpuidle_device *device)670{671 int ret;672 673 ret = cpuidle_add_state_sysfs(device);674 if (ret)675 return ret;676 677 ret = cpuidle_add_driver_sysfs(device);678 if (ret)679 cpuidle_remove_state_sysfs(device);680 return ret;681}682 683/**684 * cpuidle_remove_device_sysfs : removes device specific sysfs attributes685 * @device : the target device686 */687void cpuidle_remove_device_sysfs(struct cpuidle_device *device)688{689 cpuidle_remove_driver_sysfs(device);690 cpuidle_remove_state_sysfs(device);691}692 693/**694 * cpuidle_add_sysfs - creates a sysfs instance for the target device695 * @dev: the target device696 */697int cpuidle_add_sysfs(struct cpuidle_device *dev)698{699 struct cpuidle_device_kobj *kdev;700 struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);701 int error;702 703 /*704 * Return if cpu_device is not setup for this CPU.705 *706 * This could happen if the arch did not set up cpu_device707 * since this CPU is not in cpu_present mask and the708 * driver did not send a correct CPU mask during registration.709 * Without this check we would end up passing bogus710 * value for &cpu_dev->kobj in kobject_init_and_add()711 */712 if (!cpu_dev)713 return -ENODEV;714 715 kdev = kzalloc(sizeof(*kdev), GFP_KERNEL);716 if (!kdev)717 return -ENOMEM;718 kdev->dev = dev;719 720 init_completion(&kdev->kobj_unregister);721 722 error = kobject_init_and_add(&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,723 "cpuidle");724 if (error) {725 kobject_put(&kdev->kobj);726 kfree(kdev);727 return error;728 }729 730 dev->kobj_dev = kdev;731 kobject_uevent(&kdev->kobj, KOBJ_ADD);732 733 return 0;734}735 736/**737 * cpuidle_remove_sysfs - deletes a sysfs instance on the target device738 * @dev: the target device739 */740void cpuidle_remove_sysfs(struct cpuidle_device *dev)741{742 struct cpuidle_device_kobj *kdev = dev->kobj_dev;743 744 kobject_put(&kdev->kobj);745 wait_for_completion(&kdev->kobj_unregister);746 kfree(kdev);747}748