Branch data Line data Source code
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 : : static 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 : : */ 28 : 0 : static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) 29 : : { 30 : : int ret = -EINVAL; 31 : 0 : unsigned int *setspeed = policy->governor_data; 32 : : 33 : : pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); 34 : : 35 : 0 : mutex_lock(&userspace_mutex); 36 : 0 : if (!per_cpu(cpu_is_managed, policy->cpu)) 37 : : goto err; 38 : : 39 : 0 : *setspeed = freq; 40 : : 41 : 0 : ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); 42 : : err: 43 : 0 : mutex_unlock(&userspace_mutex); 44 : 0 : return ret; 45 : : } 46 : : 47 : 0 : static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) 48 : : { 49 : 0 : return sprintf(buf, "%u\n", policy->cur); 50 : : } 51 : : 52 : 0 : static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) 53 : : { 54 : : unsigned int *setspeed; 55 : : 56 : 0 : setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); 57 : 0 : if (!setspeed) 58 : : return -ENOMEM; 59 : : 60 : 0 : policy->governor_data = setspeed; 61 : 0 : return 0; 62 : : } 63 : : 64 : 0 : static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) 65 : : { 66 : 0 : mutex_lock(&userspace_mutex); 67 : 0 : kfree(policy->governor_data); 68 : 0 : policy->governor_data = NULL; 69 : 0 : mutex_unlock(&userspace_mutex); 70 : 0 : } 71 : : 72 : 0 : static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) 73 : : { 74 : 0 : unsigned int *setspeed = policy->governor_data; 75 : : 76 : 0 : BUG_ON(!policy->cur); 77 : : pr_debug("started managing cpu %u\n", policy->cpu); 78 : : 79 : 0 : mutex_lock(&userspace_mutex); 80 : 0 : per_cpu(cpu_is_managed, policy->cpu) = 1; 81 : 0 : *setspeed = policy->cur; 82 : 0 : mutex_unlock(&userspace_mutex); 83 : 0 : return 0; 84 : : } 85 : : 86 : 0 : static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) 87 : : { 88 : 0 : unsigned int *setspeed = policy->governor_data; 89 : : 90 : : pr_debug("managing cpu %u stopped\n", policy->cpu); 91 : : 92 : 0 : mutex_lock(&userspace_mutex); 93 : 0 : per_cpu(cpu_is_managed, policy->cpu) = 0; 94 : 0 : *setspeed = 0; 95 : 0 : mutex_unlock(&userspace_mutex); 96 : 0 : } 97 : : 98 : 0 : static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) 99 : : { 100 : 0 : unsigned int *setspeed = policy->governor_data; 101 : : 102 : 0 : 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 : 0 : if (policy->max < *setspeed) 108 : 0 : __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); 109 : 0 : else if (policy->min > *setspeed) 110 : 0 : __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); 111 : : else 112 : 0 : __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); 113 : : 114 : 0 : mutex_unlock(&userspace_mutex); 115 : 0 : } 116 : : 117 : : static 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 : : 129 : 3 : static int __init cpufreq_gov_userspace_init(void) 130 : : { 131 : 3 : return cpufreq_register_governor(&cpufreq_gov_userspace); 132 : : } 133 : : 134 : 0 : static void __exit cpufreq_gov_userspace_exit(void) 135 : : { 136 : 0 : cpufreq_unregister_governor(&cpufreq_gov_userspace); 137 : 0 : } 138 : : 139 : : MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 140 : : "Russell King <rmk@arm.linux.org.uk>"); 141 : : MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 142 : : MODULE_LICENSE("GPL"); 143 : : 144 : : #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 145 : : struct cpufreq_governor *cpufreq_default_governor(void) 146 : : { 147 : : return &cpufreq_gov_userspace; 148 : : } 149 : : 150 : : fs_initcall(cpufreq_gov_userspace_init); 151 : : #else 152 : : module_init(cpufreq_gov_userspace_init); 153 : : #endif 154 : : module_exit(cpufreq_gov_userspace_exit);