at master 153 lines 4.0 kB view raw
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 18struct userspace_policy { 19 unsigned int is_managed; 20 unsigned int setspeed; 21 struct mutex mutex; 22}; 23 24/** 25 * cpufreq_set - set the CPU frequency 26 * @policy: pointer to policy struct where freq is being set 27 * @freq: target frequency in kHz 28 * 29 * Sets the CPU frequency to freq. 30 */ 31static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 32{ 33 int ret = -EINVAL; 34 struct userspace_policy *userspace = policy->governor_data; 35 36 pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 37 38 mutex_lock(&userspace->mutex); 39 if (!userspace->is_managed) 40 goto err; 41 42 userspace->setspeed = freq; 43 44 ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 45 err: 46 mutex_unlock(&userspace->mutex); 47 return ret; 48} 49 50static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 51{ 52 return sprintf(buf, "%u\n", policy->cur); 53} 54 55static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) 56{ 57 struct userspace_policy *userspace; 58 59 userspace = kzalloc(sizeof(*userspace), GFP_KERNEL); 60 if (!userspace) 61 return -ENOMEM; 62 63 mutex_init(&userspace->mutex); 64 65 policy->governor_data = userspace; 66 return 0; 67} 68 69/* 70 * Any routine that writes to the policy struct will hold the "rwsem" of 71 * policy struct that means it is free to free "governor_data" here. 72 */ 73static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) 74{ 75 kfree(policy->governor_data); 76 policy->governor_data = NULL; 77} 78 79static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) 80{ 81 struct userspace_policy *userspace = policy->governor_data; 82 83 BUG_ON(!policy->cur); 84 pr_debug("started managing cpu %u\n", policy->cpu); 85 86 mutex_lock(&userspace->mutex); 87 userspace->is_managed = 1; 88 userspace->setspeed = policy->cur; 89 mutex_unlock(&userspace->mutex); 90 return 0; 91} 92 93static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) 94{ 95 struct userspace_policy *userspace = policy->governor_data; 96 97 pr_debug("managing cpu %u stopped\n", policy->cpu); 98 99 mutex_lock(&userspace->mutex); 100 userspace->is_managed = 0; 101 userspace->setspeed = 0; 102 mutex_unlock(&userspace->mutex); 103} 104 105static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) 106{ 107 struct userspace_policy *userspace = policy->governor_data; 108 109 mutex_lock(&userspace->mutex); 110 111 pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", 112 policy->cpu, policy->min, policy->max, policy->cur, userspace->setspeed); 113 114 if (policy->max < userspace->setspeed) 115 __cpufreq_driver_target(policy, policy->max, 116 CPUFREQ_RELATION_H); 117 else if (policy->min > userspace->setspeed) 118 __cpufreq_driver_target(policy, policy->min, 119 CPUFREQ_RELATION_L); 120 else 121 __cpufreq_driver_target(policy, userspace->setspeed, 122 CPUFREQ_RELATION_L); 123 124 mutex_unlock(&userspace->mutex); 125} 126 127static struct cpufreq_governor cpufreq_gov_userspace = { 128 .name = "userspace", 129 .init = cpufreq_userspace_policy_init, 130 .exit = cpufreq_userspace_policy_exit, 131 .start = cpufreq_userspace_policy_start, 132 .stop = cpufreq_userspace_policy_stop, 133 .limits = cpufreq_userspace_policy_limits, 134 .store_setspeed = cpufreq_set, 135 .show_setspeed = show_speed, 136 .owner = THIS_MODULE, 137 .flags = CPUFREQ_GOV_STRICT_TARGET, 138}; 139 140MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 141 "Russell King <rmk@arm.linux.org.uk>"); 142MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 143MODULE_LICENSE("GPL"); 144 145#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 146struct cpufreq_governor *cpufreq_default_governor(void) 147{ 148 return &cpufreq_gov_userspace; 149} 150#endif 151 152cpufreq_governor_init(cpufreq_gov_userspace); 153cpufreq_governor_exit(cpufreq_gov_userspace);