linux/drivers/cpuidle/governor.c
<<
>>
Prefs
   1/*
   2 * governor.c - governor 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
  17LIST_HEAD(cpuidle_governors);
  18struct cpuidle_governor *cpuidle_curr_governor;
  19
  20/**
  21 * __cpuidle_find_governor - finds a governor of the specified name
  22 * @str: the name
  23 *
  24 * Must be called with cpuidle_lock aquired.
  25 */
  26static struct cpuidle_governor * __cpuidle_find_governor(const char *str)
  27{
  28        struct cpuidle_governor *gov;
  29
  30        list_for_each_entry(gov, &cpuidle_governors, governor_list)
  31                if (!strnicmp(str, gov->name, CPUIDLE_NAME_LEN))
  32                        return gov;
  33
  34        return NULL;
  35}
  36
  37/**
  38 * cpuidle_switch_governor - changes the governor
  39 * @gov: the new target governor
  40 *
  41 * NOTE: "gov" can be NULL to specify disabled
  42 * Must be called with cpuidle_lock aquired.
  43 */
  44int cpuidle_switch_governor(struct cpuidle_governor *gov)
  45{
  46        struct cpuidle_device *dev;
  47
  48        if (gov == cpuidle_curr_governor)
  49                return 0;
  50
  51        cpuidle_uninstall_idle_handler();
  52
  53        if (cpuidle_curr_governor) {
  54                list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
  55                        cpuidle_disable_device(dev);
  56                module_put(cpuidle_curr_governor->owner);
  57        }
  58
  59        cpuidle_curr_governor = gov;
  60
  61        if (gov) {
  62                if (!try_module_get(cpuidle_curr_governor->owner))
  63                        return -EINVAL;
  64                list_for_each_entry(dev, &cpuidle_detected_devices, device_list)
  65                        cpuidle_enable_device(dev);
  66                cpuidle_install_idle_handler();
  67                printk(KERN_INFO "cpuidle: using governor %s\n", gov->name);
  68        }
  69
  70        return 0;
  71}
  72
  73/**
  74 * cpuidle_register_governor - registers a governor
  75 * @gov: the governor
  76 */
  77int cpuidle_register_governor(struct cpuidle_governor *gov)
  78{
  79        int ret = -EEXIST;
  80
  81        if (!gov || !gov->select)
  82                return -EINVAL;
  83
  84        mutex_lock(&cpuidle_lock);
  85        if (__cpuidle_find_governor(gov->name) == NULL) {
  86                ret = 0;
  87                list_add_tail(&gov->governor_list, &cpuidle_governors);
  88                if (!cpuidle_curr_governor ||
  89                    cpuidle_curr_governor->rating < gov->rating)
  90                        cpuidle_switch_governor(gov);
  91        }
  92        mutex_unlock(&cpuidle_lock);
  93
  94        return ret;
  95}
  96
  97/**
  98 * cpuidle_replace_governor - find a replacement governor
  99 * @exclude_rating: the rating that will be skipped while looking for
 100 * new governor.
 101 */
 102static struct cpuidle_governor *cpuidle_replace_governor(int exclude_rating)
 103{
 104        struct cpuidle_governor *gov;
 105        struct cpuidle_governor *ret_gov = NULL;
 106        unsigned int max_rating = 0;
 107
 108        list_for_each_entry(gov, &cpuidle_governors, governor_list) {
 109                if (gov->rating == exclude_rating)
 110                        continue;
 111                if (gov->rating > max_rating) {
 112                        max_rating = gov->rating;
 113                        ret_gov = gov;
 114                }
 115        }
 116
 117        return ret_gov;
 118}
 119
 120/**
 121 * cpuidle_unregister_governor - unregisters a governor
 122 * @gov: the governor
 123 */
 124void cpuidle_unregister_governor(struct cpuidle_governor *gov)
 125{
 126        if (!gov)
 127                return;
 128
 129        mutex_lock(&cpuidle_lock);
 130        if (gov == cpuidle_curr_governor) {
 131                struct cpuidle_governor *new_gov;
 132                new_gov = cpuidle_replace_governor(gov->rating);
 133                cpuidle_switch_governor(new_gov);
 134        }
 135        list_del(&gov->governor_list);
 136        mutex_unlock(&cpuidle_lock);
 137}
 138
 139