linux/drivers/cpuidle/sysfs.c
<<
>>
Prefs
   1/*
   2 * sysfs.c - sysfs support
   3 *
   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/capability.h>
  15#include <linux/device.h>
  16
  17#include "cpuidle.h"
  18
  19static unsigned int sysfs_switch;
  20static int __init cpuidle_sysfs_setup(char *unused)
  21{
  22        sysfs_switch = 1;
  23        return 1;
  24}
  25__setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup);
  26
  27static ssize_t show_available_governors(struct device *dev,
  28                                        struct device_attribute *attr,
  29                                        char *buf)
  30{
  31        ssize_t i = 0;
  32        struct cpuidle_governor *tmp;
  33
  34        mutex_lock(&cpuidle_lock);
  35        list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
  36                if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
  37                        goto out;
  38                i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
  39        }
  40
  41out:
  42        i+= sprintf(&buf[i], "\n");
  43        mutex_unlock(&cpuidle_lock);
  44        return i;
  45}
  46
  47static ssize_t show_current_driver(struct device *dev,
  48                                   struct device_attribute *attr,
  49                                   char *buf)
  50{
  51        ssize_t ret;
  52        struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
  53
  54        spin_lock(&cpuidle_driver_lock);
  55        if (cpuidle_driver)
  56                ret = sprintf(buf, "%s\n", cpuidle_driver->name);
  57        else
  58                ret = sprintf(buf, "none\n");
  59        spin_unlock(&cpuidle_driver_lock);
  60
  61        return ret;
  62}
  63
  64static ssize_t show_current_governor(struct device *dev,
  65                                     struct device_attribute *attr,
  66                                     char *buf)
  67{
  68        ssize_t ret;
  69
  70        mutex_lock(&cpuidle_lock);
  71        if (cpuidle_curr_governor)
  72                ret = sprintf(buf, "%s\n", cpuidle_curr_governor->name);
  73        else
  74                ret = sprintf(buf, "none\n");
  75        mutex_unlock(&cpuidle_lock);
  76
  77        return ret;
  78}
  79
  80static ssize_t store_current_governor(struct device *dev,
  81                                      struct device_attribute *attr,
  82                                      const char *buf, size_t count)
  83{
  84        char gov_name[CPUIDLE_NAME_LEN];
  85        int ret = -EINVAL;
  86        size_t len = count;
  87        struct cpuidle_governor *gov;
  88
  89        if (!len || len >= sizeof(gov_name))
  90                return -EINVAL;
  91
  92        memcpy(gov_name, buf, len);
  93        gov_name[len] = '\0';
  94        if (gov_name[len - 1] == '\n')
  95                gov_name[--len] = '\0';
  96
  97        mutex_lock(&cpuidle_lock);
  98
  99        list_for_each_entry(gov, &cpuidle_governors, governor_list) {
 100                if (strlen(gov->name) == len && !strcmp(gov->name, gov_name)) {
 101                        ret = cpuidle_switch_governor(gov);
 102                        break;
 103                }
 104        }
 105
 106        mutex_unlock(&cpuidle_lock);
 107
 108        if (ret)
 109                return ret;
 110        else
 111                return count;
 112}
 113
 114static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL);
 115static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL);
 116
 117static struct attribute *cpuidle_default_attrs[] = {
 118        &dev_attr_current_driver.attr,
 119        &dev_attr_current_governor_ro.attr,
 120        NULL
 121};
 122
 123static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL);
 124static DEVICE_ATTR(current_governor, 0644, show_current_governor,
 125                   store_current_governor);
 126
 127static struct attribute *cpuidle_switch_attrs[] = {
 128        &dev_attr_available_governors.attr,
 129        &dev_attr_current_driver.attr,
 130        &dev_attr_current_governor.attr,
 131        NULL
 132};
 133
 134static struct attribute_group cpuidle_attr_group = {
 135        .attrs = cpuidle_default_attrs,
 136        .name = "cpuidle",
 137};
 138
 139/**
 140 * cpuidle_add_interface - add CPU global sysfs attributes
 141 */
 142int cpuidle_add_interface(struct device *dev)
 143{
 144        if (sysfs_switch)
 145                cpuidle_attr_group.attrs = cpuidle_switch_attrs;
 146
 147        return sysfs_create_group(&dev->kobj, &cpuidle_attr_group);
 148}
 149
 150/**
 151 * cpuidle_remove_interface - remove CPU global sysfs attributes
 152 */
 153void cpuidle_remove_interface(struct device *dev)
 154{
 155        sysfs_remove_group(&dev->kobj, &cpuidle_attr_group);
 156}
 157
 158struct cpuidle_attr {
 159        struct attribute attr;
 160        ssize_t (*show)(struct cpuidle_device *, char *);
 161        ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);
 162};
 163
 164#define define_one_ro(_name, show) \
 165        static struct cpuidle_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
 166#define define_one_rw(_name, show, store) \
 167        static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
 168
 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)
 171static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
 172{
 173        int ret = -EIO;
 174        struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 175        struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
 176
 177        if (cattr->show) {
 178                mutex_lock(&cpuidle_lock);
 179                ret = cattr->show(dev, buf);
 180                mutex_unlock(&cpuidle_lock);
 181        }
 182        return ret;
 183}
 184
 185static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
 186                     const char * buf, size_t count)
 187{
 188        int ret = -EIO;
 189        struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 190        struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
 191
 192        if (cattr->store) {
 193                mutex_lock(&cpuidle_lock);
 194                ret = cattr->store(dev, buf, count);
 195                mutex_unlock(&cpuidle_lock);
 196        }
 197        return ret;
 198}
 199
 200static const struct sysfs_ops cpuidle_sysfs_ops = {
 201        .show = cpuidle_show,
 202        .store = cpuidle_store,
 203};
 204
 205static void cpuidle_sysfs_release(struct kobject *kobj)
 206{
 207        struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 208
 209        complete(&dev->kobj_unregister);
 210}
 211
 212static struct kobj_type ktype_cpuidle = {
 213        .sysfs_ops = &cpuidle_sysfs_ops,
 214        .release = cpuidle_sysfs_release,
 215};
 216
 217struct cpuidle_state_attr {
 218        struct attribute attr;
 219        ssize_t (*show)(struct cpuidle_state *, \
 220                                        struct cpuidle_state_usage *, char *);
 221        ssize_t (*store)(struct cpuidle_state *, \
 222                        struct cpuidle_state_usage *, const char *, size_t);
 223};
 224
 225#define define_one_state_ro(_name, show) \
 226static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
 227
 228#define define_one_state_rw(_name, show, store) \
 229static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
 230
 231#define define_show_state_function(_name) \
 232static ssize_t show_state_##_name(struct cpuidle_state *state, \
 233                         struct cpuidle_state_usage *state_usage, char *buf) \
 234{ \
 235        return sprintf(buf, "%u\n", state->_name);\
 236}
 237
 238#define define_store_state_ull_function(_name) \
 239static ssize_t store_state_##_name(struct cpuidle_state *state, \
 240                struct cpuidle_state_usage *state_usage, \
 241                const char *buf, size_t size) \
 242{ \
 243        unsigned long long value; \
 244        int err; \
 245        if (!capable(CAP_SYS_ADMIN)) \
 246                return -EPERM; \
 247        err = kstrtoull(buf, 0, &value); \
 248        if (err) \
 249                return err; \
 250        if (value) \
 251                state_usage->_name = 1; \
 252        else \
 253                state_usage->_name = 0; \
 254        return size; \
 255}
 256
 257#define define_show_state_ull_function(_name) \
 258static ssize_t show_state_##_name(struct cpuidle_state *state, \
 259                        struct cpuidle_state_usage *state_usage, char *buf) \
 260{ \
 261        return sprintf(buf, "%llu\n", state_usage->_name);\
 262}
 263
 264#define define_show_state_str_function(_name) \
 265static ssize_t show_state_##_name(struct cpuidle_state *state, \
 266                        struct cpuidle_state_usage *state_usage, char *buf) \
 267{ \
 268        if (state->_name[0] == '\0')\
 269                return sprintf(buf, "<null>\n");\
 270        return sprintf(buf, "%s\n", state->_name);\
 271}
 272
 273define_show_state_function(exit_latency)
 274define_show_state_function(power_usage)
 275define_show_state_ull_function(usage)
 276define_show_state_ull_function(time)
 277define_show_state_str_function(name)
 278define_show_state_str_function(desc)
 279define_show_state_ull_function(disable)
 280define_store_state_ull_function(disable)
 281
 282define_one_state_ro(name, show_state_name);
 283define_one_state_ro(desc, show_state_desc);
 284define_one_state_ro(latency, show_state_exit_latency);
 285define_one_state_ro(power, show_state_power_usage);
 286define_one_state_ro(usage, show_state_usage);
 287define_one_state_ro(time, show_state_time);
 288define_one_state_rw(disable, show_state_disable, store_state_disable);
 289
 290static struct attribute *cpuidle_state_default_attrs[] = {
 291        &attr_name.attr,
 292        &attr_desc.attr,
 293        &attr_latency.attr,
 294        &attr_power.attr,
 295        &attr_usage.attr,
 296        &attr_time.attr,
 297        &attr_disable.attr,
 298        NULL
 299};
 300
 301struct cpuidle_state_kobj {
 302        struct cpuidle_state *state;
 303        struct cpuidle_state_usage *state_usage;
 304        struct completion kobj_unregister;
 305        struct kobject kobj;
 306};
 307
 308#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
 309#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)
 311#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
 312static ssize_t cpuidle_state_show(struct kobject * kobj,
 313        struct attribute * attr ,char * buf)
 314{
 315        int ret = -EIO;
 316        struct cpuidle_state *state = kobj_to_state(kobj);
 317        struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
 318        struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
 319
 320        if (cattr->show)
 321                ret = cattr->show(state, state_usage, buf);
 322
 323        return ret;
 324}
 325
 326static ssize_t cpuidle_state_store(struct kobject *kobj,
 327        struct attribute *attr, const char *buf, size_t size)
 328{
 329        int ret = -EIO;
 330        struct cpuidle_state *state = kobj_to_state(kobj);
 331        struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
 332        struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
 333
 334        if (cattr->store)
 335                ret = cattr->store(state, state_usage, buf, size);
 336
 337        return ret;
 338}
 339
 340static const struct sysfs_ops cpuidle_state_sysfs_ops = {
 341        .show = cpuidle_state_show,
 342        .store = cpuidle_state_store,
 343};
 344
 345static void cpuidle_state_sysfs_release(struct kobject *kobj)
 346{
 347        struct cpuidle_state_kobj *state_obj = kobj_to_state_obj(kobj);
 348
 349        complete(&state_obj->kobj_unregister);
 350}
 351
 352static struct kobj_type ktype_state_cpuidle = {
 353        .sysfs_ops = &cpuidle_state_sysfs_ops,
 354        .default_attrs = cpuidle_state_default_attrs,
 355        .release = cpuidle_state_sysfs_release,
 356};
 357
 358static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
 359{
 360        kobject_put(&device->kobjs[i]->kobj);
 361        wait_for_completion(&device->kobjs[i]->kobj_unregister);
 362        kfree(device->kobjs[i]);
 363        device->kobjs[i] = NULL;
 364}
 365
 366/**
 367 * cpuidle_add_state_sysfs - adds cpuidle states sysfs attributes
 368 * @device: the target device
 369 */
 370static int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 371{
 372        int i, ret = -ENOMEM;
 373        struct cpuidle_state_kobj *kobj;
 374        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(device);
 375
 376        /* state statistics */
 377        for (i = 0; i < device->state_count; i++) {
 378                kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
 379                if (!kobj)
 380                        goto error_state;
 381                kobj->state = &drv->states[i];
 382                kobj->state_usage = &device->states_usage[i];
 383                init_completion(&kobj->kobj_unregister);
 384
 385                ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle,
 386                                           &device->kobj, "state%d", i);
 387                if (ret) {
 388                        kfree(kobj);
 389                        goto error_state;
 390                }
 391                kobject_uevent(&kobj->kobj, KOBJ_ADD);
 392                device->kobjs[i] = kobj;
 393        }
 394
 395        return 0;
 396
 397error_state:
 398        for (i = i - 1; i >= 0; i--)
 399                cpuidle_free_state_kobj(device, i);
 400        return ret;
 401}
 402
 403/**
 404 * cpuidle_remove_driver_sysfs - removes the cpuidle states sysfs attributes
 405 * @device: the target device
 406 */
 407static void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
 408{
 409        int i;
 410
 411        for (i = 0; i < device->state_count; i++)
 412                cpuidle_free_state_kobj(device, i);
 413}
 414
 415#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
 416#define kobj_to_driver_kobj(k) container_of(k, struct cpuidle_driver_kobj, kobj)
 417#define attr_to_driver_attr(a) container_of(a, struct cpuidle_driver_attr, attr)
 418
 419#define define_one_driver_ro(_name, show)                       \
 420        static struct cpuidle_driver_attr attr_driver_##_name = \
 421                __ATTR(_name, 0644, show, NULL)
 422
 423struct cpuidle_driver_kobj {
 424        struct cpuidle_driver *drv;
 425        struct completion kobj_unregister;
 426        struct kobject kobj;
 427};
 428
 429struct cpuidle_driver_attr {
 430        struct attribute attr;
 431        ssize_t (*show)(struct cpuidle_driver *, char *);
 432        ssize_t (*store)(struct cpuidle_driver *, const char *, size_t);
 433};
 434
 435static ssize_t show_driver_name(struct cpuidle_driver *drv, char *buf)
 436{
 437        ssize_t ret;
 438
 439        spin_lock(&cpuidle_driver_lock);
 440        ret = sprintf(buf, "%s\n", drv ? drv->name : "none");
 441        spin_unlock(&cpuidle_driver_lock);
 442
 443        return ret;
 444}
 445
 446static void cpuidle_driver_sysfs_release(struct kobject *kobj)
 447{
 448        struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
 449        complete(&driver_kobj->kobj_unregister);
 450}
 451
 452static ssize_t cpuidle_driver_show(struct kobject *kobj, struct attribute * attr,
 453                                   char * buf)
 454{
 455        int ret = -EIO;
 456        struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
 457        struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);
 458
 459        if (dattr->show)
 460                ret = dattr->show(driver_kobj->drv, buf);
 461
 462        return ret;
 463}
 464
 465static ssize_t cpuidle_driver_store(struct kobject *kobj, struct attribute *attr,
 466                                    const char *buf, size_t size)
 467{
 468        int ret = -EIO;
 469        struct cpuidle_driver_kobj *driver_kobj = kobj_to_driver_kobj(kobj);
 470        struct cpuidle_driver_attr *dattr = attr_to_driver_attr(attr);
 471
 472        if (dattr->store)
 473                ret = dattr->store(driver_kobj->drv, buf, size);
 474
 475        return ret;
 476}
 477
 478define_one_driver_ro(name, show_driver_name);
 479
 480static const struct sysfs_ops cpuidle_driver_sysfs_ops = {
 481        .show = cpuidle_driver_show,
 482        .store = cpuidle_driver_store,
 483};
 484
 485static struct attribute *cpuidle_driver_default_attrs[] = {
 486        &attr_driver_name.attr,
 487        NULL
 488};
 489
 490static struct kobj_type ktype_driver_cpuidle = {
 491        .sysfs_ops = &cpuidle_driver_sysfs_ops,
 492        .default_attrs = cpuidle_driver_default_attrs,
 493        .release = cpuidle_driver_sysfs_release,
 494};
 495
 496/**
 497 * cpuidle_add_driver_sysfs - adds the driver name sysfs attribute
 498 * @device: the target device
 499 */
 500static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
 501{
 502        struct cpuidle_driver_kobj *kdrv;
 503        struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
 504        int ret;
 505
 506        kdrv = kzalloc(sizeof(*kdrv), GFP_KERNEL);
 507        if (!kdrv)
 508                return -ENOMEM;
 509
 510        kdrv->drv = drv;
 511        init_completion(&kdrv->kobj_unregister);
 512
 513        ret = kobject_init_and_add(&kdrv->kobj, &ktype_driver_cpuidle,
 514                                   &dev->kobj, "driver");
 515        if (ret) {
 516                kfree(kdrv);
 517                return ret;
 518        }
 519
 520        kobject_uevent(&kdrv->kobj, KOBJ_ADD);
 521        dev->kobj_driver = kdrv;
 522
 523        return ret;
 524}
 525
 526/**
 527 * cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute
 528 * @device: the target device
 529 */
 530static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
 531{
 532        struct cpuidle_driver_kobj *kdrv = dev->kobj_driver;
 533        kobject_put(&kdrv->kobj);
 534        wait_for_completion(&kdrv->kobj_unregister);
 535        kfree(kdrv);
 536}
 537#else
 538static inline int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
 539{
 540        return 0;
 541}
 542
 543static inline void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
 544{
 545        ;
 546}
 547#endif
 548
 549/**
 550 * cpuidle_add_device_sysfs - adds device specific sysfs attributes
 551 * @device: the target device
 552 */
 553int cpuidle_add_device_sysfs(struct cpuidle_device *device)
 554{
 555        int ret;
 556
 557        ret = cpuidle_add_state_sysfs(device);
 558        if (ret)
 559                return ret;
 560
 561        ret = cpuidle_add_driver_sysfs(device);
 562        if (ret)
 563                cpuidle_remove_state_sysfs(device);
 564        return ret;
 565}
 566
 567/**
 568 * cpuidle_remove_device_sysfs : removes device specific sysfs attributes
 569 * @device : the target device
 570 */
 571void cpuidle_remove_device_sysfs(struct cpuidle_device *device)
 572{
 573        cpuidle_remove_driver_sysfs(device);
 574        cpuidle_remove_state_sysfs(device);
 575}
 576
 577/**
 578 * cpuidle_add_sysfs - creates a sysfs instance for the target device
 579 * @dev: the target device
 580 */
 581int cpuidle_add_sysfs(struct cpuidle_device *dev)
 582{
 583        struct device *cpu_dev = get_cpu_device((unsigned long)dev->cpu);
 584        int error;
 585
 586        init_completion(&dev->kobj_unregister);
 587
 588        error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
 589                                     "cpuidle");
 590        if (!error)
 591                kobject_uevent(&dev->kobj, KOBJ_ADD);
 592        return error;
 593}
 594
 595/**
 596 * cpuidle_remove_sysfs - deletes a sysfs instance on the target device
 597 * @dev: the target device
 598 */
 599void cpuidle_remove_sysfs(struct cpuidle_device *dev)
 600{
 601        kobject_put(&dev->kobj);
 602        wait_for_completion(&dev->kobj_unregister);
 603}
 604
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.