aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-07-21 10:39:15 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-07-21 10:39:15 +0100
commit0bfcf984b727797fb48e19507cd9f00afd1cd65a (patch)
tree31ddf702ba481f7ec78b6f0f953ccdabff6a23dc
parent7f6d517c52302528257cf78be40b1079f592fcde (diff)
downloadxen-0bfcf984b727797fb48e19507cd9f00afd1cd65a.tar.gz
xen-0bfcf984b727797fb48e19507cd9f00afd1cd65a.tar.bz2
xen-0bfcf984b727797fb48e19507cd9f00afd1cd65a.zip
x86: Reintroduce clocksource=tsc.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
-rw-r--r--xen/arch/x86/time.c78
1 files changed, 70 insertions, 8 deletions
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 3ae67e4ad4..72f1c4a6c1 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -481,6 +481,35 @@ static int init_pmtimer(struct platform_timesource *pts)
}
/************************************************************
+ * PLATFORM TIMER 5: TSC
+ */
+
+static const char plt_tsc_name[] = "TSC";
+#define platform_timer_is_tsc() (plt_src.name == plt_tsc_name)
+
+static int init_tsctimer(struct platform_timesource *pts)
+{
+ if ( !tsc_invariant )
+ return 0;
+
+ pts->name = (char *)plt_tsc_name;
+ return 1;
+}
+
+static void make_tsctimer_record(void)
+{
+ struct cpu_time *t = &this_cpu(cpu_time);
+ s_time_t now;
+ u64 tsc;
+
+ rdtscll(tsc);
+ now = scale_delta(tsc, &t->tsc_scale);
+
+ t->local_tsc_stamp = tsc;
+ t->stime_local_stamp = t->stime_master_stamp = now;
+}
+
+/************************************************************
* GENERIC PLATFORM TIMER INFRASTRUCTURE
*/
@@ -545,6 +574,12 @@ static void platform_time_calibration(void)
static void resume_platform_timer(void)
{
+ if ( platform_timer_is_tsc() )
+ {
+ /* TODO: Save/restore TSC values. */
+ return;
+ }
+
/* No change in platform_stime across suspend/resume. */
platform_timer_stamp = plt_stamp64;
plt_stamp = plt_src.read_counter();
@@ -565,6 +600,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",
@@ -578,6 +615,12 @@ static void init_platform_timer(void)
!init_pmtimer(pts) )
init_pit(pts);
+ if ( platform_timer_is_tsc() )
+ {
+ printk("Platform timer is TSC\n");
+ return;
+ }
+
plt_mask = (u64)~0ull >> (64 - pts->counter_bits);
set_time_scale(&plt_scale, pts->frequency);
@@ -780,6 +823,10 @@ int cpu_frequency_change(u64 freq)
struct cpu_time *t = &this_cpu(cpu_time);
u64 curr_tsc;
+ /* Nothing to do if TSC is platform timer. Assume it is constant-rate. */
+ if ( platform_timer_is_tsc() )
+ return 0;
+
/* Sanity check: CPU frequency allegedly dropping below 1MHz? */
if ( freq < 1000000u )
{
@@ -861,6 +908,14 @@ static void local_time_calibration(void *unused)
/* The overall calibration scale multiplier. */
u32 calibration_mul_frac;
+ if ( platform_timer_is_tsc() )
+ {
+ make_tsctimer_record();
+ update_vcpu_system_time(current);
+ set_timer(&t->calibration_timer, NOW() + MILLISECS(10*1000));
+ return;
+ }
+
prev_tsc = t->local_tsc_stamp;
prev_local_stime = t->stime_local_stamp;
prev_master_stime = t->stime_master_stamp;
@@ -978,6 +1033,12 @@ void init_percpu_time(void)
unsigned long flags;
s_time_t now;
+ if ( platform_timer_is_tsc() )
+ {
+ make_tsctimer_record();
+ goto out;
+ }
+
local_irq_save(flags);
rdtscll(t->local_tsc_stamp);
now = !plt_src.read_counter ? 0 : read_platform_stime();
@@ -986,6 +1047,7 @@ void init_percpu_time(void)
t->stime_master_stamp = now;
t->stime_local_stamp = now;
+ out:
init_timer(&t->calibration_timer, local_time_calibration,
NULL, smp_processor_id());
set_timer(&t->calibration_timer, NOW() + EPOCH);
@@ -994,19 +1056,19 @@ void init_percpu_time(void)
/* Late init function (after all CPUs are booted). */
int __init init_xen_time(void)
{
- wc_sec = get_cmos_time();
-
local_irq_disable();
+ /* 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;
+
init_percpu_time();
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;
+ do_settime(get_cmos_time(), 0, NOW());
local_irq_enable();
@@ -1120,10 +1182,10 @@ int time_resume(void)
resume_platform_timer();
- do_settime(get_cmos_time() + cmos_utc_offset, 0, read_platform_stime());
-
init_percpu_time();
+ do_settime(get_cmos_time() + cmos_utc_offset, 0, NOW());
+
if ( !is_idle_vcpu(current) )
update_vcpu_system_time(current);