debuggers.hg

view xen/drivers/acpi/pmstat.c @ 20954:a06e9def02bb

xenpm: Allow user to enable/disable dbs governor turbo mode.

Signed-off-by: Lu Guanqun <guanqun.lu@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 08 08:48:40 2010 +0000 (2010-02-08)
parents bde24590c13a
children 6c3db6c83a02
line source
1 /*****************************************************************************
2 # pmstat.c - Power Management statistic information (Px/Cx/Tx, etc.)
3 #
4 # Copyright (c) 2008, Liu Jinsong <jinsong.liu@intel.com>
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; either version 2 of the License, or (at your option)
9 # any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 # more details.
15 #
16 # You should have received a copy of the GNU General Public License along with
17 # this program; if not, write to the Free Software Foundation, Inc., 59
18 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 #
20 # The full GNU General Public License is included in this distribution in the
21 # file called LICENSE.
22 #
23 *****************************************************************************/
25 #include <xen/config.h>
26 #include <xen/lib.h>
27 #include <xen/errno.h>
28 #include <xen/sched.h>
29 #include <xen/event.h>
30 #include <xen/irq.h>
31 #include <xen/iocap.h>
32 #include <xen/compat.h>
33 #include <xen/guest_access.h>
34 #include <asm/current.h>
35 #include <public/xen.h>
36 #include <xen/cpumask.h>
37 #include <asm/processor.h>
38 #include <xen/percpu.h>
39 #include <xen/domain.h>
40 #include <xen/acpi.h>
42 #include <public/sysctl.h>
43 #include <acpi/cpufreq/cpufreq.h>
44 #include <xen/pmstat.h>
46 struct pm_px *__read_mostly cpufreq_statistic_data[NR_CPUS];
48 extern struct list_head cpufreq_governor_list;
50 /*
51 * Get PM statistic info
52 */
53 int do_get_pm_info(struct xen_sysctl_get_pmstat *op)
54 {
55 int ret = 0;
56 const struct processor_pminfo *pmpt;
58 if ( !op || (op->cpuid >= NR_CPUS) || !cpu_online(op->cpuid) )
59 return -EINVAL;
60 pmpt = processor_pminfo[op->cpuid];
62 switch ( op->type & PMSTAT_CATEGORY_MASK )
63 {
64 case PMSTAT_CX:
65 if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_CX) )
66 return -ENODEV;
67 break;
68 case PMSTAT_PX:
69 if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
70 return -ENODEV;
71 if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
72 return -EINVAL;
73 break;
74 default:
75 return -ENODEV;
76 }
78 switch ( op->type )
79 {
80 case PMSTAT_get_max_px:
81 {
82 op->u.getpx.total = pmpt->perf.state_count;
83 break;
84 }
86 case PMSTAT_get_pxstat:
87 {
88 uint32_t ct;
89 struct pm_px *pxpt = cpufreq_statistic_data[op->cpuid];
90 spinlock_t *cpufreq_statistic_lock =
91 &per_cpu(cpufreq_statistic_lock, op->cpuid);
93 spin_lock(cpufreq_statistic_lock);
95 if ( !pxpt || !pxpt->u.pt || !pxpt->u.trans_pt )
96 {
97 spin_unlock(cpufreq_statistic_lock);
98 return -ENODATA;
99 }
101 pxpt->u.usable = pmpt->perf.state_count - pmpt->perf.platform_limit;
103 cpufreq_residency_update(op->cpuid, pxpt->u.cur);
105 ct = pmpt->perf.state_count;
106 if ( copy_to_guest(op->u.getpx.trans_pt, pxpt->u.trans_pt, ct*ct) )
107 {
108 spin_unlock(cpufreq_statistic_lock);
109 ret = -EFAULT;
110 break;
111 }
113 if ( copy_to_guest(op->u.getpx.pt, pxpt->u.pt, ct) )
114 {
115 spin_unlock(cpufreq_statistic_lock);
116 ret = -EFAULT;
117 break;
118 }
120 op->u.getpx.total = pxpt->u.total;
121 op->u.getpx.usable = pxpt->u.usable;
122 op->u.getpx.last = pxpt->u.last;
123 op->u.getpx.cur = pxpt->u.cur;
125 spin_unlock(cpufreq_statistic_lock);
127 break;
128 }
130 case PMSTAT_reset_pxstat:
131 {
132 cpufreq_statistic_reset(op->cpuid);
133 break;
134 }
136 #ifdef CONFIG_X86
137 case PMSTAT_get_max_cx:
138 {
139 op->u.getcx.nr = pmstat_get_cx_nr(op->cpuid);
140 ret = 0;
141 break;
142 }
144 case PMSTAT_get_cxstat:
145 {
146 ret = pmstat_get_cx_stat(op->cpuid, &op->u.getcx);
147 break;
148 }
150 case PMSTAT_reset_cxstat:
151 {
152 ret = pmstat_reset_cx_stat(op->cpuid);
153 break;
154 }
155 #endif
157 default:
158 printk("not defined sub-hypercall @ do_get_pm_info\n");
159 ret = -ENOSYS;
160 break;
161 }
163 return ret;
164 }
166 /*
167 * 1. Get PM parameter
168 * 2. Provide user PM control
169 */
170 static int read_scaling_available_governors(char *scaling_available_governors,
171 unsigned int size)
172 {
173 unsigned int i = 0;
174 struct cpufreq_governor *t;
176 if ( !scaling_available_governors )
177 return -EINVAL;
179 list_for_each_entry(t, &cpufreq_governor_list, governor_list)
180 {
181 i += scnprintf(&scaling_available_governors[i],
182 CPUFREQ_NAME_LEN, "%s ", t->name);
183 if ( i > size )
184 return -EINVAL;
185 }
186 scaling_available_governors[i-1] = '\0';
188 return 0;
189 }
191 static int get_cpufreq_para(struct xen_sysctl_pm_op *op)
192 {
193 uint32_t ret = 0;
194 const struct processor_pminfo *pmpt;
195 struct cpufreq_policy *policy;
196 uint32_t gov_num = 0;
197 uint32_t *affected_cpus;
198 uint32_t *scaling_available_frequencies;
199 char *scaling_available_governors;
200 struct list_head *pos;
201 uint32_t cpu, i, j = 0;
203 if ( !op || !cpu_online(op->cpuid) )
204 return -EINVAL;
205 pmpt = processor_pminfo[op->cpuid];
206 policy = cpufreq_cpu_policy[op->cpuid];
208 if ( !pmpt || !pmpt->perf.states ||
209 !policy || !policy->governor )
210 return -EINVAL;
212 list_for_each(pos, &cpufreq_governor_list)
213 gov_num++;
215 if ( (op->u.get_para.cpu_num != cpus_weight(policy->cpus)) ||
216 (op->u.get_para.freq_num != pmpt->perf.state_count) ||
217 (op->u.get_para.gov_num != gov_num) )
218 {
219 op->u.get_para.cpu_num = cpus_weight(policy->cpus);
220 op->u.get_para.freq_num = pmpt->perf.state_count;
221 op->u.get_para.gov_num = gov_num;
222 return -EAGAIN;
223 }
225 if ( !(affected_cpus = xmalloc_array(uint32_t, op->u.get_para.cpu_num)) )
226 return -ENOMEM;
227 memset(affected_cpus, 0, op->u.get_para.cpu_num * sizeof(uint32_t));
228 for_each_cpu_mask(cpu, policy->cpus)
229 affected_cpus[j++] = cpu;
230 ret = copy_to_guest(op->u.get_para.affected_cpus,
231 affected_cpus, op->u.get_para.cpu_num);
232 xfree(affected_cpus);
233 if ( ret )
234 return ret;
236 if ( !(scaling_available_frequencies =
237 xmalloc_array(uint32_t, op->u.get_para.freq_num)) )
238 return -ENOMEM;
239 memset(scaling_available_frequencies, 0,
240 op->u.get_para.freq_num * sizeof(uint32_t));
241 for ( i = 0; i < op->u.get_para.freq_num; i++ )
242 scaling_available_frequencies[i] =
243 pmpt->perf.states[i].core_frequency * 1000;
244 ret = copy_to_guest(op->u.get_para.scaling_available_frequencies,
245 scaling_available_frequencies, op->u.get_para.freq_num);
246 xfree(scaling_available_frequencies);
247 if ( ret )
248 return ret;
250 if ( !(scaling_available_governors =
251 xmalloc_array(char, gov_num * CPUFREQ_NAME_LEN)) )
252 return -ENOMEM;
253 memset(scaling_available_governors, 0,
254 gov_num * CPUFREQ_NAME_LEN * sizeof(char));
255 if ( (ret = read_scaling_available_governors(scaling_available_governors,
256 gov_num * CPUFREQ_NAME_LEN * sizeof(char))) )
257 {
258 xfree(scaling_available_governors);
259 return ret;
260 }
261 ret = copy_to_guest(op->u.get_para.scaling_available_governors,
262 scaling_available_governors, gov_num * CPUFREQ_NAME_LEN);
263 xfree(scaling_available_governors);
264 if ( ret )
265 return ret;
267 op->u.get_para.cpuinfo_cur_freq =
268 cpufreq_driver->get ? cpufreq_driver->get(op->cpuid) : policy->cur;
269 op->u.get_para.cpuinfo_max_freq = policy->cpuinfo.max_freq;
270 op->u.get_para.cpuinfo_min_freq = policy->cpuinfo.min_freq;
271 op->u.get_para.scaling_cur_freq = policy->cur;
272 op->u.get_para.scaling_max_freq = policy->max;
273 op->u.get_para.scaling_min_freq = policy->min;
275 if ( cpufreq_driver->name )
276 strlcpy(op->u.get_para.scaling_driver,
277 cpufreq_driver->name, CPUFREQ_NAME_LEN);
278 else
279 strlcpy(op->u.get_para.scaling_driver, "Unknown", CPUFREQ_NAME_LEN);
281 if ( policy->governor->name )
282 strlcpy(op->u.get_para.scaling_governor,
283 policy->governor->name, CPUFREQ_NAME_LEN);
284 else
285 strlcpy(op->u.get_para.scaling_governor, "Unknown", CPUFREQ_NAME_LEN);
287 /* governor specific para */
288 if ( !strnicmp(op->u.get_para.scaling_governor,
289 "userspace", CPUFREQ_NAME_LEN) )
290 {
291 op->u.get_para.u.userspace.scaling_setspeed = policy->cur;
292 }
294 if ( !strnicmp(op->u.get_para.scaling_governor,
295 "ondemand", CPUFREQ_NAME_LEN) )
296 {
297 ret = get_cpufreq_ondemand_para(
298 &op->u.get_para.u.ondemand.sampling_rate_max,
299 &op->u.get_para.u.ondemand.sampling_rate_min,
300 &op->u.get_para.u.ondemand.sampling_rate,
301 &op->u.get_para.u.ondemand.up_threshold);
302 op->u.get_para.u.ondemand.turbo_enabled =
303 cpufreq_dbs_get_turbo_status(op->cpuid);
304 }
306 return ret;
307 }
309 static int set_cpufreq_gov(struct xen_sysctl_pm_op *op)
310 {
311 struct cpufreq_policy new_policy, *old_policy;
313 if ( !op || !cpu_online(op->cpuid) )
314 return -EINVAL;
316 old_policy = cpufreq_cpu_policy[op->cpuid];
317 if ( !old_policy )
318 return -EINVAL;
320 memcpy(&new_policy, old_policy, sizeof(struct cpufreq_policy));
322 new_policy.governor = __find_governor(op->u.set_gov.scaling_governor);
323 if (new_policy.governor == NULL)
324 return -EINVAL;
326 return __cpufreq_set_policy(old_policy, &new_policy);
327 }
329 static int set_cpufreq_para(struct xen_sysctl_pm_op *op)
330 {
331 int ret = 0;
332 struct cpufreq_policy *policy;
334 if ( !op || !cpu_online(op->cpuid) )
335 return -EINVAL;
336 policy = cpufreq_cpu_policy[op->cpuid];
338 if ( !policy || !policy->governor )
339 return -EINVAL;
341 switch(op->u.set_para.ctrl_type)
342 {
343 case SCALING_MAX_FREQ:
344 {
345 struct cpufreq_policy new_policy;
347 memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
348 new_policy.max = op->u.set_para.ctrl_value;
349 ret = __cpufreq_set_policy(policy, &new_policy);
351 break;
352 }
354 case SCALING_MIN_FREQ:
355 {
356 struct cpufreq_policy new_policy;
358 memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
359 new_policy.min = op->u.set_para.ctrl_value;
360 ret = __cpufreq_set_policy(policy, &new_policy);
362 break;
363 }
365 case SCALING_SETSPEED:
366 {
367 unsigned int freq =op->u.set_para.ctrl_value;
369 if ( !strnicmp(policy->governor->name,
370 "userspace", CPUFREQ_NAME_LEN) )
371 ret = write_userspace_scaling_setspeed(op->cpuid, freq);
372 else
373 ret = -EINVAL;
375 break;
376 }
378 case SAMPLING_RATE:
379 {
380 unsigned int sampling_rate = op->u.set_para.ctrl_value;
382 if ( !strnicmp(policy->governor->name,
383 "ondemand", CPUFREQ_NAME_LEN) )
384 ret = write_ondemand_sampling_rate(sampling_rate);
385 else
386 ret = -EINVAL;
388 break;
389 }
391 case UP_THRESHOLD:
392 {
393 unsigned int up_threshold = op->u.set_para.ctrl_value;
395 if ( !strnicmp(policy->governor->name,
396 "ondemand", CPUFREQ_NAME_LEN) )
397 ret = write_ondemand_up_threshold(up_threshold);
398 else
399 ret = -EINVAL;
401 break;
402 }
404 default:
405 ret = -EINVAL;
406 break;
407 }
409 return ret;
410 }
412 static int get_cpufreq_avgfreq(struct xen_sysctl_pm_op *op)
413 {
414 if ( !op || !cpu_online(op->cpuid) )
415 return -EINVAL;
417 op->u.get_avgfreq = cpufreq_driver_getavg(op->cpuid, USR_GETAVG);
419 return 0;
420 }
422 static int get_cputopo (struct xen_sysctl_pm_op *op)
423 {
424 uint32_t i, nr_cpus;
425 XEN_GUEST_HANDLE_64(uint32) cpu_to_core_arr;
426 XEN_GUEST_HANDLE_64(uint32) cpu_to_socket_arr;
427 int arr_size, ret=0;
429 cpu_to_core_arr = op->u.get_topo.cpu_to_core;
430 cpu_to_socket_arr = op->u.get_topo.cpu_to_socket;
431 arr_size= min_t(uint32_t, op->u.get_topo.max_cpus, NR_CPUS);
433 if ( guest_handle_is_null( cpu_to_core_arr ) ||
434 guest_handle_is_null( cpu_to_socket_arr) )
435 {
436 ret = -EINVAL;
437 goto out;
438 }
440 nr_cpus = 0;
441 for ( i = 0; i < arr_size; i++ )
442 {
443 uint32_t core, socket;
444 if ( cpu_online(i) )
445 {
446 core = cpu_to_core(i);
447 socket = cpu_to_socket(i);
448 nr_cpus = i;
449 }
450 else
451 {
452 core = socket = INVALID_TOPOLOGY_ID;
453 }
455 if ( copy_to_guest_offset(cpu_to_core_arr, i, &core, 1) ||
456 copy_to_guest_offset(cpu_to_socket_arr, i, &socket, 1))
457 {
458 ret = -EFAULT;
459 goto out;
460 }
461 }
463 op->u.get_topo.nr_cpus = nr_cpus + 1;
464 out:
465 return ret;
466 }
468 int do_pm_op(struct xen_sysctl_pm_op *op)
469 {
470 int ret = 0;
471 const struct processor_pminfo *pmpt;
473 if ( !op || !cpu_online(op->cpuid) )
474 return -EINVAL;
475 pmpt = processor_pminfo[op->cpuid];
477 switch ( op->cmd & PM_PARA_CATEGORY_MASK )
478 {
479 case CPUFREQ_PARA:
480 if ( !(xen_processor_pmbits & XEN_PROCESSOR_PM_PX) )
481 return -ENODEV;
482 if ( !pmpt || !(pmpt->perf.init & XEN_PX_INIT) )
483 return -EINVAL;
484 break;
485 }
487 switch ( op->cmd )
488 {
489 case GET_CPUFREQ_PARA:
490 {
491 ret = get_cpufreq_para(op);
492 break;
493 }
495 case SET_CPUFREQ_GOV:
496 {
497 ret = set_cpufreq_gov(op);
498 break;
499 }
501 case SET_CPUFREQ_PARA:
502 {
503 ret = set_cpufreq_para(op);
504 break;
505 }
507 case GET_CPUFREQ_AVGFREQ:
508 {
509 ret = get_cpufreq_avgfreq(op);
510 break;
511 }
513 case XEN_SYSCTL_pm_op_get_cputopo:
514 {
515 ret = get_cputopo(op);
516 break;
517 }
519 case XEN_SYSCTL_pm_op_set_sched_opt_smt:
520 {
521 uint32_t saved_value;
523 saved_value = sched_smt_power_savings;
524 sched_smt_power_savings = !!op->u.set_sched_opt_smt;
525 op->u.set_sched_opt_smt = saved_value;
527 break;
528 }
530 case XEN_SYSCTL_pm_op_set_vcpu_migration_delay:
531 {
532 set_vcpu_migration_delay(op->u.set_vcpu_migration_delay);
533 break;
534 }
536 case XEN_SYSCTL_pm_op_get_vcpu_migration_delay:
537 {
538 op->u.get_vcpu_migration_delay = get_vcpu_migration_delay();
539 break;
540 }
542 case XEN_SYSCTL_pm_op_get_max_cstate:
543 {
544 op->u.get_max_cstate = acpi_get_cstate_limit();
545 break;
546 }
548 case XEN_SYSCTL_pm_op_set_max_cstate:
549 {
550 acpi_set_cstate_limit(op->u.set_max_cstate);
551 break;
552 }
554 case XEN_SYSCTL_pm_op_enable_turbo:
555 {
556 cpufreq_dbs_enable_turbo(op->cpuid);
557 break;
558 }
560 case XEN_SYSCTL_pm_op_disable_turbo:
561 {
562 cpufreq_dbs_disable_turbo(op->cpuid);
563 break;
564 }
566 default:
567 printk("not defined sub-hypercall @ do_pm_op\n");
568 ret = -ENOSYS;
569 break;
570 }
572 return ret;
573 }