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