Skip to content

Commit

Permalink
x86/tsc: Detect random warps
Browse files Browse the repository at this point in the history
If time warps can be observed then they should only ever be observed on one
CPU. If they are observed on both CPUs then the system is completely hosed.

Add a check for this condition and notify if it happens.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Link: http://lkml.kernel.org/r/20161119134017.574838461@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Nov 29, 2016
1 parent 7b3d2f6 commit bec8520
Showing 1 changed file with 12 additions and 1 deletion.
13 changes: 12 additions & 1 deletion arch/x86/kernel/tsc_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ static arch_spinlock_t sync_lock = __ARCH_SPIN_LOCK_UNLOCKED;
static cycles_t last_tsc;
static cycles_t max_warp;
static int nr_warps;
static int random_warps;

/*
* TSC-warp measurement loop running on both CPUs. This is not called
Expand All @@ -45,7 +46,7 @@ static int nr_warps;
static void check_tsc_warp(unsigned int timeout)
{
cycles_t start, now, prev, end;
int i;
int i, cur_warps = 0;

start = rdtsc_ordered();
/*
Expand Down Expand Up @@ -85,7 +86,14 @@ static void check_tsc_warp(unsigned int timeout)
if (unlikely(prev > now)) {
arch_spin_lock(&sync_lock);
max_warp = max(max_warp, prev - now);
/*
* Check whether this bounces back and forth. Only
* one CPU should observe time going backwards.
*/
if (cur_warps != nr_warps)
random_warps++;
nr_warps++;
cur_warps = nr_warps;
arch_spin_unlock(&sync_lock);
}
}
Expand Down Expand Up @@ -160,6 +168,8 @@ void check_tsc_sync_source(int cpu)
smp_processor_id(), cpu);
pr_warning("Measured %Ld cycles TSC warp between CPUs, "
"turning off TSC clock.\n", max_warp);
if (random_warps)
pr_warning("TSC warped randomly between CPUs\n");
mark_tsc_unstable("check_tsc_sync_source failed");
} else {
pr_debug("TSC synchronization [CPU#%d -> CPU#%d]: passed\n",
Expand All @@ -170,6 +180,7 @@ void check_tsc_sync_source(int cpu)
* Reset it - just in case we boot another CPU later:
*/
atomic_set(&start_count, 0);
random_warps = 0;
nr_warps = 0;
max_warp = 0;
last_tsc = 0;
Expand Down

0 comments on commit bec8520

Please sign in to comment.