diff -r bd97e45e073a xen/arch/x86/time.c --- a/xen/arch/x86/time.c Tue Jul 08 09:28:50 2008 +0100 +++ b/xen/arch/x86/time.c Sat Jul 12 14:58:44 2008 -0600 @@ -452,6 +452,24 @@ static int init_pmtimer(struct platform_ } /************************************************************ + * PLATFORM TIMER 4: TSC + */ + +static bool_t clocksource_is_tsc = 0; +static u64 tsc_freq; + +static int init_tsctimer(struct platform_timesource *pts) +{ + /* TODO: evaluate stability of TSC here, return 0 if not stable */ + pts->name = "TSC"; + pts->frequency = tsc_freq; + pts->read_counter = 0; /* unused as of now */ + pts->counter_bits = 64; + clocksource_is_tsc = 1; + return 1; +} + +/************************************************************ * GENERIC PLATFORM TIMER INFRASTRUCTURE */ @@ -483,16 +501,28 @@ static void plt_overflow(void *unused) static s_time_t __read_platform_stime(u64 platform_time) { - u64 diff = platform_time - platform_timer_stamp; + u64 diff, tsc; + + if ( clocksource_is_tsc ) + { + rdtscll(tsc); + return scale_delta(tsc, &plt_scale); + } + diff = platform_time - platform_timer_stamp; ASSERT(spin_is_locked(&platform_timer_lock)); return (stime_platform_stamp + scale_delta(diff, &plt_scale)); } static s_time_t read_platform_stime(void) { - u64 count; + u64 count, tsc; s_time_t stime; + if ( clocksource_is_tsc ) + { + rdtscll(tsc); + return scale_delta(tsc, &plt_scale); + } spin_lock(&platform_timer_lock); count = plt_stamp64 + ((plt_src.read_counter() - plt_stamp) & plt_mask); stime = __read_platform_stime(count); @@ -506,6 +536,8 @@ static void platform_time_calibration(vo u64 count; s_time_t stamp; + if ( clocksource_is_tsc ) + return; spin_lock(&platform_timer_lock); count = plt_stamp64 + ((plt_src.read_counter() - plt_stamp) & plt_mask); stamp = __read_platform_stime(count); @@ -516,6 +548,8 @@ static void platform_time_calibration(vo static void resume_platform_timer(void) { + if ( clocksource_is_tsc ) + return; /* No change in platform_stime across suspend/resume. */ platform_timer_stamp = plt_stamp64; plt_stamp = plt_src.read_counter(); @@ -536,6 +570,8 @@ static void init_platform_timer(void) rc = init_cyclone(pts); else if ( !strcmp(opt_clocksource, "acpi") ) rc = init_pmtimer(pts); + else if ( !strcmp(opt_clocksource, "tsc") ) + rc = init_tsctimer(pts); if ( rc <= 0 ) printk("WARNING: %s clocksource '%s'.\n", @@ -549,16 +585,20 @@ static void init_platform_timer(void) !init_pmtimer(pts) ) init_pit(pts); - plt_mask = (u32)~0u >> (32 - pts->counter_bits); - set_time_scale(&plt_scale, pts->frequency); - plt_overflow_period = scale_delta( - 1ull << (pts->counter_bits-1), &plt_scale); - init_timer(&plt_overflow_timer, plt_overflow, NULL, 0); - plt_overflow(NULL); + if (pts->counter_bits != 64 ) + { + plt_mask = (u32)~0u >> (32 - pts->counter_bits); - platform_timer_stamp = plt_stamp64; + plt_overflow_period = scale_delta( + 1ull << (pts->counter_bits-1), &plt_scale); + init_timer(&plt_overflow_timer, plt_overflow, NULL, 0); + plt_overflow(NULL); + + platform_timer_stamp = plt_stamp64; + } + printk("Platform timer is %s %s\n", freq_string(pts->frequency), pts->name); @@ -580,7 +620,8 @@ void cstate_restore_tsc(void) u32 plt_count_delta; u64 tsc_delta; - if (!tsc_invariant){ + if ( !tsc_invariant && !clocksource_is_tsc ) + { t = &this_cpu(cpu_time); /* if platform counter overflow happens, interrupt will bring CPU from @@ -687,14 +728,18 @@ static unsigned long get_cmos_time(void) s_time_t get_s_time(void) { - struct cpu_time *t = &this_cpu(cpu_time); + struct cpu_time *t; u64 tsc, delta; s_time_t now; rdtscll(tsc); - delta = tsc - t->local_tsc_stamp; - now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale); - + if ( clocksource_is_tsc ) + now = scale_delta(tsc, &plt_scale); + else { + t = &this_cpu(cpu_time); + delta = tsc - t->local_tsc_stamp; + now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale); + } return now; } @@ -996,6 +1041,7 @@ void __init early_time_init(void) { u64 tmp = init_pit_and_calibrate_tsc(); + tsc_freq = tmp; set_time_scale(&this_cpu(cpu_time).tsc_scale, tmp); do_div(tmp, 1000);