#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 *);
#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)
{
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);
}
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