Mark Langsdorf
2007-Aug-30 17:00 UTC
[Xen-devel] [PATCH][Retry 1] 1/4: cpufreq/PowerNow! in Xen: Xen timer changes
Enable cpufreq support in Xen for AMD Operton processors by: 1) Allowing the PowerNow! driver in dom0 to write to the PowerNow! MSRs. 2) Adding the cpufreq notifier chain to time-xen.c in dom0. On a frequency change, a platform hypercall is performed to scale the frequency multiplier in the hypervisor. 3) Adding a platform hypercall to the hypervisor the scale the frequency multiplier and reset the time stamps so that next calibration remains reasonably correct. 4) Adding the cpufreq Xen option which pins the VCPUs to the physical CPU cores. Patch 1 covers the frequency scaling platform call in Xen. Patch 2 allows MSR accesses from the PowerNow! driver. Patch 3 covers the frequency scaling platform call in Linux. Patch 4 covers the changes necessary to the PowerNow! driver to make it correctly associate shared cores under Xen. This code can be readily expanded to cover Intel or other non-AMD processors by modifying xen/arch/x8/traps.c to allow the appropriate MSR accesses. Caveat: currently, this code does not support the in-kernel ondemand cpufreq governor. Dom0 must run a userspace daemon to monitor the utilization of the physical cpus with the getcpuinfo sysctl hypercall. Caveat 2: Even though the clock multipliers are being scaled and recorded correctly in both dom0 and the hypervisor, time errors appear immediately after a frequency change. They are not more likely when the frequency is constant. Signed-off-by: Mark Langsdorf <mark.langsdorf@amd.com> diff -r 256160ff19b7 xen/arch/x86/platform_hypercall.c --- a/xen/arch/x86/platform_hypercall.c Thu Aug 16 13:27:59 2007 +0100 +++ b/xen/arch/x86/platform_hypercall.c Thu Aug 30 12:08:29 2007 -0500 @@ -252,6 +252,13 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe ret = acpi_enter_sleep(&op->u.enter_acpi_sleep); break; + case XENPF_change_freq: + { + do_change_freq((struct vcpu_time_info *) op->u.change_freq.info, op->u.change_freq.old, op->u.change_freq.new, op->u.change_freq.cpu_num); + ret = 0; + } + break; + default: ret = -ENOSYS; break; diff -r 256160ff19b7 xen/arch/x86/time.c --- a/xen/arch/x86/time.c Thu Aug 16 13:27:59 2007 +0100 +++ b/xen/arch/x86/time.c Thu Aug 30 12:08:29 2007 -0500 @@ -723,6 +723,41 @@ void update_domain_wallclock_time(struct spin_unlock(&wc_lock); } +/* calculate new tsc_scale factor based on ratio of new and old frequency + * and update time stamps to restart the period for the next calibration + */ +void do_change_freq(struct vcpu_time_info *info, unsigned int old, unsigned int new, int cpu_num) +{ + u64 new_mult, curr_tsc; + s8 new_shift; + struct cpu_time *t; + + t = &this_cpu(cpu_time); + new_mult = info->tsc_to_system_mul; + do_div(new_mult, new / 1000); + new_mult *= (old / 1000); + new_shift = info->tsc_shift; + while (new_mult > (1LL <<32)) { + new_shift += 1; + new_mult = new_mult >> 1; + } + while (new_mult < (1LL << 31)) { + new_shift -= 1; + new_mult = new_mult << 1; + } + + t->tsc_scale.mul_frac = new_mult; + t->tsc_scale.shift = new_shift; + local_irq_disable(); + rdtscll(curr_tsc); + t->local_tsc_stamp = curr_tsc; + t->stime_local_stamp = get_s_time(); + t->stime_master_stamp = read_platform_stime(); + local_irq_enable(); + + platform_time_calibration(); +} + /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) { @@ -862,7 +897,7 @@ static void local_time_calibration(void if ( error_factor != 0 ) calibration_mul_frac = mul_frac(calibration_mul_frac, error_factor); -#if 0 +#if 0 printk("---%d: %08x %08x %d\n", smp_processor_id(), error_factor, calibration_mul_frac, tsc_shift); #endif diff -r 256160ff19b7 xen/common/schedule.c --- a/xen/common/schedule.c Thu Aug 16 13:27:59 2007 +0100 +++ b/xen/common/schedule.c Thu Aug 30 12:08:29 2007 -0500 @@ -39,7 +39,9 @@ string_param("sched", opt_sched); /* opt_dom0_vcpus_pin: If true, dom0 VCPUs are pinned. */ static unsigned int opt_dom0_vcpus_pin; +unsigned int opt_cpufreq; boolean_param("dom0_vcpus_pin", opt_dom0_vcpus_pin); +boolean_param("cpufreq", opt_cpufreq); #define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */ @@ -105,7 +107,7 @@ int sched_init_vcpu(struct vcpu *v, unsi * domain-0 VCPUs, are pinned onto their respective physical CPUs. */ v->processor = processor; - if ( is_idle_domain(d) || ((d->domain_id == 0) && opt_dom0_vcpus_pin) ) + if ( is_idle_domain(d) || ((d->domain_id == 0) && ( opt_cpufreq || opt_dom0_vcpus_pin) ) ) v->cpu_affinity = cpumask_of_cpu(processor); else cpus_setall(v->cpu_affinity); @@ -254,7 +256,7 @@ int vcpu_set_affinity(struct vcpu *v, cp { cpumask_t online_affinity; - if ( (v->domain->domain_id == 0) && opt_dom0_vcpus_pin ) + if ( (v->domain->domain_id == 0) && ( opt_dom0_vcpus_pin || opt_cpufreq ) ) return -EINVAL; cpus_and(online_affinity, *affinity, cpu_online_map); diff -r 256160ff19b7 xen/include/public/platform.h --- a/xen/include/public/platform.h Thu Aug 16 13:27:59 2007 +0100 +++ b/xen/include/public/platform.h Thu Aug 30 12:08:29 2007 -0500 @@ -164,6 +164,17 @@ typedef struct xenpf_enter_acpi_sleep xe typedef struct xenpf_enter_acpi_sleep xenpf_enter_acpi_sleep_t; DEFINE_XEN_GUEST_HANDLE(xenpf_enter_acpi_sleep_t); +#define XENPF_change_freq 52 +struct xenpf_change_freq { + /* IN variables */ + struct vcpu_time_info *info; /* vcpu time info for changing vcpu */ + uint32_t old; /* original frequency */ + uint32_t new; /* new frequency */ + uint32_t cpu_num; +}; +typedef struct xenpf_change_freq xenpf_change_freq_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_change_freq_t); + struct xen_platform_op { uint32_t cmd; uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ @@ -176,6 +187,7 @@ struct xen_platform_op { struct xenpf_platform_quirk platform_quirk; struct xenpf_firmware_info firmware_info; struct xenpf_enter_acpi_sleep enter_acpi_sleep; + struct xenpf_change_freq change_freq; uint8_t pad[128]; } u; }; diff -r 256160ff19b7 xen/include/xen/sched.h --- a/xen/include/xen/sched.h Thu Aug 16 13:27:59 2007 +0100 +++ b/xen/include/xen/sched.h Thu Aug 30 12:08:29 2007 -0500 @@ -496,6 +496,9 @@ static inline void vcpu_unblock(struct v #define is_hvm_domain(d) ((d)->is_hvm) #define is_hvm_vcpu(v) (is_hvm_domain(v->domain)) +/* global variable for cpufreq ability */ +extern unsigned int opt_cpufreq; + #endif /* __SCHED_H__ */ /* diff -r 256160ff19b7 xen/include/xen/time.h --- a/xen/include/xen/time.h Thu Aug 16 13:27:59 2007 +0100 +++ b/xen/include/xen/time.h Thu Aug 30 12:08:29 2007 -0500 @@ -74,6 +74,8 @@ extern void do_settime( extern void do_settime( unsigned long secs, unsigned long nsecs, u64 system_time_base); +extern void do_change_freq(struct vcpu_time_info *info, unsigned int old, unsigned int new, int cpu_num); + extern void send_timer_event(struct vcpu *v); #endif /* __XEN_TIME_H__ */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Apparently Analagous Threads
- [PATCH] 1/2: cpufreq/PowerNow! in Xen: Time and platform changes
- [PATCH] x86: add hypercall to query current underlying pCPU''s frequency
- [PATCH 2/2] RFC: Xen pad logic
- [PATCH] xen/xsm: Compile error due to naming clash between XSM and EFI runtime
- [PATCH 0/3] Xen Microcode update driver for 2.6.38