Blame view
drivers/cpufreq/cpufreq_userspace.c
5.92 KB
c06728601 [CPUFREQ] Get rid... |
1 |
|
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 8 9 10 11 12 |
/* * linux/drivers/cpufreq/cpufreq_userspace.c * * Copyright (C) 2001 Russell King * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * */ |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 19 |
#include <linux/kernel.h> #include <linux/module.h> #include <linux/smp.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/cpufreq.h> |
153d7f3fc [PATCH] Reorganiz... |
20 |
#include <linux/cpu.h> |
1da177e4c Linux-2.6.12-rc2 |
21 22 23 |
#include <linux/types.h> #include <linux/fs.h> #include <linux/sysfs.h> |
3fc54d37a [CPUFREQ] Convert... |
24 |
#include <linux/mutex.h> |
1da177e4c Linux-2.6.12-rc2 |
25 |
|
1da177e4c Linux-2.6.12-rc2 |
26 27 28 |
/** * A few values needed by the userspace governor */ |
b38868aab NR_CPUS: Replace ... |
29 30 31 32 33 34 |
static DEFINE_PER_CPU(unsigned int, cpu_max_freq); static DEFINE_PER_CPU(unsigned int, cpu_min_freq); static DEFINE_PER_CPU(unsigned int, cpu_cur_freq); /* current CPU freq */ static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by userspace */ static DEFINE_PER_CPU(unsigned int, cpu_is_managed); |
1da177e4c Linux-2.6.12-rc2 |
35 |
|
1bceb8d13 [CPUFREQ] checkpa... |
36 |
static DEFINE_MUTEX(userspace_mutex); |
c7f652e04 [CPUFREQ] Keep us... |
37 |
static int cpus_using_userspace_governor; |
1da177e4c Linux-2.6.12-rc2 |
38 |
|
1da177e4c Linux-2.6.12-rc2 |
39 |
/* keep track of frequency transitions */ |
32ee8c3e4 [CPUFREQ] Lots of... |
40 |
static int |
1da177e4c Linux-2.6.12-rc2 |
41 |
userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val, |
1bceb8d13 [CPUFREQ] checkpa... |
42 |
void *data) |
1da177e4c Linux-2.6.12-rc2 |
43 |
{ |
1bceb8d13 [CPUFREQ] checkpa... |
44 |
struct cpufreq_freqs *freq = data; |
1da177e4c Linux-2.6.12-rc2 |
45 |
|
b38868aab NR_CPUS: Replace ... |
46 |
if (!per_cpu(cpu_is_managed, freq->cpu)) |
c7f652e04 [CPUFREQ] Keep us... |
47 |
return 0; |
226dd0193 [CPUFREQ] cpufreq... |
48 49 50 51 52 53 |
if (val == CPUFREQ_POSTCHANGE) { pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz ", freq->cpu, freq->new); per_cpu(cpu_cur_freq, freq->cpu) = freq->new; } |
1da177e4c Linux-2.6.12-rc2 |
54 |
|
1bceb8d13 [CPUFREQ] checkpa... |
55 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
56 57 58 |
} static struct notifier_block userspace_cpufreq_notifier_block = { |
1bceb8d13 [CPUFREQ] checkpa... |
59 |
.notifier_call = userspace_cpufreq_notifier |
1da177e4c Linux-2.6.12-rc2 |
60 |
}; |
32ee8c3e4 [CPUFREQ] Lots of... |
61 |
/** |
1da177e4c Linux-2.6.12-rc2 |
62 |
* cpufreq_set - set the CPU frequency |
9e76988e9 [CPUFREQ] Elimina... |
63 |
* @policy: pointer to policy struct where freq is being set |
1da177e4c Linux-2.6.12-rc2 |
64 |
* @freq: target frequency in kHz |
1da177e4c Linux-2.6.12-rc2 |
65 66 67 |
* * Sets the CPU frequency to freq. */ |
9e76988e9 [CPUFREQ] Elimina... |
68 |
static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) |
1da177e4c Linux-2.6.12-rc2 |
69 70 |
{ int ret = -EINVAL; |
2d06d8c49 [CPUFREQ] use dyn... |
71 72 |
pr_debug("cpufreq_set for cpu %u, freq %u kHz ", policy->cpu, freq); |
1da177e4c Linux-2.6.12-rc2 |
73 |
|
3fc54d37a [CPUFREQ] Convert... |
74 |
mutex_lock(&userspace_mutex); |
b38868aab NR_CPUS: Replace ... |
75 |
if (!per_cpu(cpu_is_managed, policy->cpu)) |
1da177e4c Linux-2.6.12-rc2 |
76 |
goto err; |
b38868aab NR_CPUS: Replace ... |
77 |
per_cpu(cpu_set_freq, policy->cpu) = freq; |
1da177e4c Linux-2.6.12-rc2 |
78 |
|
b38868aab NR_CPUS: Replace ... |
79 80 81 82 |
if (freq < per_cpu(cpu_min_freq, policy->cpu)) freq = per_cpu(cpu_min_freq, policy->cpu); if (freq > per_cpu(cpu_max_freq, policy->cpu)) freq = per_cpu(cpu_max_freq, policy->cpu); |
1da177e4c Linux-2.6.12-rc2 |
83 84 85 |
/* * We're safe from concurrent calls to ->target() here |
3fc54d37a [CPUFREQ] Convert... |
86 |
* as we hold the userspace_mutex lock. If we were calling |
1da177e4c Linux-2.6.12-rc2 |
87 |
* cpufreq_driver_target, a deadlock situation might occur: |
1bceb8d13 [CPUFREQ] checkpa... |
88 89 90 91 92 |
* A: cpufreq_set (lock userspace_mutex) -> * cpufreq_driver_target(lock policy->lock) * B: cpufreq_set_policy(lock policy->lock) -> * __cpufreq_governor -> * cpufreq_governor_userspace (lock userspace_mutex) |
1da177e4c Linux-2.6.12-rc2 |
93 |
*/ |
c06728601 [CPUFREQ] Get rid... |
94 |
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); |
1da177e4c Linux-2.6.12-rc2 |
95 96 |
err: |
3fc54d37a [CPUFREQ] Convert... |
97 |
mutex_unlock(&userspace_mutex); |
1da177e4c Linux-2.6.12-rc2 |
98 99 |
return ret; } |
9e76988e9 [CPUFREQ] Elimina... |
100 |
static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
101 |
{ |
b38868aab NR_CPUS: Replace ... |
102 103 |
return sprintf(buf, "%u ", per_cpu(cpu_cur_freq, policy->cpu)); |
1da177e4c Linux-2.6.12-rc2 |
104 |
} |
1da177e4c Linux-2.6.12-rc2 |
105 106 107 108 |
static int cpufreq_governor_userspace(struct cpufreq_policy *policy, unsigned int event) { unsigned int cpu = policy->cpu; |
914f7c31b [CPUFREQ] handle ... |
109 |
int rc = 0; |
1da177e4c Linux-2.6.12-rc2 |
110 111 112 113 114 |
switch (event) { case CPUFREQ_GOV_START: if (!cpu_online(cpu)) return -EINVAL; BUG_ON(!policy->cur); |
3fc54d37a [CPUFREQ] Convert... |
115 |
mutex_lock(&userspace_mutex); |
914f7c31b [CPUFREQ] handle ... |
116 |
|
c7f652e04 [CPUFREQ] Keep us... |
117 118 119 120 121 122 |
if (cpus_using_userspace_governor == 0) { cpufreq_register_notifier( &userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } cpus_using_userspace_governor++; |
b38868aab NR_CPUS: Replace ... |
123 124 125 126 127 |
per_cpu(cpu_is_managed, cpu) = 1; per_cpu(cpu_min_freq, cpu) = policy->min; per_cpu(cpu_max_freq, cpu) = policy->max; per_cpu(cpu_cur_freq, cpu) = policy->cur; per_cpu(cpu_set_freq, cpu) = policy->cur; |
2d06d8c49 [CPUFREQ] use dyn... |
128 |
pr_debug("managing cpu %u started " |
b38868aab NR_CPUS: Replace ... |
129 130 131 132 133 134 |
"(%u - %u kHz, currently %u kHz) ", cpu, per_cpu(cpu_min_freq, cpu), per_cpu(cpu_max_freq, cpu), per_cpu(cpu_cur_freq, cpu)); |
9e76988e9 [CPUFREQ] Elimina... |
135 |
|
3fc54d37a [CPUFREQ] Convert... |
136 |
mutex_unlock(&userspace_mutex); |
1da177e4c Linux-2.6.12-rc2 |
137 138 |
break; case CPUFREQ_GOV_STOP: |
3fc54d37a [CPUFREQ] Convert... |
139 |
mutex_lock(&userspace_mutex); |
c7f652e04 [CPUFREQ] Keep us... |
140 141 142 143 144 145 |
cpus_using_userspace_governor--; if (cpus_using_userspace_governor == 0) { cpufreq_unregister_notifier( &userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); } |
b38868aab NR_CPUS: Replace ... |
146 147 148 149 |
per_cpu(cpu_is_managed, cpu) = 0; per_cpu(cpu_min_freq, cpu) = 0; per_cpu(cpu_max_freq, cpu) = 0; per_cpu(cpu_set_freq, cpu) = 0; |
2d06d8c49 [CPUFREQ] use dyn... |
150 151 |
pr_debug("managing cpu %u stopped ", cpu); |
3fc54d37a [CPUFREQ] Convert... |
152 |
mutex_unlock(&userspace_mutex); |
1da177e4c Linux-2.6.12-rc2 |
153 154 |
break; case CPUFREQ_GOV_LIMITS: |
3fc54d37a [CPUFREQ] Convert... |
155 |
mutex_lock(&userspace_mutex); |
2d06d8c49 [CPUFREQ] use dyn... |
156 |
pr_debug("limit event for cpu %u: %u - %u kHz, " |
c06728601 [CPUFREQ] Get rid... |
157 158 159 |
"currently %u kHz, last set to %u kHz ", cpu, policy->min, policy->max, |
b38868aab NR_CPUS: Replace ... |
160 161 162 |
per_cpu(cpu_cur_freq, cpu), per_cpu(cpu_set_freq, cpu)); if (policy->max < per_cpu(cpu_set_freq, cpu)) { |
c06728601 [CPUFREQ] Get rid... |
163 164 |
__cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); |
b38868aab NR_CPUS: Replace ... |
165 |
} else if (policy->min > per_cpu(cpu_set_freq, cpu)) { |
c06728601 [CPUFREQ] Get rid... |
166 167 |
__cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); |
b38868aab NR_CPUS: Replace ... |
168 169 170 |
} else { __cpufreq_driver_target(policy, per_cpu(cpu_set_freq, cpu), |
c06728601 [CPUFREQ] Get rid... |
171 172 |
CPUFREQ_RELATION_L); } |
b38868aab NR_CPUS: Replace ... |
173 174 175 |
per_cpu(cpu_min_freq, cpu) = policy->min; per_cpu(cpu_max_freq, cpu) = policy->max; per_cpu(cpu_cur_freq, cpu) = policy->cur; |
3fc54d37a [CPUFREQ] Convert... |
176 |
mutex_unlock(&userspace_mutex); |
1da177e4c Linux-2.6.12-rc2 |
177 178 |
break; } |
914f7c31b [CPUFREQ] handle ... |
179 |
return rc; |
1da177e4c Linux-2.6.12-rc2 |
180 |
} |
c4d14bc0b [CPUFREQ] Don't e... |
181 182 183 |
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE static #endif |
1da177e4c Linux-2.6.12-rc2 |
184 185 186 |
struct cpufreq_governor cpufreq_gov_userspace = { .name = "userspace", .governor = cpufreq_governor_userspace, |
9e76988e9 [CPUFREQ] Elimina... |
187 188 |
.store_setspeed = cpufreq_set, .show_setspeed = show_speed, |
1da177e4c Linux-2.6.12-rc2 |
189 190 |
.owner = THIS_MODULE, }; |
1da177e4c Linux-2.6.12-rc2 |
191 192 193 |
static int __init cpufreq_gov_userspace_init(void) { |
1da177e4c Linux-2.6.12-rc2 |
194 195 196 197 198 199 200 |
return cpufreq_register_governor(&cpufreq_gov_userspace); } static void __exit cpufreq_gov_userspace_exit(void) { cpufreq_unregister_governor(&cpufreq_gov_userspace); |
1da177e4c Linux-2.6.12-rc2 |
201 |
} |
1bceb8d13 [CPUFREQ] checkpa... |
202 203 204 205 |
MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>, " "Russell King <rmk@arm.linux.org.uk>"); MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'"); MODULE_LICENSE("GPL"); |
1da177e4c Linux-2.6.12-rc2 |
206 |
|
6915719b3 cpufreq: Initiali... |
207 |
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE |
1da177e4c Linux-2.6.12-rc2 |
208 |
fs_initcall(cpufreq_gov_userspace_init); |
6915719b3 cpufreq: Initiali... |
209 210 211 |
#else module_init(cpufreq_gov_userspace_init); #endif |
1da177e4c Linux-2.6.12-rc2 |
212 |
module_exit(cpufreq_gov_userspace_exit); |