These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / arch / x86 / kernel / kvmclock.c
index 42caaef..2bd81e3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <linux/memblock.h>
+#include <linux/sched.h>
 
 #include <asm/x86_init.h>
 #include <asm/reboot.h>
@@ -31,6 +32,7 @@
 static int kvmclock = 1;
 static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
 static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
+static cycle_t kvm_sched_clock_offset;
 
 static int parse_no_kvmclock(char *arg)
 {
@@ -91,6 +93,29 @@ static cycle_t kvm_clock_get_cycles(struct clocksource *cs)
        return kvm_clock_read();
 }
 
+static cycle_t kvm_sched_clock_read(void)
+{
+       return kvm_clock_read() - kvm_sched_clock_offset;
+}
+
+static inline void kvm_sched_clock_init(bool stable)
+{
+       if (!stable) {
+               pv_time_ops.sched_clock = kvm_clock_read;
+               return;
+       }
+
+       kvm_sched_clock_offset = kvm_clock_read();
+       pv_time_ops.sched_clock = kvm_sched_clock_read;
+       set_sched_clock_stable();
+
+       printk(KERN_INFO "kvm-clock: using sched offset of %llu cycles\n",
+                       kvm_sched_clock_offset);
+
+       BUILD_BUG_ON(sizeof(kvm_sched_clock_offset) >
+                sizeof(((struct pvclock_vcpu_time_info *)NULL)->system_time));
+}
+
 /*
  * If we don't do that, there is the possibility that the guest
  * will calibrate under heavy load - thus, getting a lower lpj -
@@ -199,7 +224,7 @@ static void kvm_setup_secondary_clock(void)
  * kind of shutdown from our side, we unregister the clock by writting anything
  * that does not have the 'enable' bit set in the msr
  */
-#ifdef CONFIG_KEXEC
+#ifdef CONFIG_KEXEC_CORE
 static void kvm_crash_shutdown(struct pt_regs *regs)
 {
        native_write_msr(msr_kvm_system_time, 0, 0);
@@ -217,8 +242,10 @@ static void kvm_shutdown(void)
 
 void __init kvmclock_init(void)
 {
+       struct pvclock_vcpu_time_info *vcpu_time;
        unsigned long mem;
-       int size;
+       int size, cpu;
+       u8 flags;
 
        size = PAGE_ALIGN(sizeof(struct pvclock_vsyscall_time_info)*NR_CPUS);
 
@@ -245,7 +272,17 @@ void __init kvmclock_init(void)
                memblock_free(mem, size);
                return;
        }
-       pv_time_ops.sched_clock = kvm_clock_read;
+
+       if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
+               pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
+
+       cpu = get_cpu();
+       vcpu_time = &hv_clock[cpu].pvti;
+       flags = pvclock_read_flags(vcpu_time);
+
+       kvm_sched_clock_init(flags & PVCLOCK_TSC_STABLE_BIT);
+       put_cpu();
+
        x86_platform.calibrate_tsc = kvm_get_tsc_khz;
        x86_platform.get_wallclock = kvm_get_wallclock;
        x86_platform.set_wallclock = kvm_set_wallclock;
@@ -256,15 +293,12 @@ void __init kvmclock_init(void)
        x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
        x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
        machine_ops.shutdown  = kvm_shutdown;
-#ifdef CONFIG_KEXEC
+#ifdef CONFIG_KEXEC_CORE
        machine_ops.crash_shutdown  = kvm_crash_shutdown;
 #endif
        kvm_get_preset_lpj();
        clocksource_register_hz(&kvm_clock, NSEC_PER_SEC);
        pv_info.name = "KVM";
-
-       if (kvm_para_has_feature(KVM_FEATURE_CLOCKSOURCE_STABLE_BIT))
-               pvclock_set_flags(PVCLOCK_TSC_STABLE_BIT);
 }
 
 int __init kvm_setup_vsyscall_timeinfo(void)