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