153 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3/*4 * linux/drivers/cpufreq/cpufreq_userspace.c5 *6 * Copyright (C) 2001 Russell King7 * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>8 */9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt11 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 frequency26 * @policy: pointer to policy struct where freq is being set27 * @freq: target frequency in kHz28 *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" of71 * 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 else121 __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};138 139MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, "140 "Russell King <rmk@arm.linux.org.uk>");141MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");142MODULE_LICENSE("GPL");143 144#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE145struct cpufreq_governor *cpufreq_default_governor(void)146{147 return &cpufreq_gov_userspace;148}149#endif150 151cpufreq_governor_init(cpufreq_gov_userspace);152cpufreq_governor_exit(cpufreq_gov_userspace);153