ia64/xen-unstable

changeset 18883:eed39afde7dd

cpuidle: revise tsc-save/restore to reduce tsc skew between cpus

Signed-off-by: Wei Gang <gang.wei@intel.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Dec 05 13:03:44 2008 +0000 (2008-12-05)
parents 5e066dc410ac
children 4ffd935c08a3
files xen/arch/x86/acpi/cpu_idle.c xen/arch/x86/time.c xen/include/xen/time.h
line diff
     1.1 --- a/xen/arch/x86/acpi/cpu_idle.c	Fri Dec 05 11:37:20 2008 +0000
     1.2 +++ b/xen/arch/x86/acpi/cpu_idle.c	Fri Dec 05 13:03:44 2008 +0000
     1.3 @@ -317,8 +317,6 @@ static void acpi_processor_idle(void)
     1.4           * stopped by H/W. Without carefully handling of TSC/APIC stop issues,
     1.5           * deep C state can't work correctly.
     1.6           */
     1.7 -        /* preparing TSC stop */
     1.8 -        cstate_save_tsc();
     1.9          /* preparing APIC stop */
    1.10          lapic_timer_off();
    1.11  
     2.1 --- a/xen/arch/x86/time.c	Fri Dec 05 11:37:20 2008 +0000
     2.2 +++ b/xen/arch/x86/time.c	Fri Dec 05 13:03:44 2008 +0000
     2.3 @@ -48,11 +48,9 @@ struct time_scale {
     2.4  
     2.5  struct cpu_time {
     2.6      u64 local_tsc_stamp;
     2.7 -    u64 cstate_tsc_stamp;
     2.8      s_time_t stime_local_stamp;
     2.9      s_time_t stime_master_stamp;
    2.10      struct time_scale tsc_scale;
    2.11 -    u64 cstate_plt_count_stamp;
    2.12  };
    2.13  
    2.14  struct platform_timesource {
    2.15 @@ -151,6 +149,19 @@ static inline u64 scale_delta(u64 delta,
    2.16      return product;
    2.17  }
    2.18  
    2.19 +/* Compute the reciprocal of the given time_scale. */
    2.20 +static inline struct time_scale scale_reciprocal(struct time_scale scale)
    2.21 +{
    2.22 +    u32 q, r;
    2.23 +
    2.24 +    asm (
    2.25 +        "divl %4"
    2.26 +        : "=a" (q), "=d" (r)
    2.27 +        : "0" (1), "1" (0), "r" (scale.mul_frac) );
    2.28 +
    2.29 +    return (struct time_scale) { .shift = -scale.shift, .mul_frac = q };
    2.30 +}
    2.31 +
    2.32  /*
    2.33   * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
    2.34   * IPIs in place of local APIC timers
    2.35 @@ -644,29 +655,23 @@ static void init_platform_timer(void)
    2.36             freq_string(pts->frequency), pts->name);
    2.37  }
    2.38  
    2.39 -void cstate_save_tsc(void)
    2.40 +void cstate_restore_tsc(void)
    2.41  {
    2.42      struct cpu_time *t = &this_cpu(cpu_time);
    2.43 +    struct time_scale sys_to_tsc = scale_reciprocal(t->tsc_scale);
    2.44 +    s_time_t stime_delta;
    2.45 +    u64 tsc_delta;
    2.46  
    2.47      if ( tsc_invariant )
    2.48          return;
    2.49  
    2.50 -    t->cstate_plt_count_stamp = plt_src.read_counter();
    2.51 -    rdtscll(t->cstate_tsc_stamp);
    2.52 -}
    2.53 +    stime_delta = read_platform_stime() - t->stime_master_stamp;
    2.54 +    if ( stime_delta < 0 )
    2.55 +        stime_delta = 0;
    2.56  
    2.57 -void cstate_restore_tsc(void)
    2.58 -{
    2.59 -    struct cpu_time *t = &this_cpu(cpu_time);
    2.60 -    u64 plt_count_delta, tsc_delta;
    2.61 +    tsc_delta = scale_delta(stime_delta, &sys_to_tsc);
    2.62  
    2.63 -    if ( tsc_invariant )
    2.64 -        return;
    2.65 -
    2.66 -    plt_count_delta = (plt_src.read_counter() -
    2.67 -                       t->cstate_plt_count_stamp) & plt_mask;
    2.68 -    tsc_delta = scale_delta(plt_count_delta, &plt_scale) * cpu_khz/1000000UL;
    2.69 -    wrmsrl(MSR_IA32_TSC, t->cstate_tsc_stamp + tsc_delta);
    2.70 +    wrmsrl(MSR_IA32_TSC, t->local_tsc_stamp + tsc_delta);
    2.71  }
    2.72  
    2.73  /***************************************************************************
     3.1 --- a/xen/include/xen/time.h	Fri Dec 05 11:37:20 2008 +0000
     3.2 +++ b/xen/include/xen/time.h	Fri Dec 05 13:03:44 2008 +0000
     3.3 @@ -13,7 +13,6 @@
     3.4  #include <asm/time.h>
     3.5  
     3.6  extern int init_xen_time(void);
     3.7 -extern void cstate_save_tsc(void);
     3.8  extern void cstate_restore_tsc(void);
     3.9  
    3.10  extern unsigned long cpu_khz;