1 /*
2 * xen/drivers/cpufreq/cpufreq_misc_gov.c
3 *
4 * Copyright (C) 2001 Russell King
5 * (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
6 *
7 * Nov 2008 Liu Jinsong <jinsong.liu@intel.com>
8 * Porting cpufreq_userspace.c, cpufreq_performance.c, and
9 * cpufreq_powersave.c from Liunx 2.6.23 to Xen hypervisor
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
14 *
15 */
16
17 #include <xen/cpu.h>
18 #include <xen/init.h>
19 #include <xen/percpu.h>
20 #include <xen/sched.h>
21 #include <acpi/cpufreq/cpufreq.h>
22
23 /*
24 * cpufreq userspace governor
25 */
26 static unsigned int __read_mostly userspace_cmdline_freq;
27 static DEFINE_PER_CPU(unsigned int, cpu_set_freq);
28
cpufreq_governor_userspace(struct cpufreq_policy * policy,unsigned int event)29 static int cf_check cpufreq_governor_userspace(
30 struct cpufreq_policy *policy, unsigned int event)
31 {
32 int ret = 0;
33 unsigned int cpu;
34
35 if (unlikely(!policy) ||
36 unlikely(!cpu_online(cpu = policy->cpu)))
37 return -EINVAL;
38
39 switch (event) {
40 case CPUFREQ_GOV_START:
41 if (!per_cpu(cpu_set_freq, cpu))
42 per_cpu(cpu_set_freq, cpu) = policy->cur;
43 break;
44 case CPUFREQ_GOV_STOP:
45 per_cpu(cpu_set_freq, cpu) = 0;
46 break;
47 case CPUFREQ_GOV_LIMITS:
48 if (policy->max < per_cpu(cpu_set_freq, cpu))
49 ret = __cpufreq_driver_target(policy, policy->max,
50 CPUFREQ_RELATION_H);
51 else if (policy->min > per_cpu(cpu_set_freq, cpu))
52 ret = __cpufreq_driver_target(policy, policy->min,
53 CPUFREQ_RELATION_L);
54 else
55 ret = __cpufreq_driver_target(policy, per_cpu(cpu_set_freq, cpu),
56 CPUFREQ_RELATION_L);
57
58 break;
59 default:
60 ret = -EINVAL;
61 break;
62 }
63
64 return ret;
65 }
66
67 #ifdef CONFIG_PM_OP
write_userspace_scaling_setspeed(unsigned int cpu,unsigned int freq)68 int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq)
69 {
70 struct cpufreq_policy *policy;
71
72 if (!cpu_online(cpu) || !(policy = per_cpu(cpufreq_cpu_policy, cpu)))
73 return -EINVAL;
74
75 per_cpu(cpu_set_freq, cpu) = freq;
76
77 if (freq < policy->min)
78 freq = policy->min;
79 if (freq > policy->max)
80 freq = policy->max;
81
82 return __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
83 }
84 #endif /* CONFIG_PM_OP */
85
86 static bool __init cf_check
cpufreq_userspace_handle_option(const char * name,const char * val)87 cpufreq_userspace_handle_option(const char *name, const char *val)
88 {
89 if (!strcmp(name, "speed") && val) {
90 userspace_cmdline_freq = simple_strtoul(val, NULL, 0);
91 return 1;
92 }
93 return 0;
94 }
95
cpufreq_userspace_cpu_callback(struct notifier_block * nfb,unsigned long action,void * hcpu)96 static int cf_check cpufreq_userspace_cpu_callback(
97 struct notifier_block *nfb, unsigned long action, void *hcpu)
98 {
99 unsigned int cpu = (unsigned long)hcpu;
100
101 switch (action)
102 {
103 case CPU_UP_PREPARE:
104 per_cpu(cpu_set_freq, cpu) = userspace_cmdline_freq;
105 break;
106 }
107
108 return NOTIFY_DONE;
109 }
110
111 static struct notifier_block cpufreq_userspace_cpu_nfb = {
112 .notifier_call = cpufreq_userspace_cpu_callback
113 };
114
115 struct cpufreq_governor cpufreq_gov_userspace = {
116 .name = "userspace",
117 .governor = cpufreq_governor_userspace,
118 .handle_option = cpufreq_userspace_handle_option
119 };
120
cpufreq_gov_userspace_init(void)121 static int __init cf_check cpufreq_gov_userspace_init(void)
122 {
123 unsigned int cpu;
124
125 if ( cpufreq_governor_internal )
126 return 0;
127
128 for_each_online_cpu(cpu)
129 per_cpu(cpu_set_freq, cpu) = userspace_cmdline_freq;
130 register_cpu_notifier(&cpufreq_userspace_cpu_nfb);
131 return cpufreq_register_governor(&cpufreq_gov_userspace);
132 }
133 __initcall(cpufreq_gov_userspace_init);
134
135
136 /*
137 * cpufreq performance governor
138 */
cpufreq_governor_performance(struct cpufreq_policy * policy,unsigned int event)139 static int cf_check cpufreq_governor_performance(
140 struct cpufreq_policy *policy, unsigned int event)
141 {
142 int ret = 0;
143
144 if (!policy)
145 return -EINVAL;
146
147 switch (event) {
148 case CPUFREQ_GOV_START:
149 case CPUFREQ_GOV_STOP:
150 break;
151 case CPUFREQ_GOV_LIMITS:
152 ret = __cpufreq_driver_target(policy, policy->max,
153 CPUFREQ_RELATION_H);
154 break;
155 default:
156 ret = -EINVAL;
157 break;
158 }
159
160 return ret;
161 }
162
163 struct cpufreq_governor cpufreq_gov_performance = {
164 .name = "performance",
165 .governor = cpufreq_governor_performance,
166 };
167
cpufreq_gov_performance_init(void)168 static int __init cf_check cpufreq_gov_performance_init(void)
169 {
170 if ( cpufreq_governor_internal )
171 return 0;
172
173 return cpufreq_register_governor(&cpufreq_gov_performance);
174 }
175 __initcall(cpufreq_gov_performance_init);
176
177
178 /*
179 * cpufreq powersave governor
180 */
cpufreq_governor_powersave(struct cpufreq_policy * policy,unsigned int event)181 static int cf_check cpufreq_governor_powersave(
182 struct cpufreq_policy *policy, unsigned int event)
183 {
184 int ret = 0;
185
186 if (!policy)
187 return -EINVAL;
188
189 switch (event) {
190 case CPUFREQ_GOV_START:
191 case CPUFREQ_GOV_STOP:
192 break;
193 case CPUFREQ_GOV_LIMITS:
194 ret = __cpufreq_driver_target(policy, policy->min,
195 CPUFREQ_RELATION_L);
196 break;
197 default:
198 ret = -EINVAL;
199 break;
200 }
201
202 return ret;
203 }
204
205 struct cpufreq_governor cpufreq_gov_powersave = {
206 .name = "powersave",
207 .governor = cpufreq_governor_powersave,
208 };
209
cpufreq_gov_powersave_init(void)210 static int __init cf_check cpufreq_gov_powersave_init(void)
211 {
212 if ( cpufreq_governor_internal )
213 return 0;
214
215 return cpufreq_register_governor(&cpufreq_gov_powersave);
216 }
217 __initcall(cpufreq_gov_powersave_init);
218