cpufreq_userspace.c (3724B)
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);