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 40 *setspeed = freq; 41 42 ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 43err: 44 mutex_unlock(&userspace_mutex); 45 return ret; 46} 47 48static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 49{ 50 return sprintf(buf, "%u\n", policy->cur); 51} 52 53static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) 54{ 55 unsigned int *setspeed; 56 57 setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); 58 if (!setspeed) { 59 return -ENOMEM; 60 } 61 62 policy->governor_data = setspeed; 63 return 0; 64} 65 66static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) 67{ 68 mutex_lock(&userspace_mutex); 69 kfree(policy->governor_data); 70 policy->governor_data = NULL; 71 mutex_unlock(&userspace_mutex); 72} 73 74static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) 75{ 76 unsigned int *setspeed = policy->governor_data; 77 78 BUG_ON(!policy->cur); 79 pr_debug("started managing cpu %u\n", policy->cpu); 80 81 mutex_lock(&userspace_mutex); 82 per_cpu(cpu_is_managed, policy->cpu) = 1; 83 if (!*setspeed) { 84 *setspeed = policy->cur; 85 } 86 mutex_unlock(&userspace_mutex); 87 return 0; 88} 89 90static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) 91{ 92 pr_debug("managing cpu %u stopped\n", policy->cpu); 93 94 mutex_lock(&userspace_mutex); 95 per_cpu(cpu_is_managed, policy->cpu) = 0; 96 mutex_unlock(&userspace_mutex); 97} 98 99static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) 100{ 101 unsigned int *setspeed = policy->governor_data; 102 103 mutex_lock(&userspace_mutex); 104 105 pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", policy->cpu, policy->min, 106 policy->max, policy->cur, *setspeed); 107 108 if (policy->max < *setspeed) { 109 __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); 110 } else if (policy->min > *setspeed) { 111 __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); 112 } else { 113 __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); 114 } 115 116 mutex_unlock(&userspace_mutex); 117} 118 119static struct cpufreq_governor cpufreq_gov_userspace = { 120 .name = "userspace", 121 .init = cpufreq_userspace_policy_init, 122 .exit = cpufreq_userspace_policy_exit, 123 .start = cpufreq_userspace_policy_start, 124 .stop = cpufreq_userspace_policy_stop, 125 .limits = cpufreq_userspace_policy_limits, 126 .store_setspeed = cpufreq_set, 127 .show_setspeed = show_speed, 128 .owner = THIS_MODULE, 129}; 130 131MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 132 "Russell King <rmk@arm.linux.org.uk>"); 133MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 134MODULE_LICENSE("GPL"); 135 136#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 137struct cpufreq_governor *cpufreq_default_governor(void) 138{ 139 return &cpufreq_gov_userspace; 140} 141#endif 142 143cpufreq_governor_init(cpufreq_gov_userspace); 144cpufreq_governor_exit(cpufreq_gov_userspace); 145