2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2014, the V3VEE Project <http://www.v3vee.org>
11 * all rights reserved.
13 * Author: Kyle C. Hale <kh@u.northwestern.edu>
14 * Shiva Rao <shiva.rao.717@gmail.com>
15 * Peter Dinda <pdinda@northwestern.edu>
17 * This is free software. you are permitted to use,
18 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 #include <linux/uaccess.h>
22 #include <linux/seq_file.h>
23 #include <linux/proc_fs.h>
24 #include <linux/cpufreq.h>
25 #include <asm/processor.h>
27 #include <asm/msr-index.h>
29 #include <interfaces/vmm_pstate_ctrl.h>
32 #include "iface-pstate-ctrl.h"
34 #include "linux-exts.h"
37 This P-STATE control implementation includes:
39 - Direct control of Intel and AMD processor pstates
40 - External control of processor states via Linux (unimplemented)
41 - Internal control of processor states in Palacios (handoff from Linux)
43 Additionally, it provides a user-space interface for manipulating
44 p-state regardless of the host's functionality. This includes
45 an ioctl for commanding the implementation and a /proc file for
46 showing current status and capabilities.
53 struct pstate_core_info {
54 // Here we have the notion of host control
55 #define V3_PSTATE_HOST_CONTROL 0
56 // and all the modes from the Palacios interface:
57 // V3_PSTATE_EXTERNAL_CONTROL
58 // V3_PSTATE_DIRECT_CONTROL
59 // V3_PSTATE_INTERNAL_CONTROL
62 // Apply if we are under the DIRECT state
67 uint8_t cur_hw_pstate;
69 // Apply if we are under the EXTERNAL state
70 uint64_t cur_freq_khz;
71 uint64_t max_freq_khz;
72 uint64_t min_freq_khz;
74 // Intel-specific for DIRECT state
75 uint8_t turbo_disabled;
83 static DEFINE_PER_CPU(struct pstate_core_info, core_state);
86 // These are used to assert DIRECT control over the core pstates
87 struct pstate_core_funcs {
88 void (*arch_init)(void);
89 void (*arch_deinit)(void);
90 uint8_t (*get_min_pstate)(void);
91 uint8_t (*get_max_pstate)(void);
92 uint8_t (*get_pstate)(void);
93 void (*set_pstate)(uint8_t pstate);
96 struct pstate_machine_info {
97 enum {INTEL, AMD, OTHER } arch;
99 // used for DIRECT control
100 struct pstate_core_funcs *funcs;
103 static struct pstate_machine_info machine_state;
106 /****************************************************
108 ***************************************************/
110 /* AMD Programmer's Manual Vol 2 (Rev 3, 2013), Sec. 17.1, pp.557 */
111 #define MSR_PSTATE_LIMIT_REG_AMD 0xc0010061
112 #define MSR_PSTATE_CTL_REG_AMD 0xc0010062
113 #define MSR_PSTATE_STAT_REG_AMD 0xc0010063
115 struct p_state_limit_reg_amd {
119 uint8_t pstate_limit : 4; /* lowest P-state value (highest perf.) supported currently (this can change at runtime) */
120 uint8_t pstate_max : 4; /* highest P-state value supported (lowest perf) */
123 } __attribute__((packed));
124 } __attribute__((packed));
127 struct p_state_stat_reg_amd {
134 } __attribute__((packed));
135 } __attribute__((packed));
138 struct p_state_ctl_reg_amd {
145 } __attribute__((packed));
146 } __attribute__((packed));
149 /* CPUID Fn8000_0007_EDX[HwPstate(7)] = 1 */
150 static uint8_t supports_pstates_amd (void)
152 uint32_t eax, ebx, ecx, edx;
153 cpuid(0x80000007, &eax, &ebx, &ecx, &edx);
154 return !!(edx & (1 << 7));
157 static void init_arch_amd(void)
159 /* KCH: nothing to do here */
162 static void deinit_arch_amd(void)
164 /* KCH: nothing to do here */
167 static uint8_t get_pstate_amd(void)
169 struct p_state_stat_reg_amd pstat;
171 rdmsrl(MSR_PSTATE_STAT_REG_AMD, pstat.val);
173 get_cpu_var(core_state).cur_pstate=pstat.reg.pstate;
174 put_cpu_var(core_state);
176 return pstat.reg.pstate;
179 static void set_pstate_amd(uint8_t p)
181 struct p_state_ctl_reg_amd pctl;
185 wrmsrl(MSR_PSTATE_CTL_REG_AMD, pctl.val);
187 get_cpu_var(core_state).cur_pstate=p;
188 put_cpu_var(core_state);
192 * NOTE: HW may change this value at runtime
194 static uint8_t get_max_pstate_amd(void)
196 struct p_state_limit_reg_amd plimits;
198 rdmsrl(MSR_PSTATE_LIMIT_REG_AMD, plimits.val);
200 return plimits.reg.pstate_max;
204 static uint8_t get_min_pstate_amd(void)
206 struct p_state_limit_reg_amd plimits;
208 rdmsrl(MSR_PSTATE_LIMIT_REG_AMD, plimits.val);
210 return plimits.reg.pstate_limit;
214 static struct pstate_core_funcs amd_funcs =
216 .arch_init = init_arch_amd,
217 .arch_deinit = deinit_arch_amd,
218 .get_pstate = get_pstate_amd,
219 .set_pstate = set_pstate_amd,
220 .get_max_pstate = get_max_pstate_amd,
221 .get_min_pstate = get_min_pstate_amd,
226 /***********************************************************
228 **********************************************************/
231 /* Intel System Programmer's Manual Vol. 3B, 14-2 */
232 #define MSR_MPERF_IA32 0x000000e7
233 #define MSR_APERF_IA32 0x000000e8
234 #define MSR_MISC_ENABLE_IA32 0x000001a0
235 #define MSR_NHM_TURBO_RATIO_LIMIT 0x000001ad
236 #define MSR_PLATFORM_INFO_IA32 0x000000ce
237 #define MSR_PERF_CTL_IA32 0x00000199
241 struct turbo_mode_info_reg_intel {
246 uint8_t max_noturbo_ratio;
248 uint8_t ratio_limit : 1;
249 uint8_t tdc_tdp_limit : 1;
254 } __attribute__((packed));
255 } __attribute__((packed));
258 /* CPUID.01:ECX.AES(7) */
259 static uint8_t supports_pstates_intel(void)
261 /* NOTE: CPUID.06H:ECX.SETBH[bit 3] is set and it also implies the presence of a new architectural MSR called IA32_ENERGY_PERF_BIAS (1B0H).
263 uint32_t eax, ebx, ecx, edx;
264 cpuid(0x1, &eax, &ebx, &ecx, &edx);
265 return !!(ecx & (1 << 7));
269 static void init_arch_intel(void)
273 rdmsrl(MSR_MISC_ENABLE_IA32, val);
277 wrmsrl(MSR_MISC_ENABLE_IA32, val);
281 static void deinit_arch_intel(void)
286 /* TODO: Intel P-states require sampling at intervals... */
287 static uint8_t get_pstate_intel(void)
291 // This should read the HW...
292 pstate=get_cpu_var(core_state).cur_pstate;
293 put_cpu_var(core_state);
297 static void set_pstate_intel(uint8_t p)
299 uint64_t val = ((uint64_t)p) << 8;
301 /* ...Intel IDA (dynamic acceleration)
302 if (c->no_turbo && !c->turbo_disabled) {
307 wrmsrl(MSR_PERF_CTL_IA32, val);
309 get_cpu_var(core_state).cur_pstate = p;
310 put_cpu_var(core_state);
314 static uint8_t get_min_pstate_intel(void)
316 struct turbo_mode_info_reg_intel t;
318 rdmsrl(MSR_PLATFORM_INFO_IA32, t.val);
320 return t.reg.min_ratio;
325 static uint8_t get_max_pstate_intel (void)
327 struct turbo_mode_info_reg_intel t;
329 rdmsrl(MSR_PLATFORM_INFO_IA32, t.val);
331 return t.reg.max_noturbo_ratio;
334 static struct pstate_core_funcs intel_funcs =
336 .arch_init = init_arch_intel,
337 .arch_deinit = deinit_arch_intel,
338 .get_pstate = get_pstate_intel,
339 .set_pstate = set_pstate_intel,
340 .get_max_pstate = get_max_pstate_intel,
341 .get_min_pstate = get_min_pstate_intel,
346 /***********************************************
347 Arch determination and setup
348 ***********************************************/
350 static inline void cpuid_string (uint32_t id, uint32_t dest[4])
353 :"=a"(*dest),"=b"(*(dest+1)),"=c"(*(dest+2)),"=d"(*(dest+3))
358 static int get_cpu_vendor (char name[13])
363 cpuid_string(0,dest);
365 ((uint32_t*)name)[0]=dest[1];
366 ((uint32_t*)name)[1]=dest[3];
367 ((uint32_t*)name)[2]=dest[2];
374 static int is_intel (void)
377 get_cpu_vendor(name);
378 return !strcmp(name,"GenuineIntel");
382 static int is_amd (void)
385 get_cpu_vendor(name);
386 return !strcmp(name,"AuthenticAMD");
389 static int pstate_arch_setup(void)
393 machine_state.arch = AMD;
394 machine_state.funcs = &amd_funcs;
395 machine_state.supports_pstates = supports_pstates_amd();
396 INFO("PSTATE: P-State initialized for AMD\n");
397 } else if (is_intel()) {
398 machine_state.arch = INTEL;
399 machine_state.funcs = &intel_funcs;
400 machine_state.supports_pstates = supports_pstates_intel();
401 INFO("PSTATE: P-State initialized for INTEL (Work in progress...)\n");
405 machine_state.arch = OTHER;
406 machine_state.funcs = NULL;
407 machine_state.supports_pstates = 0;
408 INFO("PSTATE: P-state control: No support for direct control on this architecture\n");
417 /******************************************************************
419 *****************************************************************/
422 // The purpose of the stub governor is the pretend to keep
423 // the processor at the maximum frequency, while we manipulate he
424 // processor ccre directly
425 static int governor_run(struct cpufreq_policy *policy, unsigned int event)
428 case CPUFREQ_GOV_START:
429 case CPUFREQ_GOV_STOP:
430 cpu_freq_driver_target(policy, policy->max_freq);
432 case CPUFREQ_GOV_LIMITS:
436 static struct cpufreq_governor stub_governor =
438 .name="PALACIOS_STUB",
439 .governor=governor_run,
443 static void linux_init(void)
447 // change to userspace governor - or change to our do nothing governor? (call set_speed)
448 // stash the old governor
449 // tell governor to do max freq
453 static void linux_deinit(void)
457 static uint8_t linux_get_pstate(void)
462 static void linux_set_pstate(uint8_t p)
466 static void linux_restore_defaults(void)
473 /******************************************************************
474 Generic Interface as provided to Palacios and to the rest of the
476 ******************************************************************/
478 static void init_core(void)
481 struct cpufreq_policy *p;
484 DEBUG("P-State Core Init\n");
486 get_cpu_var(core_state).mode = V3_PSTATE_HOST_CONTROL;
487 get_cpu_var(core_state).cur_pstate = 0;
489 if (machine_state.funcs) {
490 get_cpu_var(core_state).min_pstate = machine_state.funcs->get_min_pstate();
491 get_cpu_var(core_state).max_pstate = machine_state.funcs->get_max_pstate();
493 get_cpu_var(core_state).min_pstate = 0;
494 get_cpu_var(core_state).max_pstate = 0;
498 cpu = get_cpu(); put_cpu();
500 p = cpufreq_cpu_get(cpu);
503 get_cpu_var(core_state).have_cpufreq = 0;
504 get_cpu_var(core_state).min_freq_khz=0;
505 get_cpu_var(core_state).max_freq_khz=0;
506 get_cpu_var(core_state).cur_freq_khz=0;
508 get_cpu_var(core_state).have_cpufreq = 1;
509 get_cpu_var(core_state).min_freq_khz=p->min;
510 get_cpu_var(core_state).max_freq_khz=p->max;
511 get_cpu_var(core_state).cur_freq_khz=p->cur;
515 put_cpu_var(core_state);
520 void palacios_pstate_ctrl_release(void);
523 static void deinit_core(void)
525 DEBUG("P-State Core Deinit\n");
526 palacios_pstate_ctrl_release();
531 void palacios_pstate_ctrl_get_chars(struct v3_cpu_pstate_chars *c)
533 memset(c,0,sizeof(struct v3_cpu_pstate_chars));
536 c->features = V3_PSTATE_INTERNAL_CONTROL;
538 if (get_cpu_var(core_state).have_cpufreq) {
539 c->features |= V3_PSTATE_EXTERNAL_CONTROL;
542 if (machine_state.arch==AMD || machine_state.arch==INTEL) {
543 c->features |= V3_PSTATE_DIRECT_CONTROL;
545 c->cur_mode = get_cpu_var(core_state).mode;
546 c->min_pstate = get_cpu_var(core_state).min_pstate;
547 c->max_pstate = get_cpu_var(core_state).max_pstate;
548 c->cur_pstate = get_cpu_var(core_state).cur_pstate;
549 c->min_freq_khz = get_cpu_var(core_state).min_freq_khz;
550 c->max_freq_khz = get_cpu_var(core_state).max_freq_khz;
551 c->cur_freq_khz = get_cpu_var(core_state).cur_freq_khz;
553 put_cpu_var(core_state);
560 uint8_t palacios_pstate_ctrl_get_pstate(void)
562 if (get_cpu_var(core_state).mode==V3_PSTATE_DIRECT_CONTROL) {
563 put_cpu_var(core_state);
564 return machine_state.funcs->get_pstate();
566 put_cpu_var(core_state);
571 void palacios_pstate_ctrl_set_pstate(uint8_t p)
573 if (get_cpu_var(core_state).mode==V3_PSTATE_DIRECT_CONTROL) {
574 put_cpu_var(core_state);
575 machine_state.funcs->set_pstate(p);
580 void palacios_pstate_ctrl_set_pstate_wrapper(void *p)
582 palacios_pstate_ctrl_set_pstate((uint8_t)(uint64_t)p);
585 uint64_t palacios_pstate_ctrl_get_freq(void)
587 if (get_cpu_var(core_state).mode==V3_PSTATE_EXTERNAL_CONTROL) {
588 put_cpu_var(core_state);
589 ERROR("Unimplemented get freq\n");
592 put_cpu_var(core_state);
597 void palacios_pstate_ctrl_set_freq(uint64_t p)
599 if (get_cpu_var(core_state).mode==V3_PSTATE_EXTERNAL_CONTROL) {
600 put_cpu_var(core_state);
601 ERROR("Unimplemented set freq\n");
603 put_cpu_var(core_state);
608 static void switch_to_external(void)
610 if (!(get_cpu_var(core_state).have_cpufreq)) {
611 put_cpu_var(core_state);
612 ERROR("No cpufreq - cannot switch to external...\n");
615 put_cpu_var(core_state);
617 ERROR("Unimplemented switch to external...\n");
620 static void switch_to_direct(void)
622 if (get_cpu_var(core_state).have_cpufreq) {
623 put_cpu_var(core_state);
624 ERROR("Unimplemented: switch to direct on machine with cpu freq\n");
625 // The implementation would set the policy and governor to peg cpu
626 // regardless of load
629 if (machine_state.funcs && machine_state.funcs->arch_init) {
630 get_cpu_var(core_state).mode=V3_PSTATE_DIRECT_CONTROL;
632 machine_state.funcs->arch_init();
634 put_cpu_var(core_state);
640 static void switch_to_internal(void)
642 if (get_cpu_var(core_state).have_cpufreq) {
643 put_cpu_var(core_state);
644 ERROR("Unimplemented: switch to internal on machine with cpu freq\n");
646 // The implementation would set the policy and governor to peg cpu
647 // regardless of load - exactly like direct
650 get_cpu_var(core_state).mode=V3_PSTATE_INTERNAL_CONTROL;
652 put_cpu_var(core_state);
658 static void switch_from_external(void)
660 if (!(get_cpu_var(core_state).have_cpufreq)) {
661 put_cpu_var(core_state);
662 ERROR("No cpufreq - how did we get here... external...\n");
666 ERROR("Unimplemented switch from external...\n");
668 get_cpu_var(core_state).mode = V3_PSTATE_HOST_CONTROL;
670 put_cpu_var(core_state);
674 static void switch_from_direct(void)
677 if (get_cpu_var(core_state).have_cpufreq) {
678 put_cpu_var(core_state);
679 ERROR("Unimplemented: switch from direct on machine with cpu freq - will just pretend to do so\n");
680 // The implementation would switch back to default policy and governor
683 get_cpu_var(core_state).mode=V3_PSTATE_HOST_CONTROL;
686 machine_state.funcs->set_pstate(get_cpu_var(core_state).min_pstate);
688 machine_state.funcs->arch_deinit();
690 put_cpu_var(core_state);
694 static void switch_from_internal(void)
696 if (get_cpu_var(core_state).have_cpufreq) {
697 put_cpu_var(core_state);
698 ERROR("Unimplemented: switch from internal on machine with cpu freq - will just pretend to do so\n");
699 // The implementation would switch back to default policy and governor
702 get_cpu_var(core_state).mode=V3_PSTATE_HOST_CONTROL;
704 put_cpu_var(core_state);
711 void palacios_pstate_ctrl_acquire(uint32_t type)
713 if (get_cpu_var(core_state).mode != V3_PSTATE_HOST_CONTROL) {
714 palacios_pstate_ctrl_release();
717 put_cpu_var(core_state);
720 case V3_PSTATE_EXTERNAL_CONTROL:
721 switch_to_external();
723 case V3_PSTATE_DIRECT_CONTROL:
726 case V3_PSTATE_INTERNAL_CONTROL:
727 switch_to_internal();
730 ERROR("Unknown pstate control type %u\n",type);
736 // Wrappers for xcalls
737 static void palacios_pstate_ctrl_acquire_external(void)
739 palacios_pstate_ctrl_acquire(V3_PSTATE_EXTERNAL_CONTROL);
742 static void palacios_pstate_ctrl_acquire_direct(void)
744 palacios_pstate_ctrl_acquire(V3_PSTATE_DIRECT_CONTROL);
748 void palacios_pstate_ctrl_release(void)
751 if (get_cpu_var(core_state).mode == V3_PSTATE_HOST_CONTROL) {
752 put_cpu_var(core_state);
756 switch (get_cpu_var(core_state).mode) {
757 case V3_PSTATE_EXTERNAL_CONTROL:
758 switch_from_external();
760 case V3_PSTATE_DIRECT_CONTROL:
761 switch_from_direct();
763 case V3_PSTATE_INTERNAL_CONTROL:
764 switch_from_internal();
767 ERROR("Unknown pstate control type %u\n",core_state.mode);
771 put_cpu_var(core_state);
776 static void update_hw_pstate(void *arg)
778 if (machine_state.funcs && machine_state.funcs->get_pstate) {
779 get_cpu_var(core_state).cur_hw_pstate = machine_state.funcs->get_pstate();
780 put_cpu_var(core_state);
782 get_cpu_var(core_state).cur_hw_pstate = 0;
783 put_cpu_var(core_state);
788 /***************************************************************************
789 PROC Interface to expose state
790 ***************************************************************************/
792 static int pstate_show(struct seq_file * file, void * v)
795 unsigned int numcpus = num_online_cpus();
797 seq_printf(file, "V3VEE DVFS Status\n\n");
799 for (cpu=0;cpu<numcpus;cpu++) {
800 palacios_xcall(cpu,update_hw_pstate,0);
803 seq_printf(file, "Arch:\t%s\nPStates:\t%s\n\n",
804 machine_state.arch==INTEL ? "Intel" :
805 machine_state.arch==AMD ? "AMD" : "Other",
806 machine_state.supports_pstates ? "Yes" : "No");
808 for (cpu=0;cpu<numcpus;cpu++) {
809 struct pstate_core_info *s = &per_cpu(core_state,cpu);
810 seq_printf(file,"pcore %u: hw pstate %u mode %s of [ host ",cpu,
812 s->mode==V3_PSTATE_HOST_CONTROL ? "host" :
813 s->mode==V3_PSTATE_EXTERNAL_CONTROL ? "external" :
814 s->mode==V3_PSTATE_DIRECT_CONTROL ? "direct" :
815 s->mode==V3_PSTATE_INTERNAL_CONTROL ? "internal" : "UNKNOWN");
816 if (s->have_cpufreq) {
817 seq_printf(file," external ");
819 if (machine_state.arch==AMD || machine_state.arch==INTEL) {
820 seq_printf(file,"direct ");
822 seq_printf(file,"internal ] ");
823 if (s->mode==V3_PSTATE_EXTERNAL_CONTROL) {
824 seq_printf(file,"(min=%llu max=%llu cur=%llu) ", s->min_freq_khz, s->max_freq_khz, s->cur_freq_khz);
826 if (s->mode==V3_PSTATE_DIRECT_CONTROL) {
827 seq_printf(file,"(min=%u max=%u cur=%u) ", (uint32_t)s->min_pstate, (uint32_t)s->max_pstate, (uint32_t)s->cur_pstate);
829 seq_printf(file,"\n");
834 static int pstate_open(struct inode * inode, struct file * file)
836 return single_open(file, pstate_show, NULL);
840 static struct file_operations pstate_fops = {
841 .owner = THIS_MODULE,
845 .release = seq_release
848 int pstate_proc_setup(void)
850 struct proc_dir_entry *proc;
852 proc = create_proc_entry("v3-dvfs",0444, palacios_get_procdir());
855 ERROR("Failed to create proc entry for p-state control\n");
859 proc->proc_fops = &pstate_fops;
864 void pstate_proc_teardown(void)
866 remove_proc_entry("v3-dvfs",palacios_get_procdir());
869 /********************************************************************
870 User interface (ioctls)
871 ********************************************************************/
873 static int dvfs_ctrl(unsigned int cmd, unsigned long arg)
875 struct v3_dvfs_ctrl_request r;
877 if (copy_from_user(&r,(void __user*)arg,sizeof(struct v3_dvfs_ctrl_request))) {
878 ERROR("Failed to copy DVFS request from user\n");
882 if (r.pcore >= num_online_cpus()) {
883 ERROR("Cannot apply DVFS request to pcore %u\n",r.pcore);
888 case V3_DVFS_ACQUIRE: {
889 switch (r.acq_type) {
890 case V3_DVFS_EXTERNAL:
891 palacios_xcall(r.pcore,(void (*)(void*))palacios_pstate_ctrl_acquire_external,0);
895 palacios_xcall(r.pcore,(void (*)(void*))palacios_pstate_ctrl_acquire_direct,0);
899 ERROR("Unknown DVFS acquire type %u\n",r.acq_type);
904 case V3_DVFS_RELEASE: {
905 palacios_xcall(r.pcore,(void (*)(void*))palacios_pstate_ctrl_release,0);
909 case V3_DVFS_SETFREQ: {
910 palacios_xcall(r.pcore,(void (*)(void*))palacios_pstate_ctrl_set_freq,(void*)r.freq_khz);
914 case V3_DVFS_SETPSTATE: {
915 palacios_xcall(r.pcore,(void (*)(void*))palacios_pstate_ctrl_set_pstate_wrapper,(void*)(uint64_t)r.pstate);
919 ERROR("Unknown DVFS command %u\n",r.cmd);
927 void pstate_user_setup(void)
929 add_global_ctrl(V3_DVFS_CTRL, dvfs_ctrl);
933 void pstate_user_teardown(void)
935 remove_global_ctrl(V3_DVFS_CTRL);
938 static struct v3_host_pstate_ctrl_iface hooks = {
939 .get_chars = palacios_pstate_ctrl_get_chars,
940 .acquire = palacios_pstate_ctrl_acquire,
941 .release = palacios_pstate_ctrl_release,
942 .set_pstate = palacios_pstate_ctrl_set_pstate,
943 .get_pstate = palacios_pstate_ctrl_get_pstate,
944 .set_freq = palacios_pstate_ctrl_set_freq,
945 .get_freq = palacios_pstate_ctrl_get_freq,
950 static int pstate_ctrl_init(void)
953 unsigned int numcpus = num_online_cpus();
957 for (cpu=0;cpu<numcpus;cpu++) {
958 palacios_xcall(cpu,(void ((*)(void*)))init_core,0);
961 V3_Init_Pstate_Ctrl(&hooks);
963 if (pstate_proc_setup()) {
964 ERROR("Unable to initialize P-State Control\n");
970 INFO("P-State Control Initialized\n");
975 static int pstate_ctrl_deinit(void)
978 unsigned int numcpus=num_online_cpus();
981 pstate_user_teardown();
983 pstate_proc_teardown();
985 // release pstate control if we have it, and we need to do this on each processor
986 for (cpu=0;cpu<numcpus;cpu++) {
987 palacios_xcall(cpu,(void (*)(void *))deinit_core,0);
994 static struct linux_ext pstate_ext = {
995 .name = "PSTATE_CTRL",
996 .init = pstate_ctrl_init,
997 .deinit = pstate_ctrl_deinit,
999 .guest_deinit = NULL,
1003 register_extension(&pstate_ext);