Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cpufreq_userspace.c
Go to the documentation of this file.
1 
2 /*
3  * linux/drivers/cpufreq/cpufreq_userspace.c
4  *
5  * Copyright (C) 2001 Russell King
6  * (C) 2002 - 2004 Dominik Brodowski <[email protected]>
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 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/smp.h>
17 #include <linux/init.h>
18 #include <linux/spinlock.h>
19 #include <linux/interrupt.h>
20 #include <linux/cpufreq.h>
21 #include <linux/cpu.h>
22 #include <linux/types.h>
23 #include <linux/fs.h>
24 #include <linux/sysfs.h>
25 #include <linux/mutex.h>
26 
30 static DEFINE_PER_CPU(unsigned int, cpu_max_freq);
31 static DEFINE_PER_CPU(unsigned int, cpu_min_freq);
32 static DEFINE_PER_CPU(unsigned int, cpu_cur_freq); /* current CPU freq */
33 static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by
34  userspace */
35 static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
36 
37 static DEFINE_MUTEX(userspace_mutex);
38 static int cpus_using_userspace_governor;
39 
40 /* keep track of frequency transitions */
41 static int
42 userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
43  void *data)
44 {
45  struct cpufreq_freqs *freq = data;
46 
47  if (!per_cpu(cpu_is_managed, freq->cpu))
48  return 0;
49 
50  if (val == CPUFREQ_POSTCHANGE) {
51  pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
52  freq->cpu, freq->new);
53  per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
54  }
55 
56  return 0;
57 }
58 
59 static struct notifier_block userspace_cpufreq_notifier_block = {
60  .notifier_call = userspace_cpufreq_notifier
61 };
62 
63 
71 static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
72 {
73  int ret = -EINVAL;
74 
75  pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
76 
77  mutex_lock(&userspace_mutex);
78  if (!per_cpu(cpu_is_managed, policy->cpu))
79  goto err;
80 
81  per_cpu(cpu_set_freq, policy->cpu) = freq;
82 
83  if (freq < per_cpu(cpu_min_freq, policy->cpu))
84  freq = per_cpu(cpu_min_freq, policy->cpu);
85  if (freq > per_cpu(cpu_max_freq, policy->cpu))
86  freq = per_cpu(cpu_max_freq, policy->cpu);
87 
88  /*
89  * We're safe from concurrent calls to ->target() here
90  * as we hold the userspace_mutex lock. If we were calling
91  * cpufreq_driver_target, a deadlock situation might occur:
92  * A: cpufreq_set (lock userspace_mutex) ->
93  * cpufreq_driver_target(lock policy->lock)
94  * B: cpufreq_set_policy(lock policy->lock) ->
95  * __cpufreq_governor ->
96  * cpufreq_governor_userspace (lock userspace_mutex)
97  */
98  ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
99 
100  err:
101  mutex_unlock(&userspace_mutex);
102  return ret;
103 }
104 
105 
106 static ssize_t show_speed(struct cpufreq_policy *policy, char *buf)
107 {
108  return sprintf(buf, "%u\n", per_cpu(cpu_cur_freq, policy->cpu));
109 }
110 
111 static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
112  unsigned int event)
113 {
114  unsigned int cpu = policy->cpu;
115  int rc = 0;
116 
117  switch (event) {
118  case CPUFREQ_GOV_START:
119  if (!cpu_online(cpu))
120  return -EINVAL;
121  BUG_ON(!policy->cur);
122  mutex_lock(&userspace_mutex);
123 
124  if (cpus_using_userspace_governor == 0) {
126  &userspace_cpufreq_notifier_block,
128  }
129  cpus_using_userspace_governor++;
130 
131  per_cpu(cpu_is_managed, cpu) = 1;
132  per_cpu(cpu_min_freq, cpu) = policy->min;
133  per_cpu(cpu_max_freq, cpu) = policy->max;
134  per_cpu(cpu_cur_freq, cpu) = policy->cur;
135  per_cpu(cpu_set_freq, cpu) = policy->cur;
136  pr_debug("managing cpu %u started "
137  "(%u - %u kHz, currently %u kHz)\n",
138  cpu,
139  per_cpu(cpu_min_freq, cpu),
140  per_cpu(cpu_max_freq, cpu),
141  per_cpu(cpu_cur_freq, cpu));
142 
143  mutex_unlock(&userspace_mutex);
144  break;
145  case CPUFREQ_GOV_STOP:
146  mutex_lock(&userspace_mutex);
147  cpus_using_userspace_governor--;
148  if (cpus_using_userspace_governor == 0) {
150  &userspace_cpufreq_notifier_block,
152  }
153 
154  per_cpu(cpu_is_managed, cpu) = 0;
155  per_cpu(cpu_min_freq, cpu) = 0;
156  per_cpu(cpu_max_freq, cpu) = 0;
157  per_cpu(cpu_set_freq, cpu) = 0;
158  pr_debug("managing cpu %u stopped\n", cpu);
159  mutex_unlock(&userspace_mutex);
160  break;
161  case CPUFREQ_GOV_LIMITS:
162  mutex_lock(&userspace_mutex);
163  pr_debug("limit event for cpu %u: %u - %u kHz, "
164  "currently %u kHz, last set to %u kHz\n",
165  cpu, policy->min, policy->max,
166  per_cpu(cpu_cur_freq, cpu),
167  per_cpu(cpu_set_freq, cpu));
168  if (policy->max < per_cpu(cpu_set_freq, cpu)) {
169  __cpufreq_driver_target(policy, policy->max,
171  } else if (policy->min > per_cpu(cpu_set_freq, cpu)) {
172  __cpufreq_driver_target(policy, policy->min,
174  } else {
176  per_cpu(cpu_set_freq, cpu),
178  }
179  per_cpu(cpu_min_freq, cpu) = policy->min;
180  per_cpu(cpu_max_freq, cpu) = policy->max;
181  per_cpu(cpu_cur_freq, cpu) = policy->cur;
182  mutex_unlock(&userspace_mutex);
183  break;
184  }
185  return rc;
186 }
187 
188 
189 #ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
190 static
191 #endif
192 struct cpufreq_governor cpufreq_gov_userspace = {
193  .name = "userspace",
194  .governor = cpufreq_governor_userspace,
195  .store_setspeed = cpufreq_set,
196  .show_setspeed = show_speed,
197  .owner = THIS_MODULE,
198 };
199 
200 static int __init cpufreq_gov_userspace_init(void)
201 {
202  return cpufreq_register_governor(&cpufreq_gov_userspace);
203 }
204 
205 
206 static void __exit cpufreq_gov_userspace_exit(void)
207 {
208  cpufreq_unregister_governor(&cpufreq_gov_userspace);
209 }
210 
211 
212 MODULE_AUTHOR("Dominik Brodowski <[email protected]>, "
213  "Russell King <[email protected]>");
214 MODULE_DESCRIPTION("CPUfreq policy governor 'userspace'");
215 MODULE_LICENSE("GPL");
216 
217 #ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE
218 fs_initcall(cpufreq_gov_userspace_init);
219 #else
220 module_init(cpufreq_gov_userspace_init);
221 #endif
222 module_exit(cpufreq_gov_userspace_exit);