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 cpufreq_governor_userspace(struct cpufreq_policy *policy,
30 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
write_userspace_scaling_setspeed(unsigned int cpu,unsigned int freq)67 int write_userspace_scaling_setspeed(unsigned int cpu, unsigned int freq)
68 {
69 struct cpufreq_policy *policy;
70
71 if (!cpu_online(cpu) || !(policy = per_cpu(cpufreq_cpu_policy, cpu)))
72 return -EINVAL;
73
74 per_cpu(cpu_set_freq, cpu) = freq;
75
76 if (freq < policy->min)
77 freq = policy->min;
78 if (freq > policy->max)
79 freq = policy->max;
80
81 return __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
82 }
83
84 static bool_t __init
cpufreq_userspace_handle_option(const char * name,const char * val)85 cpufreq_userspace_handle_option(const char *name, const char *val)
86 {
87 if (!strcmp(name, "speed") && val) {
88 userspace_cmdline_freq = simple_strtoul(val, NULL, 0);
89 return 1;
90 }
91 return 0;
92 }
93
cpufreq_userspace_cpu_callback(struct notifier_block * nfb,unsigned long action,void * hcpu)94 static int cpufreq_userspace_cpu_callback(
95 struct notifier_block *nfb, unsigned long action, void *hcpu)
96 {
97 unsigned int cpu = (unsigned long)hcpu;
98
99 switch (action)
100 {
101 case CPU_UP_PREPARE:
102 per_cpu(cpu_set_freq, cpu) = userspace_cmdline_freq;
103 break;
104 }
105
106 return NOTIFY_DONE;
107 }
108
109 static struct notifier_block cpufreq_userspace_cpu_nfb = {
110 .notifier_call = cpufreq_userspace_cpu_callback
111 };
112
113 struct cpufreq_governor cpufreq_gov_userspace = {
114 .name = "userspace",
115 .governor = cpufreq_governor_userspace,
116 .handle_option = cpufreq_userspace_handle_option
117 };
118
cpufreq_gov_userspace_init(void)119 static int __init cpufreq_gov_userspace_init(void)
120 {
121 unsigned int cpu;
122
123 for_each_online_cpu(cpu)
124 per_cpu(cpu_set_freq, cpu) = userspace_cmdline_freq;
125 register_cpu_notifier(&cpufreq_userspace_cpu_nfb);
126 return cpufreq_register_governor(&cpufreq_gov_userspace);
127 }
128 __initcall(cpufreq_gov_userspace_init);
129
130
131 /*
132 * cpufreq performance governor
133 */
cpufreq_governor_performance(struct cpufreq_policy * policy,unsigned int event)134 static int cpufreq_governor_performance(struct cpufreq_policy *policy,
135 unsigned int event)
136 {
137 int ret = 0;
138
139 if (!policy)
140 return -EINVAL;
141
142 switch (event) {
143 case CPUFREQ_GOV_START:
144 case CPUFREQ_GOV_STOP:
145 break;
146 case CPUFREQ_GOV_LIMITS:
147 ret = __cpufreq_driver_target(policy, policy->max,
148 CPUFREQ_RELATION_H);
149 break;
150 default:
151 ret = -EINVAL;
152 break;
153 }
154
155 return ret;
156 }
157
158 struct cpufreq_governor cpufreq_gov_performance = {
159 .name = "performance",
160 .governor = cpufreq_governor_performance,
161 };
162
cpufreq_gov_performance_init(void)163 static int __init cpufreq_gov_performance_init(void)
164 {
165 return cpufreq_register_governor(&cpufreq_gov_performance);
166 }
167 __initcall(cpufreq_gov_performance_init);
168
169
170 /*
171 * cpufreq powersave governor
172 */
cpufreq_governor_powersave(struct cpufreq_policy * policy,unsigned int event)173 static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
174 unsigned int event)
175 {
176 int ret = 0;
177
178 if (!policy)
179 return -EINVAL;
180
181 switch (event) {
182 case CPUFREQ_GOV_START:
183 case CPUFREQ_GOV_STOP:
184 break;
185 case CPUFREQ_GOV_LIMITS:
186 ret = __cpufreq_driver_target(policy, policy->min,
187 CPUFREQ_RELATION_L);
188 break;
189 default:
190 ret = -EINVAL;
191 break;
192 }
193
194 return ret;
195 }
196
197 struct cpufreq_governor cpufreq_gov_powersave = {
198 .name = "powersave",
199 .governor = cpufreq_governor_powersave,
200 };
201
cpufreq_gov_powersave_init(void)202 static int __init cpufreq_gov_powersave_init(void)
203 {
204 return cpufreq_register_governor(&cpufreq_gov_powersave);
205 }
206 __initcall(cpufreq_gov_powersave_init);
207