]> xenbits.xensource.com Git - xen.git/commitdiff
x86: Add TSC stop support for Deep C state
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 1 May 2008 09:50:09 +0000 (10:50 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 1 May 2008 09:50:09 +0000 (10:50 +0100)
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@intel.com>
Signed-off-by: Tian Kevin <kevin.tian@intel.com>
Signed-off-by: Wei Gang<gang.wei@intel.com>
xen/arch/x86/acpi/cpu_idle.c
xen/arch/x86/time.c
xen/include/xen/time.h

index 73413dccc18aa6624afa3be41bedd1bbba3441ad..2dc5fa7256fd28a116d4d0c58ccb468a2464f124 100644 (file)
@@ -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);
index 6bec5cb1c6ff6ad706c965ba92638762feec705b..44f11187481f391ca90d8557b16e942573353420 100644 (file)
@@ -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;
 };
 
@@ -66,6 +68,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.
  * Otherwise overflow happens too quickly (~50ms) for us to guarantee that
@@ -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
@@ -973,6 +1007,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();
 
     return 0;
index e70ad5350e2b1506439d2514b20da7210e9f7dac..c7c13909a030e30ea3e6d9ef549b6de8ca777080 100644 (file)
@@ -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;