1 2 /* 3 * linux/drivers/cpufreq/cpufreq_userspace.c 4 * 5 * Copyright (C) 2001 Russell King 6 * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 * 12 */ 13 14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15 16 #include <linux/cpufreq.h> 17 #include <linux/init.h> 18 #include <linux/module.h> 19 #include <linux/mutex.h> 20 #include <linux/slab.h> 21 22 static DEFINE_PER_CPU(unsigned int, cpu_is_managed); 23 static DEFINE_MUTEX(userspace_mutex); 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 unsigned int *setspeed = 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 *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 unsigned int *setspeed; 59 60 setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); 61 if (!setspeed) 62 return -ENOMEM; 63 64 policy->governor_data = setspeed; 65 return 0; 66 } 67 68 static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) 69 { 70 mutex_lock(&userspace_mutex); 71 kfree(policy->governor_data); 72 policy->governor_data = NULL; 73 mutex_unlock(&userspace_mutex); 74 } 75 76 static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) 77 { 78 unsigned int *setspeed = policy->governor_data; 79 80 BUG_ON(!policy->cur); 81 pr_debug("started managing cpu %u\n", policy->cpu); 82 83 mutex_lock(&userspace_mutex); 84 per_cpu(cpu_is_managed, policy->cpu) = 1; 85 *setspeed = policy->cur; 86 mutex_unlock(&userspace_mutex); 87 return 0; 88 } 89 90 static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) 91 { 92 unsigned int *setspeed = policy->governor_data; 93 94 pr_debug("managing cpu %u stopped\n", policy->cpu); 95 96 mutex_lock(&userspace_mutex); 97 per_cpu(cpu_is_managed, policy->cpu) = 0; 98 *setspeed = 0; 99 mutex_unlock(&userspace_mutex); 100 } 101 102 static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) 103 { 104 unsigned int *setspeed = policy->governor_data; 105 106 mutex_lock(&userspace_mutex); 107 108 pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", 109 policy->cpu, policy->min, policy->max, policy->cur, *setspeed); 110 111 if (policy->max < *setspeed) 112 __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); 113 else if (policy->min > *setspeed) 114 __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); 115 else 116 __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); 117 118 mutex_unlock(&userspace_mutex); 119 } 120 121 static struct cpufreq_governor cpufreq_gov_userspace = { 122 .name = "userspace", 123 .init = cpufreq_userspace_policy_init, 124 .exit = cpufreq_userspace_policy_exit, 125 .start = cpufreq_userspace_policy_start, 126 .stop = cpufreq_userspace_policy_stop, 127 .limits = cpufreq_userspace_policy_limits, 128 .store_setspeed = cpufreq_set, 129 .show_setspeed = show_speed, 130 .owner = THIS_MODULE, 131 }; 132 133 static int __init cpufreq_gov_userspace_init(void) 134 { 135 return cpufreq_register_governor(&cpufreq_gov_userspace); 136 } 137 138 static void __exit cpufreq_gov_userspace_exit(void) 139 { 140 cpufreq_unregister_governor(&cpufreq_gov_userspace); 141 } 142 143 MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " 144 "Russell King <rmk@arm.linux.org.uk>"); 145 MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); 146 MODULE_LICENSE("GPL"); 147 148 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE 149 struct cpufreq_governor *cpufreq_default_governor(void) 150 { 151 return &cpufreq_gov_userspace; 152 } 153 154 fs_initcall(cpufreq_gov_userspace_init); 155 #else 156 module_init(cpufreq_gov_userspace_init); 157 #endif 158 module_exit(cpufreq_gov_userspace_exit); 159