ia64/xen-unstable

view xen/drivers/cpufreq/cpufreq.c @ 18745:85a2a54c70c8

cpufreq: Fix another build failure.
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 29 19:06:52 2008 +0000 (2008-10-29)
parents 6a8fea290af5
children 303b1014f91e
line source
1 /*
2 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
3 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
4 * Copyright (C) 2002 - 2004 Dominik Brodowski <linux@brodo.de>
5 * Copyright (C) 2006 Denis Sadykov <denis.m.sadykov@intel.com>
6 *
7 * Feb 2008 - Liu Jinsong <jinsong.liu@intel.com>
8 * Add cpufreq limit change handle and per-cpu cpufreq add/del
9 * to cope with cpu hotplug
10 *
11 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or (at
16 * your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 *
27 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
28 */
30 #include <xen/types.h>
31 #include <xen/errno.h>
32 #include <xen/delay.h>
33 #include <xen/cpumask.h>
34 #include <xen/list.h>
35 #include <xen/sched.h>
36 #include <xen/timer.h>
37 #include <xen/xmalloc.h>
38 #include <xen/guest_access.h>
39 #include <xen/domain.h>
40 #include <asm/bug.h>
41 #include <asm/io.h>
42 #include <asm/config.h>
43 #include <asm/processor.h>
44 #include <asm/percpu.h>
45 #include <acpi/acpi.h>
46 #include <acpi/cpufreq/cpufreq.h>
48 struct cpufreq_dom {
49 unsigned int dom;
50 cpumask_t map;
51 struct list_head node;
52 };
53 static LIST_HEAD(cpufreq_dom_list_head);
55 int cpufreq_limit_change(unsigned int cpu)
56 {
57 struct processor_performance *perf = &processor_pminfo[cpu]->perf;
58 struct cpufreq_policy *data = cpufreq_cpu_policy[cpu];
59 struct cpufreq_policy policy;
61 if (!cpu_online(cpu) || !data || !processor_pminfo[cpu])
62 return -ENODEV;
64 if ((perf->platform_limit < 0) ||
65 (perf->platform_limit >= perf->state_count))
66 return -EINVAL;
68 memcpy(&policy, data, sizeof(struct cpufreq_policy));
70 policy.max =
71 perf->states[perf->platform_limit].core_frequency * 1000;
73 return __cpufreq_set_policy(data, &policy);
74 }
76 int cpufreq_add_cpu(unsigned int cpu)
77 {
78 int ret = 0;
79 unsigned int firstcpu;
80 unsigned int dom, domexist = 0;
81 unsigned int j;
82 struct list_head *pos;
83 struct cpufreq_dom *cpufreq_dom = NULL;
84 struct cpufreq_policy new_policy;
85 struct cpufreq_policy *policy;
86 struct processor_performance *perf = &processor_pminfo[cpu]->perf;
88 /* to protect the case when Px was not controlled by xen */
89 if (!processor_pminfo[cpu] ||
90 !(perf->init & XEN_PX_INIT) ||
91 !cpu_online(cpu))
92 return -EINVAL;
94 if (cpufreq_cpu_policy[cpu])
95 return 0;
97 ret = cpufreq_statistic_init(cpu);
98 if (ret)
99 return ret;
101 dom = perf->domain_info.domain;
103 list_for_each(pos, &cpufreq_dom_list_head) {
104 cpufreq_dom = list_entry(pos, struct cpufreq_dom, node);
105 if (dom == cpufreq_dom->dom) {
106 domexist = 1;
107 break;
108 }
109 }
111 if (domexist) {
112 /* share policy with the first cpu since on same boat */
113 firstcpu = first_cpu(cpufreq_dom->map);
114 policy = cpufreq_cpu_policy[firstcpu];
116 cpufreq_cpu_policy[cpu] = policy;
117 cpu_set(cpu, cpufreq_dom->map);
118 cpu_set(cpu, policy->cpus);
120 printk(KERN_EMERG"adding CPU %u\n", cpu);
121 } else {
122 cpufreq_dom = xmalloc(struct cpufreq_dom);
123 if (!cpufreq_dom) {
124 cpufreq_statistic_exit(cpu);
125 return -ENOMEM;
126 }
127 memset(cpufreq_dom, 0, sizeof(struct cpufreq_dom));
128 cpufreq_dom->dom = dom;
129 cpu_set(cpu, cpufreq_dom->map);
130 list_add(&cpufreq_dom->node, &cpufreq_dom_list_head);
132 /* for the first cpu, setup policy and do init work */
133 policy = xmalloc(struct cpufreq_policy);
134 if (!policy) {
135 list_del(&cpufreq_dom->node);
136 xfree(cpufreq_dom);
137 cpufreq_statistic_exit(cpu);
138 return -ENOMEM;
139 }
140 memset(policy, 0, sizeof(struct cpufreq_policy));
141 policy->cpu = cpu;
142 cpu_set(cpu, policy->cpus);
143 cpufreq_cpu_policy[cpu] = policy;
145 ret = cpufreq_driver->init(policy);
146 if (ret)
147 goto err1;
148 printk(KERN_EMERG"CPU %u initialization completed\n", cpu);
149 }
151 /*
152 * After get full cpumap of the coordination domain,
153 * we can safely start gov here.
154 */
155 if (cpus_weight(cpufreq_dom->map) ==
156 perf->domain_info.num_processors) {
157 memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
158 policy->governor = NULL;
159 ret = __cpufreq_set_policy(policy, &new_policy);
160 if (ret)
161 goto err2;
162 }
164 return 0;
166 err2:
167 cpufreq_driver->exit(policy);
168 err1:
169 for_each_cpu_mask(j, cpufreq_dom->map) {
170 cpufreq_cpu_policy[j] = NULL;
171 cpufreq_statistic_exit(j);
172 }
174 list_del(&cpufreq_dom->node);
175 xfree(cpufreq_dom);
176 xfree(policy);
177 return ret;
178 }
180 int cpufreq_del_cpu(unsigned int cpu)
181 {
182 unsigned int dom, domexist = 0;
183 struct list_head *pos;
184 struct cpufreq_dom *cpufreq_dom = NULL;
185 struct cpufreq_policy *policy;
186 struct processor_performance *perf = &processor_pminfo[cpu]->perf;
188 /* to protect the case when Px was not controlled by xen */
189 if (!processor_pminfo[cpu] ||
190 !(perf->init & XEN_PX_INIT) ||
191 !cpu_online(cpu))
192 return -EINVAL;
194 if (!cpufreq_cpu_policy[cpu])
195 return 0;
197 dom = perf->domain_info.domain;
198 policy = cpufreq_cpu_policy[cpu];
200 list_for_each(pos, &cpufreq_dom_list_head) {
201 cpufreq_dom = list_entry(pos, struct cpufreq_dom, node);
202 if (dom == cpufreq_dom->dom) {
203 domexist = 1;
204 break;
205 }
206 }
208 if (!domexist)
209 return -EINVAL;
211 /* for the first cpu of the domain, stop gov */
212 if (cpus_weight(cpufreq_dom->map) ==
213 perf->domain_info.num_processors)
214 __cpufreq_governor(policy, CPUFREQ_GOV_STOP);
216 cpufreq_cpu_policy[cpu] = NULL;
217 cpu_clear(cpu, policy->cpus);
218 cpu_clear(cpu, cpufreq_dom->map);
219 cpufreq_statistic_exit(cpu);
221 /* for the last cpu of the domain, clean room */
222 /* It's safe here to free freq_table, drv_data and policy */
223 if (!cpus_weight(cpufreq_dom->map)) {
224 cpufreq_driver->exit(policy);
225 list_del(&cpufreq_dom->node);
226 xfree(cpufreq_dom);
227 xfree(policy);
228 }
230 printk(KERN_EMERG"deleting CPU %u\n", cpu);
231 return 0;
232 }
234 static void print_PCT(struct xen_pct_register *ptr)
235 {
236 printk(KERN_INFO "\t_PCT: descriptor=%d, length=%d, space_id=%d, "
237 "bit_width=%d, bit_offset=%d, reserved=%d, address=%"PRId64"\n",
238 ptr->descriptor, ptr->length, ptr->space_id, ptr->bit_width,
239 ptr->bit_offset, ptr->reserved, ptr->address);
240 }
242 static void print_PSS(struct xen_processor_px *ptr, int count)
243 {
244 int i;
245 printk(KERN_INFO "\t_PSS: state_count=%d\n", count);
246 for (i=0; i<count; i++){
247 printk(KERN_INFO "\tState%d: %"PRId64"MHz %"PRId64"mW %"PRId64"us "
248 "%"PRId64"us 0x%"PRIx64" 0x%"PRIx64"\n",
249 i,
250 ptr[i].core_frequency,
251 ptr[i].power,
252 ptr[i].transition_latency,
253 ptr[i].bus_master_latency,
254 ptr[i].control,
255 ptr[i].status
256 );
257 }
258 }
260 static void print_PSD( struct xen_psd_package *ptr)
261 {
262 printk(KERN_INFO "\t_PSD: num_entries=%"PRId64" rev=%"PRId64
263 " domain=%"PRId64" coord_type=%"PRId64" num_processors=%"PRId64"\n",
264 ptr->num_entries, ptr->revision, ptr->domain, ptr->coord_type,
265 ptr->num_processors);
266 }
268 static void print_PPC(unsigned int platform_limit)
269 {
270 printk(KERN_INFO "\t_PPC: %d\n", platform_limit);
271 }
273 int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *dom0_px_info)
274 {
275 int ret=0, cpuid;
276 struct processor_pminfo *pmpt;
277 struct processor_performance *pxpt;
279 cpuid = get_cpu_id(acpi_id);
280 if ( cpuid < 0 || !dom0_px_info)
281 {
282 ret = -EINVAL;
283 goto out;
284 }
285 printk(KERN_INFO "Set CPU acpi_id(%d) cpuid(%d) Px State info:\n",
286 acpi_id, cpuid);
288 pmpt = processor_pminfo[cpuid];
289 if ( !pmpt )
290 {
291 pmpt = xmalloc(struct processor_pminfo);
292 if ( !pmpt )
293 {
294 ret = -ENOMEM;
295 goto out;
296 }
297 memset(pmpt, 0, sizeof(*pmpt));
298 processor_pminfo[cpuid] = pmpt;
299 }
300 pxpt = &pmpt->perf;
301 pmpt->acpi_id = acpi_id;
302 pmpt->id = cpuid;
304 if ( dom0_px_info->flags & XEN_PX_PCT )
305 {
306 memcpy ((void *)&pxpt->control_register,
307 (void *)&dom0_px_info->control_register,
308 sizeof(struct xen_pct_register));
309 memcpy ((void *)&pxpt->status_register,
310 (void *)&dom0_px_info->status_register,
311 sizeof(struct xen_pct_register));
312 print_PCT(&pxpt->control_register);
313 print_PCT(&pxpt->status_register);
314 }
315 if ( dom0_px_info->flags & XEN_PX_PSS )
316 {
317 if ( !(pxpt->states = xmalloc_array(struct xen_processor_px,
318 dom0_px_info->state_count)) )
319 {
320 ret = -ENOMEM;
321 goto out;
322 }
323 copy_from_guest(pxpt->states, dom0_px_info->states,
324 dom0_px_info->state_count);
325 pxpt->state_count = dom0_px_info->state_count;
326 print_PSS(pxpt->states,pxpt->state_count);
327 }
328 if ( dom0_px_info->flags & XEN_PX_PSD )
329 {
330 pxpt->shared_type = dom0_px_info->shared_type;
331 memcpy ((void *)&pxpt->domain_info,
332 (void *)&dom0_px_info->domain_info,
333 sizeof(struct xen_psd_package));
334 print_PSD(&pxpt->domain_info);
335 }
336 if ( dom0_px_info->flags & XEN_PX_PPC )
337 {
338 pxpt->platform_limit = dom0_px_info->platform_limit;
339 print_PPC(pxpt->platform_limit);
341 if ( pxpt->init == XEN_PX_INIT )
342 {
344 ret = cpufreq_limit_change(cpuid);
345 goto out;
346 }
347 }
349 if ( dom0_px_info->flags == ( XEN_PX_PCT | XEN_PX_PSS |
350 XEN_PX_PSD | XEN_PX_PPC ) )
351 {
352 pxpt->init = XEN_PX_INIT;
354 ret = cpufreq_cpu_init(cpuid);
355 goto out;
356 }
358 out:
359 return ret;
360 }