aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/tsc.h2
-rw-r--r--arch/x86/kernel/process.c1
-rw-r--r--arch/x86/kernel/tsc_sync.c37
3 files changed, 38 insertions, 2 deletions
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 1ec0595867d9..b896e9ee65bc 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -50,8 +50,10 @@ extern void check_tsc_sync_target(void);
#ifdef CONFIG_X86_TSC
extern void tsc_store_and_check_tsc_adjust(void);
+extern void tsc_verify_tsc_adjust(void);
#else
static inline void tsc_store_and_check_tsc_adjust(void) { }
+static inline void tsc_verify_tsc_adjust(void) { }
#endif
extern int notsc_setup(char *);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 0888a879120f..4fe5dc84da4f 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -277,6 +277,7 @@ void exit_idle(void)
void arch_cpu_idle_enter(void)
{
+ tsc_verify_tsc_adjust();
local_touch_nmi();
enter_idle();
}
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c
index bd2bd5e89d96..f713e84d1cb4 100644
--- a/arch/x86/kernel/tsc_sync.c
+++ b/arch/x86/kernel/tsc_sync.c
@@ -22,12 +22,42 @@
#include <asm/tsc.h>
struct tsc_adjust {
- s64 bootval;
- s64 adjusted;
+ s64 bootval;
+ s64 adjusted;
+ unsigned long nextcheck;
+ bool warned;
};
static DEFINE_PER_CPU(struct tsc_adjust, tsc_adjust);
+void tsc_verify_tsc_adjust(void)
+{
+ struct tsc_adjust *adj = this_cpu_ptr(&tsc_adjust);
+ s64 curval;
+
+ if (!boot_cpu_has(X86_FEATURE_TSC_ADJUST))
+ return;
+
+ /* Rate limit the MSR check */
+ if (time_before(jiffies, adj->nextcheck))
+ return;
+
+ adj->nextcheck = jiffies + HZ;
+
+ rdmsrl(MSR_IA32_TSC_ADJUST, curval);
+ if (adj->adjusted == curval)
+ return;
+
+ /* Restore the original value */
+ wrmsrl(MSR_IA32_TSC_ADJUST, adj->adjusted);
+
+ if (!adj->warned) {
+ pr_warn(FW_BUG "TSC ADJUST differs: CPU%u %lld --> %lld. Restoring\n",
+ smp_processor_id(), adj->adjusted, curval);
+ adj->warned = true;
+ }
+}
+
#ifndef CONFIG_SMP
void __init tsc_store_and_check_tsc_adjust(void)
{
@@ -40,6 +70,7 @@ void __init tsc_store_and_check_tsc_adjust(void)
rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
cur->bootval = bootval;
cur->adjusted = bootval;
+ cur->nextcheck = jiffies + HZ;
pr_info("TSC ADJUST: Boot CPU0: %lld\n", bootval);
}
@@ -59,6 +90,8 @@ void tsc_store_and_check_tsc_adjust(void)
rdmsrl(MSR_IA32_TSC_ADJUST, bootval);
cur->bootval = bootval;
+ cur->nextcheck = jiffies + HZ;
+ cur->warned = false;
/*
* Check whether this CPU is the first in a package to come up. In