linux/drivers/cpufreq/cpufreq_userspace.c
<<
>>
Prefs
   1
   2/*
   3 *  linux/drivers/cpufreq/cpufreq_userspace.c
   4 *
   5 *  Copyright (C)  2001 Russell King
   6 *            (C)  2002 - 2004 Dominik Brodowski <linux@brodo.de>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13
  14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15
  16#include <linux/cpufreq.h>
  17#include <linux/init.h>
  18#include <linux/module.h>
  19#include <linux/mutex.h>
  20#include <linux/slab.h>
  21
  22static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
  23static DEFINE_MUTEX(userspace_mutex);
  24
  25/**
  26 * cpufreq_set - set the CPU frequency
  27 * @policy: pointer to policy struct where freq is being set
  28 * @freq: target frequency in kHz
  29 *
  30 * Sets the CPU frequency to freq.
  31 */
  32static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
  33{
  34        int ret = -EINVAL;
  35        unsigned int *setspeed = policy->governor_data;
  36
  37        pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
  38
  39        mutex_lock(&userspace_mutex);
  40        if (!per_cpu(cpu_is_managed, policy->cpu))
  41                goto err;
  42
  43        *setspeed = freq;
  44
  45        ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
  46 err:
  47        mutex_unlock(&userspace_mutex);
  48        return ret;
  49}
  50
  51static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
  52{
  53        return sprintf(buf, "%u\n", policy->cur);
  54}
  55
  56static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy)
  57{
  58        unsigned int *setspeed;
  59
  60        setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL);
  61        if (!setspeed)
  62                return -ENOMEM;
  63
  64        policy->governor_data = setspeed;
  65        return 0;
  66}
  67
  68static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy)
  69{
  70        mutex_lock(&userspace_mutex);
  71        kfree(policy->governor_data);
  72        policy->governor_data = NULL;
  73        mutex_unlock(&userspace_mutex);
  74}
  75
  76static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy)
  77{
  78        unsigned int *setspeed = policy->governor_data;
  79
  80        BUG_ON(!policy->cur);
  81        pr_debug("started managing cpu %u\n", policy->cpu);
  82
  83        mutex_lock(&userspace_mutex);
  84        per_cpu(cpu_is_managed, policy->cpu) = 1;
  85        *setspeed = policy->cur;
  86        mutex_unlock(&userspace_mutex);
  87        return 0;
  88}
  89
  90static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy)
  91{
  92        unsigned int *setspeed = policy->governor_data;
  93
  94        pr_debug("managing cpu %u stopped\n", policy->cpu);
  95
  96        mutex_lock(&userspace_mutex);
  97        per_cpu(cpu_is_managed, policy->cpu) = 0;
  98        *setspeed = 0;
  99        mutex_unlock(&userspace_mutex);
 100}
 101
 102static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy)
 103{
 104        unsigned int *setspeed = policy->governor_data;
 105
 106        mutex_lock(&userspace_mutex);
 107
 108        pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
 109                 policy->cpu, policy->min, policy->max, policy->cur, *setspeed);
 110
 111        if (policy->max < *setspeed)
 112                __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
 113        else if (policy->min > *setspeed)
 114                __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
 115        else
 116                __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L);
 117
 118        mutex_unlock(&userspace_mutex);
 119}
 120
 121static struct cpufreq_governor cpufreq_gov_userspace = {
 122        .name           = "userspace",
 123        .init           = cpufreq_userspace_policy_init,
 124        .exit           = cpufreq_userspace_policy_exit,
 125        .start          = cpufreq_userspace_policy_start,
 126        .stop           = cpufreq_userspace_policy_stop,
 127        .limits         = cpufreq_userspace_policy_limits,
 128        .store_setspeed = cpufreq_set,
 129        .show_setspeed  = show_speed,
 130        .owner          = THIS_MODULE,
 131};
 132
 133static int __init cpufreq_gov_userspace_init(void)
 134{
 135        return cpufreq_register_governor(&cpufreq_gov_userspace);
 136}
 137
 138static void __exit cpufreq_gov_userspace_exit(void)
 139{
 140        cpufreq_unregister_governor(&cpufreq_gov_userspace);
 141}
 142
 143MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "
 144                "Russell King <rmk@arm.linux.org.uk>");
 145MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
 146MODULE_LICENSE("GPL");
 147
 148#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
 149struct cpufreq_governor *cpufreq_default_governor(void)
 150{
 151        return &cpufreq_gov_userspace;
 152}
 153
 154fs_initcall(cpufreq_gov_userspace_init);
 155#else
 156module_init(cpufreq_gov_userspace_init);
 157#endif
 158module_exit(cpufreq_gov_userspace_exit);
 159