forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
3.6 KiB
142 lines
3.6 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
|
|
/* |
|
* linux/drivers/cpufreq/cpufreq_userspace.c |
|
* |
|
* Copyright (C) 2001 Russell King |
|
* (C) 2002 - 2004 Dominik Brodowski <[email protected]> |
|
*/ |
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|
|
|
#include <linux/cpufreq.h> |
|
#include <linux/init.h> |
|
#include <linux/module.h> |
|
#include <linux/mutex.h> |
|
#include <linux/slab.h> |
|
|
|
static DEFINE_PER_CPU(unsigned int, cpu_is_managed); |
|
static DEFINE_MUTEX(userspace_mutex); |
|
|
|
/** |
|
* cpufreq_set - set the CPU frequency |
|
* @policy: pointer to policy struct where freq is being set |
|
* @freq: target frequency in kHz |
|
* |
|
* Sets the CPU frequency to freq. |
|
*/ |
|
static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) |
|
{ |
|
int ret = -EINVAL; |
|
unsigned int *setspeed = policy->governor_data; |
|
|
|
pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); |
|
|
|
mutex_lock(&userspace_mutex); |
|
if (!per_cpu(cpu_is_managed, policy->cpu)) |
|
goto err; |
|
|
|
*setspeed = freq; |
|
|
|
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); |
|
err: |
|
mutex_unlock(&userspace_mutex); |
|
return ret; |
|
} |
|
|
|
static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) |
|
{ |
|
return sprintf(buf, "%u\n", policy->cur); |
|
} |
|
|
|
static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) |
|
{ |
|
unsigned int *setspeed; |
|
|
|
setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); |
|
if (!setspeed) |
|
return -ENOMEM; |
|
|
|
policy->governor_data = setspeed; |
|
return 0; |
|
} |
|
|
|
static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) |
|
{ |
|
mutex_lock(&userspace_mutex); |
|
kfree(policy->governor_data); |
|
policy->governor_data = NULL; |
|
mutex_unlock(&userspace_mutex); |
|
} |
|
|
|
static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) |
|
{ |
|
unsigned int *setspeed = policy->governor_data; |
|
|
|
BUG_ON(!policy->cur); |
|
pr_debug("started managing cpu %u\n", policy->cpu); |
|
|
|
mutex_lock(&userspace_mutex); |
|
per_cpu(cpu_is_managed, policy->cpu) = 1; |
|
*setspeed = policy->cur; |
|
mutex_unlock(&userspace_mutex); |
|
return 0; |
|
} |
|
|
|
static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) |
|
{ |
|
unsigned int *setspeed = policy->governor_data; |
|
|
|
pr_debug("managing cpu %u stopped\n", policy->cpu); |
|
|
|
mutex_lock(&userspace_mutex); |
|
per_cpu(cpu_is_managed, policy->cpu) = 0; |
|
*setspeed = 0; |
|
mutex_unlock(&userspace_mutex); |
|
} |
|
|
|
static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) |
|
{ |
|
unsigned int *setspeed = policy->governor_data; |
|
|
|
mutex_lock(&userspace_mutex); |
|
|
|
pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", |
|
policy->cpu, policy->min, policy->max, policy->cur, *setspeed); |
|
|
|
if (policy->max < *setspeed) |
|
__cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); |
|
else if (policy->min > *setspeed) |
|
__cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); |
|
else |
|
__cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); |
|
|
|
mutex_unlock(&userspace_mutex); |
|
} |
|
|
|
static struct cpufreq_governor cpufreq_gov_userspace = { |
|
.name = "userspace", |
|
.init = cpufreq_userspace_policy_init, |
|
.exit = cpufreq_userspace_policy_exit, |
|
.start = cpufreq_userspace_policy_start, |
|
.stop = cpufreq_userspace_policy_stop, |
|
.limits = cpufreq_userspace_policy_limits, |
|
.store_setspeed = cpufreq_set, |
|
.show_setspeed = show_speed, |
|
.owner = THIS_MODULE, |
|
}; |
|
|
|
MODULE_AUTHOR("Dominik Brodowski <[email protected]>, " |
|
"Russell King <[email protected]>"); |
|
MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); |
|
MODULE_LICENSE("GPL"); |
|
|
|
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE |
|
struct cpufreq_governor *cpufreq_default_governor(void) |
|
{ |
|
return &cpufreq_gov_userspace; |
|
} |
|
#endif |
|
|
|
cpufreq_governor_init(cpufreq_gov_userspace); |
|
cpufreq_governor_exit(cpufreq_gov_userspace);
|
|
|