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