summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/tsc_sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/tsc_sync.c')
-rw-r--r--arch/x86/kernel/tsc_sync.c37
1 files changed, 35 insertions, 2 deletions
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