# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1209635409 -3600
# Node ID becd9b77f951fe66bb68616426ef13a2894d0191
# Parent 4aec1797720f3691a54988b2b7e02683fb6cdf89
x86: Add TSC stop support for Deep C state
TSC may stop at deep C state (C3/C4...) entry/exit. this patch add the
logic that save and restore TSC during deep C state entry/exit, by
using platform timer (PIT/HPET)
Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx>
Signed-off-by: Tian Kevin <kevin.tian@xxxxxxxxx>
Signed-off-by: Wei Gang<gang.wei@xxxxxxxxx>
---
xen/arch/x86/acpi/cpu_idle.c | 7 ++++---
xen/arch/x86/time.c | 39 +++++++++++++++++++++++++++++++++++++++
xen/include/xen/time.h | 2 ++
3 files changed, 45 insertions(+), 3 deletions(-)
diff -r 4aec1797720f -r becd9b77f951 xen/arch/x86/acpi/cpu_idle.c
--- a/xen/arch/x86/acpi/cpu_idle.c Thu May 01 10:49:38 2008 +0100
+++ b/xen/arch/x86/acpi/cpu_idle.c Thu May 01 10:50:09 2008 +0100
@@ -442,8 +442,8 @@ static void acpi_processor_idle(void)
* stopped by H/W. Without carefully handling of TSC/APIC stop issues,
* deep C state can't work correctly.
*/
- /* placeholder for preparing TSC stop */
-
+ /* preparing TSC stop */
+ cstate_save_tsc();
/* placeholder for preparing APIC stop */
/* Invoke C3 */
@@ -451,7 +451,8 @@ static void acpi_processor_idle(void)
/* placeholder for recovering APIC */
- /* placeholder for recovering TSC */
+ /* recovering TSC */
+ cstate_restore_tsc();
/* Get end time (ticks) */
t2 = inl(pmtmr_ioport);
diff -r 4aec1797720f -r becd9b77f951 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Thu May 01 10:49:38 2008 +0100
+++ b/xen/arch/x86/time.c Thu May 01 10:50:09 2008 +0100
@@ -51,9 +51,11 @@ struct time_scale {
struct cpu_time {
u64 local_tsc_stamp;
+ u64 cstate_tsc_stamp;
s_time_t stime_local_stamp;
s_time_t stime_master_stamp;
struct time_scale tsc_scale;
+ u32 cstate_plt_count_stamp;
struct timer calibration_timer;
};
@@ -65,6 +67,8 @@ struct platform_timesource {
};
static DEFINE_PER_CPU(struct cpu_time, cpu_time);
+
+static u8 tsc_invariant=0; /* TSC is invariant upon C state entry */
/*
* We simulate a 32-bit platform timer from the 16-bit PIT ch2 counter.
@@ -594,6 +598,36 @@ static void init_platform_timer(void)
freq_string(pts->frequency), pts->name);
}
+void cstate_save_tsc(void)
+{
+ struct cpu_time *t = &this_cpu(cpu_time);
+
+ if (!tsc_invariant){
+ t->cstate_plt_count_stamp = plt_src.read_counter();
+ rdtscll(t->cstate_tsc_stamp);
+ }
+}
+
+void cstate_restore_tsc(void)
+{
+ struct cpu_time *t;
+ u32 plt_count_delta;
+ u64 tsc_delta;
+
+ if (!tsc_invariant){
+ t = &this_cpu(cpu_time);
+
+ /* if platform counter overflow happens, interrupt will bring CPU from
+ C state to working state, so the platform counter won't wrap the
+ cstate_plt_count_stamp, and the 32 bit unsigned platform counter
+ is enough for delta calculation
+ */
+ plt_count_delta =
+ (plt_src.read_counter() - t->cstate_plt_count_stamp) & plt_mask;
+ tsc_delta = scale_delta(plt_count_delta, &plt_scale)*cpu_khz/1000000UL;
+ wrmsrl(MSR_IA32_TSC, t->cstate_tsc_stamp + tsc_delta);
+ }
+}
/***************************************************************************
* CMOS Timer functions
@@ -972,6 +1006,11 @@ int __init init_xen_time(void)
stime_platform_stamp = 0;
init_platform_timer();
+
+ /* check if TSC is invariant during deep C state
+ this is a new feature introduced by Nehalem*/
+ if ( cpuid_edx(0x80000007) & (1U<<8) )
+ tsc_invariant = 1;
local_irq_enable();
diff -r 4aec1797720f -r becd9b77f951 xen/include/xen/time.h
--- a/xen/include/xen/time.h Thu May 01 10:49:38 2008 +0100
+++ b/xen/include/xen/time.h Thu May 01 10:50:09 2008 +0100
@@ -13,6 +13,8 @@
#include <asm/time.h>
extern int init_xen_time(void);
+extern void cstate_save_tsc(void);
+extern void cstate_restore_tsc(void);
extern unsigned long cpu_khz;
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|