linux/drivers/cpuidle/driver.c
<<
>>
Prefs
   1/*
   2 * driver.c - driver support
   3 *
   4 * (C) 2006-2007 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
   5 *               Shaohua Li <shaohua.li@intel.com>
   6 *               Adam Belay <abelay@novell.com>
   7 *
   8 * This code is licenced under the GPL.
   9 */
  10
  11#include <linux/mutex.h>
  12#include <linux/module.h>
  13#include <linux/cpuidle.h>
  14
  15#include "cpuidle.h"
  16
  17DEFINE_SPINLOCK(cpuidle_driver_lock);
  18
  19static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu);
  20static struct cpuidle_driver * __cpuidle_get_cpu_driver(int cpu);
  21
  22static void __cpuidle_driver_init(struct cpuidle_driver *drv)
  23{
  24        drv->refcnt = 0;
  25}
  26
  27static int __cpuidle_register_driver(struct cpuidle_driver *drv, int cpu)
  28{
  29        if (!drv || !drv->state_count)
  30                return -EINVAL;
  31
  32        if (cpuidle_disabled())
  33                return -ENODEV;
  34
  35        if (__cpuidle_get_cpu_driver(cpu))
  36                return -EBUSY;
  37
  38        __cpuidle_driver_init(drv);
  39
  40        __cpuidle_set_cpu_driver(drv, cpu);
  41
  42        return 0;
  43}
  44
  45static void __cpuidle_unregister_driver(struct cpuidle_driver *drv, int cpu)
  46{
  47        if (drv != __cpuidle_get_cpu_driver(cpu))
  48                return;
  49
  50        if (!WARN_ON(drv->refcnt > 0))
  51                __cpuidle_set_cpu_driver(NULL, cpu);
  52}
  53
  54#ifdef CONFIG_CPU_IDLE_MULTIPLE_DRIVERS
  55
  56static DEFINE_PER_CPU(struct cpuidle_driver *, cpuidle_drivers);
  57
  58static void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
  59{
  60        per_cpu(cpuidle_drivers, cpu) = drv;
  61}
  62
  63static struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
  64{
  65        return per_cpu(cpuidle_drivers, cpu);
  66}
  67
  68static void __cpuidle_unregister_all_cpu_driver(struct cpuidle_driver *drv)
  69{
  70        int cpu;
  71        for_each_present_cpu(cpu)
  72                __cpuidle_unregister_driver(drv, cpu);
  73}
  74
  75static int __cpuidle_register_all_cpu_driver(struct cpuidle_driver *drv)
  76{
  77        int ret = 0;
  78        int i, cpu;
  79
  80        for_each_present_cpu(cpu) {
  81                ret = __cpuidle_register_driver(drv, cpu);
  82                if (ret)
  83                        break;
  84        }
  85
  86        if (ret)
  87                for_each_present_cpu(i) {
  88                        if (i == cpu)
  89                                break;
  90                        __cpuidle_unregister_driver(drv, i);
  91                }
  92
  93
  94        return ret;
  95}
  96
  97int cpuidle_register_cpu_driver(struct cpuidle_driver *drv, int cpu)
  98{
  99        int ret;
 100
 101        spin_lock(&cpuidle_driver_lock);
 102        ret = __cpuidle_register_driver(drv, cpu);
 103        spin_unlock(&cpuidle_driver_lock);
 104
 105        return ret;
 106}
 107
 108void cpuidle_unregister_cpu_driver(struct cpuidle_driver *drv, int cpu)
 109{
 110        spin_lock(&cpuidle_driver_lock);
 111        __cpuidle_unregister_driver(drv, cpu);
 112        spin_unlock(&cpuidle_driver_lock);
 113}
 114
 115/**
 116 * cpuidle_register_driver - registers a driver
 117 * @drv: the driver
 118 */
 119int cpuidle_register_driver(struct cpuidle_driver *drv)
 120{
 121        int ret;
 122
 123        spin_lock(&cpuidle_driver_lock);
 124        ret = __cpuidle_register_all_cpu_driver(drv);
 125        spin_unlock(&cpuidle_driver_lock);
 126
 127        return ret;
 128}
 129EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 130
 131/**
 132 * cpuidle_unregister_driver - unregisters a driver
 133 * @drv: the driver
 134 */
 135void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 136{
 137        spin_lock(&cpuidle_driver_lock);
 138        __cpuidle_unregister_all_cpu_driver(drv);
 139        spin_unlock(&cpuidle_driver_lock);
 140}
 141EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
 142
 143#else
 144
 145static struct cpuidle_driver *cpuidle_curr_driver;
 146
 147static inline void __cpuidle_set_cpu_driver(struct cpuidle_driver *drv, int cpu)
 148{
 149        cpuidle_curr_driver = drv;
 150}
 151
 152static inline struct cpuidle_driver *__cpuidle_get_cpu_driver(int cpu)
 153{
 154        return cpuidle_curr_driver;
 155}
 156
 157/**
 158 * cpuidle_register_driver - registers a driver
 159 * @drv: the driver
 160 */
 161int cpuidle_register_driver(struct cpuidle_driver *drv)
 162{
 163        int ret, cpu;
 164
 165        cpu = get_cpu();
 166        spin_lock(&cpuidle_driver_lock);
 167        ret = __cpuidle_register_driver(drv, cpu);
 168        spin_unlock(&cpuidle_driver_lock);
 169        put_cpu();
 170
 171        return ret;
 172}
 173EXPORT_SYMBOL_GPL(cpuidle_register_driver);
 174
 175/**
 176 * cpuidle_unregister_driver - unregisters a driver
 177 * @drv: the driver
 178 */
 179void cpuidle_unregister_driver(struct cpuidle_driver *drv)
 180{
 181        int cpu;
 182
 183        cpu = get_cpu();
 184        spin_lock(&cpuidle_driver_lock);
 185        __cpuidle_unregister_driver(drv, cpu);
 186        spin_unlock(&cpuidle_driver_lock);
 187        put_cpu();
 188}
 189EXPORT_SYMBOL_GPL(cpuidle_unregister_driver);
 190#endif
 191
 192/**
 193 * cpuidle_get_driver - return the current driver
 194 */
 195struct cpuidle_driver *cpuidle_get_driver(void)
 196{
 197        struct cpuidle_driver *drv;
 198        int cpu;
 199
 200        cpu = get_cpu();
 201        drv = __cpuidle_get_cpu_driver(cpu);
 202        put_cpu();
 203
 204        return drv;
 205}
 206EXPORT_SYMBOL_GPL(cpuidle_get_driver);
 207
 208/**
 209 * cpuidle_get_cpu_driver - return the driver tied with a cpu
 210 */
 211struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
 212{
 213        if (!dev)
 214                return NULL;
 215
 216        return __cpuidle_get_cpu_driver(dev->cpu);
 217}
 218EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
 219
 220struct cpuidle_driver *cpuidle_driver_ref(void)
 221{
 222        struct cpuidle_driver *drv;
 223
 224        spin_lock(&cpuidle_driver_lock);
 225
 226        drv = cpuidle_get_driver();
 227        drv->refcnt++;
 228
 229        spin_unlock(&cpuidle_driver_lock);
 230        return drv;
 231}
 232
 233void cpuidle_driver_unref(void)
 234{
 235        struct cpuidle_driver *drv = cpuidle_get_driver();
 236
 237        spin_lock(&cpuidle_driver_lock);
 238
 239        if (drv && !WARN_ON(drv->refcnt <= 0))
 240                drv->refcnt--;
 241
 242        spin_unlock(&cpuidle_driver_lock);
 243}
 244
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.