diff options
author | Joerg Roedel <joerg.roedel@amd.com> | 2011-03-25 04:44:49 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:57:05 -0400 |
commit | 4051b18801f5b47bb0369feefdc80e57819d0ddf (patch) | |
tree | ac0b50efc768bbf7bfe42fcd70e9d97bf46185b9 | |
parent | 8f6055cbaf68cbd9ff2692a2cfa691b43629ccd4 (diff) |
KVM: X86: Implement call-back to propagate virtual_tsc_khz
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>
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 33 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 11 |
3 files changed, 45 insertions, 0 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index e3aaa02ca032..f3a7116f802f 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -606,6 +606,7 @@ struct kvm_x86_ops { | |||
606 | 606 | ||
607 | bool (*has_wbinvd_exit)(void); | 607 | bool (*has_wbinvd_exit)(void); |
608 | 608 | ||
609 | void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz); | ||
609 | void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset); | 610 | void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset); |
610 | 611 | ||
611 | void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2); | 612 | void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2); |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 830150099958..a39fde4f5fe8 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -885,6 +885,38 @@ static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc) | |||
885 | return _tsc; | 885 | return _tsc; |
886 | } | 886 | } |
887 | 887 | ||
888 | static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) | ||
889 | { | ||
890 | struct vcpu_svm *svm = to_svm(vcpu); | ||
891 | u64 ratio; | ||
892 | u64 khz; | ||
893 | |||
894 | /* TSC scaling supported? */ | ||
895 | if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) | ||
896 | return; | ||
897 | |||
898 | /* TSC-Scaling disabled or guest TSC same frequency as host TSC? */ | ||
899 | if (user_tsc_khz == 0) { | ||
900 | vcpu->arch.virtual_tsc_khz = 0; | ||
901 | svm->tsc_ratio = TSC_RATIO_DEFAULT; | ||
902 | return; | ||
903 | } | ||
904 | |||
905 | khz = user_tsc_khz; | ||
906 | |||
907 | /* TSC scaling required - calculate ratio */ | ||
908 | ratio = khz << 32; | ||
909 | do_div(ratio, tsc_khz); | ||
910 | |||
911 | if (ratio == 0 || ratio & TSC_RATIO_RSVD) { | ||
912 | WARN_ONCE(1, "Invalid TSC ratio - virtual-tsc-khz=%u\n", | ||
913 | user_tsc_khz); | ||
914 | return; | ||
915 | } | ||
916 | vcpu->arch.virtual_tsc_khz = user_tsc_khz; | ||
917 | svm->tsc_ratio = ratio; | ||
918 | } | ||
919 | |||
888 | static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) | 920 | static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) |
889 | { | 921 | { |
890 | struct vcpu_svm *svm = to_svm(vcpu); | 922 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -4159,6 +4191,7 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
4159 | 4191 | ||
4160 | .has_wbinvd_exit = svm_has_wbinvd_exit, | 4192 | .has_wbinvd_exit = svm_has_wbinvd_exit, |
4161 | 4193 | ||
4194 | .set_tsc_khz = svm_set_tsc_khz, | ||
4162 | .write_tsc_offset = svm_write_tsc_offset, | 4195 | .write_tsc_offset = svm_write_tsc_offset, |
4163 | .adjust_tsc_offset = svm_adjust_tsc_offset, | 4196 | .adjust_tsc_offset = svm_adjust_tsc_offset, |
4164 | 4197 | ||
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 3dfefe3bcd05..e19c7a5473d5 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -1161,6 +1161,16 @@ static u64 guest_read_tsc(void) | |||
1161 | } | 1161 | } |
1162 | 1162 | ||
1163 | /* | 1163 | /* |
1164 | * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ | ||
1165 | * ioctl. In this case the call-back should update internal vmx state to make | ||
1166 | * the changes effective. | ||
1167 | */ | ||
1168 | static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) | ||
1169 | { | ||
1170 | /* Nothing to do here */ | ||
1171 | } | ||
1172 | |||
1173 | /* | ||
1164 | * writes 'offset' into guest's timestamp counter offset register | 1174 | * writes 'offset' into guest's timestamp counter offset register |
1165 | */ | 1175 | */ |
1166 | static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) | 1176 | static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) |
@@ -4497,6 +4507,7 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
4497 | 4507 | ||
4498 | .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit, | 4508 | .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit, |
4499 | 4509 | ||
4510 | .set_tsc_khz = vmx_set_tsc_khz, | ||
4500 | .write_tsc_offset = vmx_write_tsc_offset, | 4511 | .write_tsc_offset = vmx_write_tsc_offset, |
4501 | .adjust_tsc_offset = vmx_adjust_tsc_offset, | 4512 | .adjust_tsc_offset = vmx_adjust_tsc_offset, |
4502 | 4513 | ||