diff -r 886594fa3aef xen/arch/x86/dom0_ops.c --- a/xen/arch/x86/dom0_ops.c Sat Apr 8 12:10:04 2006 +0100 +++ b/xen/arch/x86/dom0_ops.c Mon Apr 10 19:44:19 2006 -0400 @@ -339,6 +339,13 @@ long arch_do_dom0_op(struct dom0_op *op, } break; + case DOM0_SETCPUFREQ: + { + extern int set_cpu_freq(cpumap_t cpumap, unsigned long khz); + ret = set_cpu_freq(op->u.setcpufreq.cpumap, op->u.setcpufreq.khz); + break; + } + case DOM0_GETMEMLIST: { int i; diff -r 886594fa3aef xen/arch/x86/time.c --- a/xen/arch/x86/time.c Sat Apr 8 12:10:04 2006 +0100 +++ b/xen/arch/x86/time.c Mon Apr 10 19:44:19 2006 -0400 @@ -914,6 +914,60 @@ void __init early_time_init(void) setup_irq(0, &irq0); } +/* + * This is called when the hypervisor is notified of a CPU core + * frequency change initiated by a driver in dom0. + * + * This should be called after the new frequency has stabilized. + * + * The CPUs specified may include any CPU or core (if cores have + * independent PLLs). In an SMP or multi-core system, it may + * take a while for the recalibration function to be scheduled + * on the intended target CPUs; there is no guarantee this will + * happen by the time this call returns. + * + */ +typedef struct percpu_freq_update { + cpumap_t cpumap; + unsigned long khz; +} percpu_freq_update_t; + +void set_cpu_freq_percpu(void *p) { + percpu_freq_update_t *data = (percpu_freq_update_t*)p; + int affected; + + if (!data) { + printk(" Adjust freq on cpu %d: no data!\n", smp_processor_id()); + return; + } + + affected = ((data->cpumap & (1 << smp_processor_id())) != 0); + + printk(" Frequency change request on cpu %d: cpumap %08llx, khz %ld (%s)\n", + smp_processor_id(), (unsigned long long)data->cpumap, data->khz, + (affected ? "adjusting" : "skipping")); + + if (affected) { + cpu_khz = data->khz; + local_time_calibration(NULL); + + printk(" Recalibrated timers on cpu %d to %ld khz\n", + smp_processor_id(), data->khz); + } +} + +int set_cpu_freq(cpumap_t cpumap, unsigned long khz) { + percpu_freq_update_t freq_update; + + printk("CPU frequency change request: cpumap %08llx, khz %ld", + (unsigned long long)cpumap, khz); + + freq_update.cpumap = cpumap; + freq_update.khz = khz; + + return on_each_cpu(set_cpu_freq_percpu, &freq_update, 1, 1); +} + void send_timer_event(struct vcpu *v) { send_guest_vcpu_virq(v, VIRQ_TIMER); diff -r 886594fa3aef xen/include/public/dom0_ops.h --- a/xen/include/public/dom0_ops.h Sat Apr 8 12:10:04 2006 +0100 +++ b/xen/include/public/dom0_ops.h Mon Apr 10 19:44:19 2006 -0400 @@ -283,6 +283,28 @@ typedef struct dom0_getpageframeinfo2 { GUEST_HANDLE(ulong) array; } dom0_getpageframeinfo2_t; DEFINE_GUEST_HANDLE(dom0_getpageframeinfo2_t); + +/* + * Notify hypervisor of a CPU core frequency change completed + * by cpufreq driver in dom0, triggering an internal timer + * recalibration. + * + * This should be called after the new frequency has stabilized. + * + * The CPUs specified may include any CPU or core (if cores have + * independent PLLs). In an SMP or multi-core system, it may + * take a while for the recalibration function to be scheduled + * on the intended target CPUs; there is no guarantee this will + * happen by the time this call returns. + * + */ +#define DOM0_SETCPUFREQ 30 +typedef struct dom0_setcpufreq { + /* IN variables */ + cpumap_t cpumap; + unsigned long khz; +} dom0_setcpufreq_t; +DEFINE_GUEST_HANDLE(dom0_setcpufreq_t); /* * Request memory range (@mfn, @mfn+@nr_mfns-1) to have type @type. @@ -496,6 +518,7 @@ typedef struct dom0_op { struct dom0_shadow_control shadow_control; struct dom0_setdomainmaxmem setdomainmaxmem; struct dom0_getpageframeinfo2 getpageframeinfo2; + struct dom0_setcpufreq setcpufreq; struct dom0_add_memtype add_memtype; struct dom0_del_memtype del_memtype; struct dom0_read_memtype read_memtype;