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