| 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 | struct 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 | */ | 
|---|
| 31 | static 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(lock: &userspace->mutex); | 
|---|
| 39 | if (!userspace->is_managed) | 
|---|
| 40 | goto err; | 
|---|
| 41 |  | 
|---|
| 42 | userspace->setspeed = freq; | 
|---|
| 43 |  | 
|---|
| 44 | ret = __cpufreq_driver_target(policy, target_freq: freq, CPUFREQ_RELATION_L); | 
|---|
| 45 | err: | 
|---|
| 46 | mutex_unlock(lock: &userspace->mutex); | 
|---|
| 47 | return ret; | 
|---|
| 48 | } | 
|---|
| 49 |  | 
|---|
| 50 | static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) | 
|---|
| 51 | { | 
|---|
| 52 | return sprintf(buf, fmt: "%u\n", policy->cur); | 
|---|
| 53 | } | 
|---|
| 54 |  | 
|---|
| 55 | static 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 | */ | 
|---|
| 73 | static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) | 
|---|
| 74 | { | 
|---|
| 75 | kfree(objp: policy->governor_data); | 
|---|
| 76 | policy->governor_data = NULL; | 
|---|
| 77 | } | 
|---|
| 78 |  | 
|---|
| 79 | static 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(lock: &userspace->mutex); | 
|---|
| 87 | userspace->is_managed = 1; | 
|---|
| 88 | userspace->setspeed = policy->cur; | 
|---|
| 89 | mutex_unlock(lock: &userspace->mutex); | 
|---|
| 90 | return 0; | 
|---|
| 91 | } | 
|---|
| 92 |  | 
|---|
| 93 | static 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(lock: &userspace->mutex); | 
|---|
| 100 | userspace->is_managed = 0; | 
|---|
| 101 | userspace->setspeed = 0; | 
|---|
| 102 | mutex_unlock(lock: &userspace->mutex); | 
|---|
| 103 | } | 
|---|
| 104 |  | 
|---|
| 105 | static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) | 
|---|
| 106 | { | 
|---|
| 107 | struct userspace_policy *userspace = policy->governor_data; | 
|---|
| 108 |  | 
|---|
| 109 | mutex_lock(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, target_freq: policy->max, | 
|---|
| 116 | CPUFREQ_RELATION_H); | 
|---|
| 117 | else if (policy->min > userspace->setspeed) | 
|---|
| 118 | __cpufreq_driver_target(policy, target_freq: policy->min, | 
|---|
| 119 | CPUFREQ_RELATION_L); | 
|---|
| 120 | else | 
|---|
| 121 | __cpufreq_driver_target(policy, target_freq: userspace->setspeed, | 
|---|
| 122 | CPUFREQ_RELATION_L); | 
|---|
| 123 |  | 
|---|
| 124 | mutex_unlock(lock: &userspace->mutex); | 
|---|
| 125 | } | 
|---|
| 126 |  | 
|---|
| 127 | static 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 |  | 
|---|
| 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 |  | 
|---|