aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86.c
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2012-11-27 20:29:00 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2012-11-27 20:29:12 -0500
commit16e8d74d2da9920f874b10a3d979fb25c01f518f (patch)
treecd7ba9c537a1a8853baed0e12bdfbc3f52a54b4c /arch/x86/kvm/x86.c
parente0b306fef90556233797d2e1747bd6a3ae35ea93 (diff)
KVM: x86: notifier for clocksource changes
Register a notifier for clocksource change event. In case the host switches to clock other than TSC, disable master clock usage. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r--arch/x86/kvm/x86.c94
1 files changed, 93 insertions, 1 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1155059c512e..c077b817d1c3 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -46,6 +46,8 @@
46#include <linux/uaccess.h> 46#include <linux/uaccess.h>
47#include <linux/hash.h> 47#include <linux/hash.h>
48#include <linux/pci.h> 48#include <linux/pci.h>
49#include <linux/timekeeper_internal.h>
50#include <linux/pvclock_gtod.h>
49#include <trace/events/kvm.h> 51#include <trace/events/kvm.h>
50 52
51#define CREATE_TRACE_POINTS 53#define CREATE_TRACE_POINTS
@@ -901,6 +903,55 @@ static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
901 return kvm_set_msr(vcpu, index, *data); 903 return kvm_set_msr(vcpu, index, *data);
902} 904}
903 905
906#ifdef CONFIG_X86_64
907struct pvclock_gtod_data {
908 seqcount_t seq;
909
910 struct { /* extract of a clocksource struct */
911 int vclock_mode;
912 cycle_t cycle_last;
913 cycle_t mask;
914 u32 mult;
915 u32 shift;
916 } clock;
917
918 /* open coded 'struct timespec' */
919 u64 monotonic_time_snsec;
920 time_t monotonic_time_sec;
921};
922
923static struct pvclock_gtod_data pvclock_gtod_data;
924
925static void update_pvclock_gtod(struct timekeeper *tk)
926{
927 struct pvclock_gtod_data *vdata = &pvclock_gtod_data;
928
929 write_seqcount_begin(&vdata->seq);
930
931 /* copy pvclock gtod data */
932 vdata->clock.vclock_mode = tk->clock->archdata.vclock_mode;
933 vdata->clock.cycle_last = tk->clock->cycle_last;
934 vdata->clock.mask = tk->clock->mask;
935 vdata->clock.mult = tk->mult;
936 vdata->clock.shift = tk->shift;
937
938 vdata->monotonic_time_sec = tk->xtime_sec
939 + tk->wall_to_monotonic.tv_sec;
940 vdata->monotonic_time_snsec = tk->xtime_nsec
941 + (tk->wall_to_monotonic.tv_nsec
942 << tk->shift);
943 while (vdata->monotonic_time_snsec >=
944 (((u64)NSEC_PER_SEC) << tk->shift)) {
945 vdata->monotonic_time_snsec -=
946 ((u64)NSEC_PER_SEC) << tk->shift;
947 vdata->monotonic_time_sec++;
948 }
949
950 write_seqcount_end(&vdata->seq);
951}
952#endif
953
954
904static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock) 955static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
905{ 956{
906 int version; 957 int version;
@@ -997,6 +1048,8 @@ static inline u64 get_kernel_ns(void)
997 return timespec_to_ns(&ts); 1048 return timespec_to_ns(&ts);
998} 1049}
999 1050
1051static atomic_t kvm_guest_has_master_clock = ATOMIC_INIT(0);
1052
1000static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz); 1053static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz);
1001unsigned long max_tsc_khz; 1054unsigned long max_tsc_khz;
1002 1055
@@ -1229,7 +1282,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
1229 vcpu->last_kernel_ns = kernel_ns; 1282 vcpu->last_kernel_ns = kernel_ns;
1230 vcpu->last_guest_tsc = tsc_timestamp; 1283 vcpu->last_guest_tsc = tsc_timestamp;
1231 1284
1232
1233 /* 1285 /*
1234 * The interface expects us to write an even number signaling that the 1286 * The interface expects us to write an even number signaling that the
1235 * update is finished. Since the guest won't see the intermediate 1287 * update is finished. Since the guest won't see the intermediate
@@ -4857,6 +4909,39 @@ static void kvm_set_mmio_spte_mask(void)
4857 kvm_mmu_set_mmio_spte_mask(mask); 4909 kvm_mmu_set_mmio_spte_mask(mask);
4858} 4910}
4859 4911
4912#ifdef CONFIG_X86_64
4913static void pvclock_gtod_update_fn(struct work_struct *work)
4914{
4915}
4916
4917static DECLARE_WORK(pvclock_gtod_work, pvclock_gtod_update_fn);
4918
4919/*
4920 * Notification about pvclock gtod data update.
4921 */
4922static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,
4923 void *priv)
4924{
4925 struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
4926 struct timekeeper *tk = priv;
4927
4928 update_pvclock_gtod(tk);
4929
4930 /* disable master clock if host does not trust, or does not
4931 * use, TSC clocksource
4932 */
4933 if (gtod->clock.vclock_mode != VCLOCK_TSC &&
4934 atomic_read(&kvm_guest_has_master_clock) != 0)
4935 queue_work(system_long_wq, &pvclock_gtod_work);
4936
4937 return 0;
4938}
4939
4940static struct notifier_block pvclock_gtod_notifier = {
4941 .notifier_call = pvclock_gtod_notify,
4942};
4943#endif
4944
4860int kvm_arch_init(void *opaque) 4945int kvm_arch_init(void *opaque)
4861{ 4946{
4862 int r; 4947 int r;
@@ -4898,6 +4983,10 @@ int kvm_arch_init(void *opaque)
4898 host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); 4983 host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
4899 4984
4900 kvm_lapic_init(); 4985 kvm_lapic_init();
4986#ifdef CONFIG_X86_64
4987 pvclock_gtod_register_notifier(&pvclock_gtod_notifier);
4988#endif
4989
4901 return 0; 4990 return 0;
4902 4991
4903out: 4992out:
@@ -4912,6 +5001,9 @@ void kvm_arch_exit(void)
4912 cpufreq_unregister_notifier(&kvmclock_cpufreq_notifier_block, 5001 cpufreq_unregister_notifier(&kvmclock_cpufreq_notifier_block,
4913 CPUFREQ_TRANSITION_NOTIFIER); 5002 CPUFREQ_TRANSITION_NOTIFIER);
4914 unregister_hotcpu_notifier(&kvmclock_cpu_notifier_block); 5003 unregister_hotcpu_notifier(&kvmclock_cpu_notifier_block);
5004#ifdef CONFIG_X86_64
5005 pvclock_gtod_unregister_notifier(&pvclock_gtod_notifier);
5006#endif
4915 kvm_x86_ops = NULL; 5007 kvm_x86_ops = NULL;
4916 kvm_mmu_module_exit(); 5008 kvm_mmu_module_exit();
4917} 5009}