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
  16#include "cpuidle.h"
  17
  18static unsigned int sysfs_switch;
  19static int __init cpuidle_sysfs_setup(char *unused)
  20{
  21        sysfs_switch = 1;
  22        return 1;
  23}
  24__setup("cpuidle_sysfs_switch", cpuidle_sysfs_setup);
  25
  26static ssize_t show_available_governors(struct device *dev,
  27                                        struct device_attribute *attr,
  28                                        char *buf)
  29{
  30        ssize_t i = 0;
  31        struct cpuidle_governor *tmp;
  32
  33        mutex_lock(&cpuidle_lock);
  34        list_for_each_entry(tmp, &cpuidle_governors, governor_list) {
  35                if (i >= (ssize_t) ((PAGE_SIZE/sizeof(char)) - CPUIDLE_NAME_LEN - 2))
  36                        goto out;
  37                i += scnprintf(&buf[i], CPUIDLE_NAME_LEN, "%s ", tmp->name);
  38        }
  39
  40out:
  41        i+= sprintf(&buf[i], "\n");
  42        mutex_unlock(&cpuidle_lock);
  43        return i;
  44}
  45
  46static ssize_t show_current_driver(struct device *dev,
  47                                   struct device_attribute *attr,
  48                                   char *buf)
  49{
  50        ssize_t ret;
  51        struct cpuidle_driver *cpuidle_driver = cpuidle_get_driver();
  52
  53        spin_lock(&cpuidle_driver_lock);
  54        if (cpuidle_driver)
  55                ret = sprintf(buf, "%s\n", cpuidle_driver->name);
  56        else
  57                ret = sprintf(buf, "none\n");
  58        spin_unlock(&cpuidle_driver_lock);
  59
  60        return ret;
  61}
  62
  63static ssize_t show_current_governor(struct device *dev,
  64                                     struct device_attribute *attr,
  65                                     char *buf)
  66{
  67        ssize_t ret;
  68
  69        mutex_lock(&cpuidle_lock);
  70        if (cpuidle_curr_governor)
  71                ret = sprintf(buf, "%s\n", cpuidle_curr_governor->name);
  72        else
  73                ret = sprintf(buf, "none\n");
  74        mutex_unlock(&cpuidle_lock);
  75
  76        return ret;
  77}
  78
  79static ssize_t store_current_governor(struct device *dev,
  80                                      struct device_attribute *attr,
  81                                      const char *buf, size_t count)
  82{
  83        char gov_name[CPUIDLE_NAME_LEN];
  84        int ret = -EINVAL;
  85        size_t len = count;
  86        struct cpuidle_governor *gov;
  87
  88        if (!len || len >= sizeof(gov_name))
  89                return -EINVAL;
  90
  91        memcpy(gov_name, buf, len);
  92        gov_name[len] = '\0';
  93        if (gov_name[len - 1] == '\n')
  94                gov_name[--len] = '\0';
  95
  96        mutex_lock(&cpuidle_lock);
  97
  98        list_for_each_entry(gov, &cpuidle_governors, governor_list) {
  99                if (strlen(gov->name) == len && !strcmp(gov->name, gov_name)) {
 100                        ret = cpuidle_switch_governor(gov);
 101                        break;
 102                }
 103        }
 104
 105        mutex_unlock(&cpuidle_lock);
 106
 107        if (ret)
 108                return ret;
 109        else
 110                return count;
 111}
 112
 113static DEVICE_ATTR(current_driver, 0444, show_current_driver, NULL);
 114static DEVICE_ATTR(current_governor_ro, 0444, show_current_governor, NULL);
 115
 116static struct attribute *cpuidle_default_attrs[] = {
 117        &dev_attr_current_driver.attr,
 118        &dev_attr_current_governor_ro.attr,
 119        NULL
 120};
 121
 122static DEVICE_ATTR(available_governors, 0444, show_available_governors, NULL);
 123static DEVICE_ATTR(current_governor, 0644, show_current_governor,
 124                   store_current_governor);
 125
 126static struct attribute *cpuidle_switch_attrs[] = {
 127        &dev_attr_available_governors.attr,
 128        &dev_attr_current_driver.attr,
 129        &dev_attr_current_governor.attr,
 130        NULL
 131};
 132
 133static struct attribute_group cpuidle_attr_group = {
 134        .attrs = cpuidle_default_attrs,
 135        .name = "cpuidle",
 136};
 137
 138/**
 139 * cpuidle_add_interface - add CPU global sysfs attributes
 140 */
 141int cpuidle_add_interface(struct device *dev)
 142{
 143        if (sysfs_switch)
 144                cpuidle_attr_group.attrs = cpuidle_switch_attrs;
 145
 146        return sysfs_create_group(&dev->kobj, &cpuidle_attr_group);
 147}
 148
 149/**
 150 * cpuidle_remove_interface - remove CPU global sysfs attributes
 151 */
 152void cpuidle_remove_interface(struct device *dev)
 153{
 154        sysfs_remove_group(&dev->kobj, &cpuidle_attr_group);
 155}
 156
 157struct cpuidle_attr {
 158        struct attribute attr;
 159        ssize_t (*show)(struct cpuidle_device *, char *);
 160        ssize_t (*store)(struct cpuidle_device *, const char *, size_t count);
 161};
 162
 163#define define_one_ro(_name, show) \
 164        static struct cpuidle_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
 165#define define_one_rw(_name, show, store) \
 166        static struct cpuidle_attr attr_##_name = __ATTR(_name, 0644, show, store)
 167
 168#define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
 169#define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
 170static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
 171{
 172        int ret = -EIO;
 173        struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 174        struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
 175
 176        if (cattr->show) {
 177                mutex_lock(&cpuidle_lock);
 178                ret = cattr->show(dev, buf);
 179                mutex_unlock(&cpuidle_lock);
 180        }
 181        return ret;
 182}
 183
 184static ssize_t cpuidle_store(struct kobject * kobj, struct attribute * attr,
 185                     const char * buf, size_t count)
 186{
 187        int ret = -EIO;
 188        struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 189        struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
 190
 191        if (cattr->store) {
 192                mutex_lock(&cpuidle_lock);
 193                ret = cattr->store(dev, buf, count);
 194                mutex_unlock(&cpuidle_lock);
 195        }
 196        return ret;
 197}
 198
 199static const struct sysfs_ops cpuidle_sysfs_ops = {
 200        .show = cpuidle_show,
 201        .store = cpuidle_store,
 202};
 203
 204static void cpuidle_sysfs_release(struct kobject *kobj)
 205{
 206        struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 207
 208        complete(&dev->kobj_unregister);
 209}
 210
 211static struct kobj_type ktype_cpuidle = {
 212        .sysfs_ops = &cpuidle_sysfs_ops,
 213        .release = cpuidle_sysfs_release,
 214};
 215
 216struct cpuidle_state_attr {
 217        struct attribute attr;
 218        ssize_t (*show)(struct cpuidle_state *, \
 219                                        struct cpuidle_state_usage *, char *);
 220        ssize_t (*store)(struct cpuidle_state *, \
 221                        struct cpuidle_state_usage *, const char *, size_t);
 222};
 223
 224#define define_one_state_ro(_name, show) \
 225static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL)
 226
 227#define define_one_state_rw(_name, show, store) \
 228static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0644, show, store)
 229
 230#define define_show_state_function(_name) \
 231static ssize_t show_state_##_name(struct cpuidle_state *state, \
 232                         struct cpuidle_state_usage *state_usage, char *buf) \
 233{ \
 234        return sprintf(buf, "%u\n", state->_name);\
 235}
 236
 237#define define_store_state_ull_function(_name) \
 238static ssize_t store_state_##_name(struct cpuidle_state *state, \
 239                struct cpuidle_state_usage *state_usage, \
 240                const char *buf, size_t size) \
 241{ \
 242        unsigned long long value; \
 243        int err; \
 244        if (!capable(CAP_SYS_ADMIN)) \
 245                return -EPERM; \
 246        err = kstrtoull(buf, 0, &value); \
 247        if (err) \
 248                return err; \
 249        if (value) \
 250                state_usage->_name = 1; \
 251        else \
 252                state_usage->_name = 0; \
 253        return size; \
 254}
 255
 256#define define_show_state_ull_function(_name) \
 257static ssize_t show_state_##_name(struct cpuidle_state *state, \
 258                        struct cpuidle_state_usage *state_usage, char *buf) \
 259{ \
 260        return sprintf(buf, "%llu\n", state_usage->_name);\
 261}
 262
 263#define define_show_state_str_function(_name) \
 264static ssize_t show_state_##_name(struct cpuidle_state *state, \
 265                        struct cpuidle_state_usage *state_usage, char *buf) \
 266{ \
 267        if (state->_name[0] == '\0')\
 268                return sprintf(buf, "<null>\n");\
 269        return sprintf(buf, "%s\n", state->_name);\
 270}
 271
 272define_show_state_function(exit_latency)
 273define_show_state_function(power_usage)
 274define_show_state_ull_function(usage)
 275define_show_state_ull_function(time)
 276define_show_state_str_function(name)
 277define_show_state_str_function(desc)
 278define_show_state_ull_function(disable)
 279define_store_state_ull_function(disable)
 280
 281define_one_state_ro(name, show_state_name);
 282define_one_state_ro(desc, show_state_desc);
 283define_one_state_ro(latency, show_state_exit_latency);
 284define_one_state_ro(power, show_state_power_usage);
 285define_one_state_ro(usage, show_state_usage);
 286define_one_state_ro(time, show_state_time);
 287define_one_state_rw(disable, show_state_disable, store_state_disable);
 288
 289static struct attribute *cpuidle_state_default_attrs[] = {
 290        &attr_name.attr,
 291        &attr_desc.attr,
 292        &attr_latency.attr,
 293        &attr_power.attr,
 294        &attr_usage.attr,
 295        &attr_time.attr,
 296        &attr_disable.attr,
 297        NULL
 298};
 299
 300#define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj)
 301#define kobj_to_state(k) (kobj_to_state_obj(k)->state)
 302#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage)
 303#define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr)
 304static ssize_t cpuidle_state_show(struct kobject * kobj,
 305        struct attribute * attr ,char * buf)
 306{
 307        int ret = -EIO;
 308        struct cpuidle_state *state = kobj_to_state(kobj);
 309        struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
 310        struct cpuidle_state_attr * cattr = attr_to_stateattr(attr);
 311
 312        if (cattr->show)
 313                ret = cattr->show(state, state_usage, buf);
 314
 315        return ret;
 316}
 317
 318static ssize_t cpuidle_state_store(struct kobject *kobj,
 319        struct attribute *attr, const char *buf, size_t size)
 320{
 321        int ret = -EIO;
 322        struct cpuidle_state *state = kobj_to_state(kobj);
 323        struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj);
 324        struct cpuidle_state_attr *cattr = attr_to_stateattr(attr);
 325
 326        if (cattr->store)
 327                ret = cattr->store(state, state_usage, buf, size);
 328
 329        return ret;
 330}
 331
 332static const struct sysfs_ops cpuidle_state_sysfs_ops = {
 333        .show = cpuidle_state_show,
 334        .store = cpuidle_state_store,
 335};
 336
 337static void cpuidle_state_sysfs_release(struct kobject *kobj)
 338{
 339        struct cpuidle_state_kobj *state_obj = kobj_to_state_obj(kobj);
 340
 341        complete(&state_obj->kobj_unregister);
 342}
 343
 344static struct kobj_type ktype_state_cpuidle = {
 345        .sysfs_ops = &cpuidle_state_sysfs_ops,
 346        .default_attrs = cpuidle_state_default_attrs,
 347        .release = cpuidle_state_sysfs_release,
 348};
 349
 350static inline void cpuidle_free_state_kobj(struct cpuidle_device *device, int i)
 351{
 352        kobject_put(&device->kobjs[i]->kobj);
 353        wait_for_completion(&device->kobjs[i]->kobj_unregister);
 354        kfree(device->kobjs[i]);
 355        device->kobjs[i] = NULL;
 356}
 357
 358/**
 359 * cpuidle_add_driver_sysfs - adds driver-specific sysfs attributes
 360 * @device: the target device
 361 */
 362int cpuidle_add_state_sysfs(struct cpuidle_device *device)
 363{
 364        int i, ret = -ENOMEM;
 365        struct cpuidle_state_kobj *kobj;
 366        struct cpuidle_driver *drv = cpuidle_get_driver();
 367
 368        /* state statistics */
 369        for (i = 0; i < device->state_count; i++) {
 370                kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL);
 371                if (!kobj)
 372                        goto error_state;
 373                kobj->state = &drv->states[i];
 374                kobj->state_usage = &device->states_usage[i];
 375                init_completion(&kobj->kobj_unregister);
 376
 377                ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj,
 378                                           "state%d", i);
 379                if (ret) {
 380                        kfree(kobj);
 381                        goto error_state;
 382                }
 383                kobject_uevent(&kobj->kobj, KOBJ_ADD);
 384                device->kobjs[i] = kobj;
 385        }
 386
 387        return 0;
 388
 389error_state:
 390        for (i = i - 1; i >= 0; i--)
 391                cpuidle_free_state_kobj(device, i);
 392        return ret;
 393}
 394
 395/**
 396 * cpuidle_remove_driver_sysfs - removes driver-specific sysfs attributes
 397 * @device: the target device
 398 */
 399void cpuidle_remove_state_sysfs(struct cpuidle_device *device)
 400{
 401        int i;
 402
 403        for (i = 0; i < device->state_count; i++)
 404                cpuidle_free_state_kobj(device, i);
 405}
 406
 407/**
 408 * cpuidle_add_sysfs - creates a sysfs instance for the target device
 409 * @dev: the target device
 410 */
 411int cpuidle_add_sysfs(struct device *cpu_dev)
 412{
 413        int cpu = cpu_dev->id;
 414        struct cpuidle_device *dev;
 415        int error;
 416
 417        dev = per_cpu(cpuidle_devices, cpu);
 418        error = kobject_init_and_add(&dev->kobj, &ktype_cpuidle, &cpu_dev->kobj,
 419                                     "cpuidle");
 420        if (!error)
 421                kobject_uevent(&dev->kobj, KOBJ_ADD);
 422        return error;
 423}
 424
 425/**
 426 * cpuidle_remove_sysfs - deletes a sysfs instance on the target device
 427 * @dev: the target device
 428 */
 429void cpuidle_remove_sysfs(struct device *cpu_dev)
 430{
 431        int cpu = cpu_dev->id;
 432        struct cpuidle_device *dev;
 433
 434        dev = per_cpu(cpuidle_devices, cpu);
 435        kobject_put(&dev->kobj);
 436}
 437
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.