@@ -888,6 +888,36 @@ static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
return _tsc;
}
+static bool svm_vcpu_init_tsc(struct kvm *kvm, struct vcpu_svm *svm)
+{
+ u64 ratio;
+ u64 khz;
+
+ /* TSC scaling supported? */
+ if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
+ return true;
+
+ /* Guest tsc same frequency as host tsc? */
+ if (kvm->arch.virtual_tsc_khz == tsc_khz)
+ return true;
+
+ khz = kvm->arch.virtual_tsc_khz;
+
+ if (khz == 0)
+ return false;
+
+ /* TSC scaling required - calculate ratio */
+ ratio = (u64)khz << 32;
+ do_div(ratio, tsc_khz);
+ if (ratio == 0 || ratio & TSC_RATIO_RSVD)
+ return false;
+
+ svm->tsc_scale.ratio = ratio;
+ svm->tsc_scale.enabled = true;
+
+ return true;
+}
+
static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1093,6 +1123,9 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
if (err)
goto free_svm;
+ if (!svm_vcpu_init_tsc(kvm, svm))
+ goto uninit;
+
err = -ENOMEM;
page = alloc_page(GFP_KERNEL);
if (!page)