KVM: X86: Implement call-back to propagate virtual_tsc_khz
authorJoerg Roedel <joerg.roedel@amd.com>
Fri, 25 Mar 2011 08:44:49 +0000 (09:44 +0100)
committerAvi Kivity <avi@redhat.com>
Wed, 11 May 2011 11:57:05 +0000 (07:57 -0400)
This patch implements a call-back into the architecture code
to allow the propagation of changes to the virtual tsc_khz
of the vcpu.
On SVM it updates the tsc_ratio variable, on VMX it does
nothing.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c

index e3aaa02..f3a7116 100644 (file)
@@ -606,6 +606,7 @@ struct kvm_x86_ops {
 
        bool (*has_wbinvd_exit)(void);
 
+       void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz);
        void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
        void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
index 8301500..a39fde4 100644 (file)
@@ -885,6 +885,38 @@ static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
        return _tsc;
 }
 
+static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+       u64 ratio;
+       u64 khz;
+
+       /* TSC scaling supported? */
+       if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
+               return;
+
+       /* TSC-Scaling disabled or guest TSC same frequency as host TSC? */
+       if (user_tsc_khz == 0) {
+               vcpu->arch.virtual_tsc_khz = 0;
+               svm->tsc_ratio = TSC_RATIO_DEFAULT;
+               return;
+       }
+
+       khz = user_tsc_khz;
+
+       /* TSC scaling required  - calculate ratio */
+       ratio = khz << 32;
+       do_div(ratio, tsc_khz);
+
+       if (ratio == 0 || ratio & TSC_RATIO_RSVD) {
+               WARN_ONCE(1, "Invalid TSC ratio - virtual-tsc-khz=%u\n",
+                               user_tsc_khz);
+               return;
+       }
+       vcpu->arch.virtual_tsc_khz = user_tsc_khz;
+       svm->tsc_ratio             = ratio;
+}
+
 static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -4159,6 +4191,7 @@ static struct kvm_x86_ops svm_x86_ops = {
 
        .has_wbinvd_exit = svm_has_wbinvd_exit,
 
+       .set_tsc_khz = svm_set_tsc_khz,
        .write_tsc_offset = svm_write_tsc_offset,
        .adjust_tsc_offset = svm_adjust_tsc_offset,
 
index 3dfefe3..e19c7a5 100644 (file)
@@ -1160,6 +1160,16 @@ static u64 guest_read_tsc(void)
        return host_tsc + tsc_offset;
 }
 
+/*
+ * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
+ * ioctl. In this case the call-back should update internal vmx state to make
+ * the changes effective.
+ */
+static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+{
+       /* Nothing to do here */
+}
+
 /*
  * writes 'offset' into guest's timestamp counter offset register
  */
@@ -4497,6 +4507,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
 
        .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
 
+       .set_tsc_khz = vmx_set_tsc_khz,
        .write_tsc_offset = vmx_write_tsc_offset,
        .adjust_tsc_offset = vmx_adjust_tsc_offset,