linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/12] KVM: x86: add support for VMX TSC scaling
@ 2015-09-28  5:37 Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio Haozhong Zhang
                   ` (12 more replies)
  0 siblings, 13 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:37 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patchset adds support for VMX TSC scaling feature which is
available on Intel Skylake CPU. The specification of VMX TSC scaling
can be found at
http://www.intel.com/content/www/us/en/processors/timestamp-counter-scaling-virtualization-white-paper.html

VMX TSC scaling allows guest TSC which is read by guest rdtsc(p)
instructions increases in a rate that is customized by the hypervisor
and can be different than the host TSC rate. Basically, VMX TSC
scaling adds a 64-bit field called TSC multiplier in VMCS so that, if
VMX TSC scaling is enabled, TSC read by guest rdtsc(p) instructions
will be calculated by the following formula:

  guest EDX:EAX = (Host TSC * TSC multiplier) >> 48 + VMX TSC Offset

where, Host TSC = Host MSR_IA32_TSC + Host MSR_IA32_TSC_ADJUST.

This patchset, when cooperating with another QEMU patchset (sent in
another email "target-i386: save/restore vcpu's TSC rate during
migration"), allows guest programs observe a consistent TSC rate even
though they are migrated among machines with different host TSC rates.

VMX TSC scaling shares some common logics with SVM TSC scaling which
is already supported by KVM. Patch 1 ~ 8 move those common logics from
SVM code to the common code. Upon them, patch 9 ~ 12 add VMX-specific
support for VMX TSC scaling.

Haozhong Zhang (12):
  KVM: x86: Collect information for setting TSC scaling ratio
  KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch
  KVM: x86: Add a common TSC scaling function
  KVM: x86: Replace call-back set_tsc_khz() with a common function
  KVM: x86: Replace call-back compute_tsc_offset() with a common function
  KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset()
  KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc()
  KVM: x86: Use the correct vcpu's TSC rate to compute time scale
  KVM: VMX: Enable and initialize VMX TSC scaling
  KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded
  KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC
  KVM: VMX: Dump TSC multiplier in dump_vmcs()

 arch/x86/include/asm/kvm_host.h |  24 +++----
 arch/x86/include/asm/vmx.h      |   4 +-
 arch/x86/kvm/lapic.c            |   5 +-
 arch/x86/kvm/svm.c              | 113 +++--------------------------
 arch/x86/kvm/vmx.c              |  60 ++++++++--------
 arch/x86/kvm/x86.c              | 154 +++++++++++++++++++++++++++++++++++++---
 include/linux/kvm_host.h        |  21 +++++-
 7 files changed, 221 insertions(+), 160 deletions(-)

--
2.4.8


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-29  3:28   ` Eric Northup
  2015-09-28  5:38 ` [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch Haozhong Zhang
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

The number of bits of the fractional part of the 64-bit TSC scaling
ratio in VMX and SVM is different. This patch makes the architecture
code to collect the number of fractional bits and other related
information into variables that can be accessed in the common code.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/kvm_host.h | 8 ++++++++
 arch/x86/kvm/svm.c              | 5 +++++
 arch/x86/kvm/x86.c              | 8 ++++++++
 3 files changed, 21 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 2beee03..5b9b86e 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -965,6 +965,14 @@ extern bool kvm_has_tsc_control;
 extern u32  kvm_min_guest_tsc_khz;
 /* maximum supported tsc_khz for guests */
 extern u32  kvm_max_guest_tsc_khz;
+/* number of bits of the fractional part of the TSC scaling ratio */
+extern u8   kvm_tsc_scaling_ratio_frac_bits;
+/* reserved bits of TSC scaling ratio (SBZ) */
+extern u64  kvm_tsc_scaling_ratio_rsvd;
+/* default TSC scaling ratio (= 1.0) */
+extern u64  kvm_default_tsc_scaling_ratio;
+/* maximum allowed value of TSC scaling ratio */
+extern u64  kvm_max_tsc_scaling_ratio;
 
 enum emulation_result {
 	EMULATE_DONE,         /* no further processing */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 94b7d15..eff7db7 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -963,7 +963,12 @@ static __init int svm_hardware_setup(void)
 		max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
 
 		kvm_max_guest_tsc_khz = max;
+
+		kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX;
+		kvm_tsc_scaling_ratio_frac_bits = 32;
+		kvm_tsc_scaling_ratio_rsvd = TSC_RATIO_RSVD;
 	}
+	kvm_default_tsc_scaling_ratio = TSC_RATIO_DEFAULT;
 
 	if (nested) {
 		printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 991466b..f888225 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -106,6 +106,14 @@ bool kvm_has_tsc_control;
 EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
 u32  kvm_max_guest_tsc_khz;
 EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
+u8   kvm_tsc_scaling_ratio_frac_bits;
+EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits);
+u64  kvm_tsc_scaling_ratio_rsvd;
+EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_rsvd);
+u64  kvm_default_tsc_scaling_ratio;
+EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio);
+u64  kvm_max_tsc_scaling_ratio;
+EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
 
 /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
 static u32 tsc_tolerance_ppm = 250;
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-10-05 19:26   ` Radim Krčmář
  2015-09-28  5:38 ` [PATCH 03/12] KVM: x86: Add a common TSC scaling function Haozhong Zhang
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patch moves the field of TSC scaling ratio from the architecture
struct vcpu_svm to the common struct kvm_vcpu_arch.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/svm.c              | 23 +++++++++--------------
 arch/x86/kvm/x86.c              |  3 +++
 3 files changed, 13 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 5b9b86e..4f32c68 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -500,6 +500,7 @@ struct kvm_vcpu_arch {
 	u32 virtual_tsc_mult;
 	u32 virtual_tsc_khz;
 	s64 ia32_tsc_adjust_msr;
+	u64 tsc_scaling_ratio;
 
 	atomic_t nmi_queued;  /* unprocessed asynchronous NMIs */
 	unsigned nmi_pending; /* NMI queued after currently running handler */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index eff7db7..a3186e2 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -157,8 +157,6 @@ struct vcpu_svm {
 	unsigned int3_injected;
 	unsigned long int3_rip;
 	u32 apf_reason;
-
-	u64  tsc_ratio;
 };
 
 static DEFINE_PER_CPU(u64, current_tsc_ratio);
@@ -1049,24 +1047,22 @@ static u64 __scale_tsc(u64 ratio, u64 tsc)
 
 static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
 {
-	struct vcpu_svm *svm = to_svm(vcpu);
 	u64 _tsc = tsc;
 
-	if (svm->tsc_ratio != TSC_RATIO_DEFAULT)
-		_tsc = __scale_tsc(svm->tsc_ratio, tsc);
+	if (vcpu->arch.tsc_scaling_ratio != TSC_RATIO_DEFAULT)
+		_tsc = __scale_tsc(vcpu->arch.tsc_scaling_ratio, tsc);
 
 	return _tsc;
 }
 
 static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
-	struct vcpu_svm *svm = to_svm(vcpu);
 	u64 ratio;
 	u64 khz;
 
 	/* Guest TSC same frequency as host TSC? */
 	if (!scale) {
-		svm->tsc_ratio = TSC_RATIO_DEFAULT;
+		vcpu->arch.tsc_scaling_ratio = TSC_RATIO_DEFAULT;
 		return;
 	}
 
@@ -1091,7 +1087,7 @@ static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 				user_tsc_khz);
 		return;
 	}
-	svm->tsc_ratio             = ratio;
+	vcpu->arch.tsc_scaling_ratio = ratio;
 }
 
 static u64 svm_read_tsc_offset(struct kvm_vcpu *vcpu)
@@ -1125,7 +1121,7 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
 	struct vcpu_svm *svm = to_svm(vcpu);
 
 	if (host) {
-		if (svm->tsc_ratio != TSC_RATIO_DEFAULT)
+		if (vcpu->arch.tsc_scaling_ratio != TSC_RATIO_DEFAULT)
 			WARN_ON(adjustment < 0);
 		adjustment = svm_scale_tsc(vcpu, (u64)adjustment);
 	}
@@ -1335,8 +1331,6 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
 		goto out;
 	}
 
-	svm->tsc_ratio = TSC_RATIO_DEFAULT;
-
 	err = kvm_vcpu_init(&svm->vcpu, kvm, id);
 	if (err)
 		goto free_svm;
@@ -1406,6 +1400,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 	int i;
+	u64 tsc_ratio = vcpu->arch.tsc_scaling_ratio;
 
 	if (unlikely(cpu != vcpu->cpu)) {
 		svm->asid_generation = 0;
@@ -1423,9 +1418,9 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
 
 	if (static_cpu_has(X86_FEATURE_TSCRATEMSR) &&
-	    svm->tsc_ratio != __this_cpu_read(current_tsc_ratio)) {
-		__this_cpu_write(current_tsc_ratio, svm->tsc_ratio);
-		wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_ratio);
+	    tsc_ratio != __this_cpu_read(current_tsc_ratio)) {
+		__this_cpu_write(current_tsc_ratio, tsc_ratio);
+		wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio);
 	}
 }
 
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index f888225..4a521b4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7080,6 +7080,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 
 	vcpu = kvm_x86_ops->vcpu_create(kvm, id);
 
+	if (!IS_ERR(vcpu))
+		vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
+
 	return vcpu;
 }
 
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 03/12] KVM: x86: Add a common TSC scaling function
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28 20:12   ` Paolo Bonzini
  2015-09-28  5:38 ` [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function Haozhong Zhang
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

VMX and SVM calculate the TSC scaling ratio in a similar logic, so this
patch generalizes it to a common TSC scaling function.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/kvm/svm.c       | 48 +++------------------------------
 arch/x86/kvm/x86.c       | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/kvm_host.h |  4 ++-
 3 files changed, 77 insertions(+), 45 deletions(-)

diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index a3186e2..1a333bd 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -209,7 +209,6 @@ static int nested_svm_intercept(struct vcpu_svm *svm);
 static int nested_svm_vmexit(struct vcpu_svm *svm);
 static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
 				      bool has_error_code, u32 error_code);
-static u64 __scale_tsc(u64 ratio, u64 tsc);
 
 enum {
 	VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
@@ -947,21 +946,7 @@ static __init int svm_hardware_setup(void)
 		kvm_enable_efer_bits(EFER_FFXSR);
 
 	if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
-		u64 max;
-
 		kvm_has_tsc_control = true;
-
-		/*
-		 * Make sure the user can only configure tsc_khz values that
-		 * fit into a signed integer.
-		 * A min value is not calculated needed because it will always
-		 * be 1 on all machines and a value of 0 is used to disable
-		 * tsc-scaling for the vcpu.
-		 */
-		max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
-
-		kvm_max_guest_tsc_khz = max;
-
 		kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX;
 		kvm_tsc_scaling_ratio_frac_bits = 32;
 		kvm_tsc_scaling_ratio_rsvd = TSC_RATIO_RSVD;
@@ -1030,31 +1015,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
 	seg->base = 0;
 }
 
-static u64 __scale_tsc(u64 ratio, u64 tsc)
-{
-	u64 mult, frac, _tsc;
-
-	mult  = ratio >> 32;
-	frac  = ratio & ((1ULL << 32) - 1);
-
-	_tsc  = tsc;
-	_tsc *= mult;
-	_tsc += (tsc >> 32) * frac;
-	_tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
-
-	return _tsc;
-}
-
-static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
-{
-	u64 _tsc = tsc;
-
-	if (vcpu->arch.tsc_scaling_ratio != TSC_RATIO_DEFAULT)
-		_tsc = __scale_tsc(vcpu->arch.tsc_scaling_ratio, tsc);
-
-	return _tsc;
-}
-
 static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
 {
 	u64 ratio;
@@ -1123,7 +1083,7 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
 	if (host) {
 		if (vcpu->arch.tsc_scaling_ratio != TSC_RATIO_DEFAULT)
 			WARN_ON(adjustment < 0);
-		adjustment = svm_scale_tsc(vcpu, (u64)adjustment);
+		adjustment = kvm_scale_tsc(vcpu, (u64)adjustment);
 	}
 
 	svm->vmcb->control.tsc_offset += adjustment;
@@ -1141,7 +1101,7 @@ static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
 {
 	u64 tsc;
 
-	tsc = svm_scale_tsc(vcpu, rdtsc());
+	tsc = kvm_scale_tsc(vcpu, rdtsc());
 
 	return target_tsc - tsc;
 }
@@ -3166,7 +3126,7 @@ static u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
 {
 	struct vmcb *vmcb = get_host_vmcb(to_svm(vcpu));
 	return vmcb->control.tsc_offset +
-		svm_scale_tsc(vcpu, host_tsc);
+		kvm_scale_tsc(vcpu, host_tsc);
 }
 
 static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
@@ -3176,7 +3136,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	switch (msr_info->index) {
 	case MSR_IA32_TSC: {
 		msr_info->data = svm->vmcb->control.tsc_offset +
-			svm_scale_tsc(vcpu, rdtsc());
+			kvm_scale_tsc(vcpu, rdtsc());
 
 		break;
 	}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4a521b4..920c302 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1321,6 +1321,64 @@ static void update_ia32_tsc_adjust_msr(struct kvm_vcpu *vcpu, s64 offset)
 	vcpu->arch.ia32_tsc_adjust_msr += offset - curr_offset;
 }
 
+/*
+ * Multiply tsc by a fixed point number represented by ratio.
+ *
+ * The most significant 64-N bits (mult) of ratio represent the
+ * integral part of the fixed point number; the remaining N bits
+ * (frac) represent the fractional part, ie. ratio represents a fixed
+ * point number (mult + frac * 2^(-N)).
+ *
+ * N.B: we always assume not all 64 bits of ratio are used for the
+ * fractional part and the ratio has at least 1 bit for the fractional
+ * part, i.e. 0 < N < 64.
+ *
+ * N equals to kvm_tsc_scaling_ratio_frac_bits.
+ */
+static u64 __scale_tsc(u64 ratio, u64 tsc)
+{
+	u64 mult, frac, mask, _tsc;
+	int width, nr;
+
+	BUG_ON(kvm_tsc_scaling_ratio_frac_bits >= 64 ||
+	       kvm_tsc_scaling_ratio_frac_bits == 0);
+
+	mult  = ratio >> kvm_tsc_scaling_ratio_frac_bits;
+	mask  = (1ULL << kvm_tsc_scaling_ratio_frac_bits) - 1;
+	frac  = ratio & mask;
+
+	width = 64 - kvm_tsc_scaling_ratio_frac_bits;
+	mask  = (1ULL << width) - 1;
+	nr    = kvm_tsc_scaling_ratio_frac_bits;
+
+	_tsc  = tsc;
+	_tsc *= mult;
+	_tsc += (tsc >> kvm_tsc_scaling_ratio_frac_bits) * frac;
+
+	while (nr >= width) {
+		_tsc += (((tsc >> (nr - width)) & mask) * frac) >> (64 - nr);
+		nr   -= width;
+	}
+
+	if (nr > 0)
+		_tsc += ((tsc & ((1ULL << nr) - 1)) * frac) >>
+			kvm_tsc_scaling_ratio_frac_bits;
+
+	return _tsc;
+}
+
+u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+{
+	u64 _tsc = tsc;
+	u64 ratio = vcpu->arch.tsc_scaling_ratio;
+
+	if (ratio != kvm_default_tsc_scaling_ratio)
+		_tsc = __scale_tsc(ratio, tsc);
+
+	return _tsc;
+}
+EXPORT_SYMBOL_GPL(kvm_scale_tsc);
+
 void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -7290,6 +7348,18 @@ int kvm_arch_hardware_setup(void)
 	if (r != 0)
 		return r;
 
+	/*
+	 * Make sure the user can only configure tsc_khz values that
+	 * fit into a signed integer.
+	 * A min value is not calculated needed because it will always
+	 * be 1 on all machines.
+	 */
+	if (kvm_has_tsc_control) {
+		u64 max = min(0x7fffffffULL,
+			      __scale_tsc(kvm_max_tsc_scaling_ratio, tsc_khz));
+		kvm_max_guest_tsc_khz = max;
+	}
+
 	kvm_init_msr_list();
 	return 0;
 }
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 1bef9e2..3c43e3e 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1144,5 +1144,7 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
 {
 }
 #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
-#endif
 
+u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc);
+
+#endif
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (2 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 03/12] KVM: x86: Add a common TSC scaling function Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
       [not found]   ` <CAG7+5M3z2-OKsy0wxxks2oW9+7WmFpO4JQETTx3KsaW-hWMGqw@mail.gmail.com>
  2015-10-05 19:53   ` Radim Krčmář
  2015-09-28  5:38 ` [PATCH 05/12] KVM: x86: Replace call-back compute_tsc_offset() " Haozhong Zhang
                   ` (8 subsequent siblings)
  12 siblings, 2 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

Both VMX and SVM propagate virtual_tsc_khz in the same way, so this
patch removes the call-back set_tsc_khz() and replaces it with a common
function.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/kvm_host.h |  1 -
 arch/x86/kvm/svm.c              | 36 ------------------------------------
 arch/x86/kvm/vmx.c              | 17 -----------------
 arch/x86/kvm/x86.c              | 41 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 40 insertions(+), 55 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 4f32c68..5a0c435 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -842,7 +842,6 @@ struct kvm_x86_ops {
 
 	bool (*has_wbinvd_exit)(void);
 
-	void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale);
 	u64 (*read_tsc_offset)(struct kvm_vcpu *vcpu);
 	void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 1a333bd..d46dcf3 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1015,41 +1015,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
 	seg->base = 0;
 }
 
-static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
-{
-	u64 ratio;
-	u64 khz;
-
-	/* Guest TSC same frequency as host TSC? */
-	if (!scale) {
-		vcpu->arch.tsc_scaling_ratio = TSC_RATIO_DEFAULT;
-		return;
-	}
-
-	/* TSC scaling supported? */
-	if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
-		if (user_tsc_khz > tsc_khz) {
-			vcpu->arch.tsc_catchup = 1;
-			vcpu->arch.tsc_always_catchup = 1;
-		} else
-			WARN(1, "user requested TSC rate below hardware speed\n");
-		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.tsc_scaling_ratio = ratio;
-}
-
 static u64 svm_read_tsc_offset(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -4507,7 +4472,6 @@ static struct kvm_x86_ops svm_x86_ops = {
 
 	.has_wbinvd_exit = svm_has_wbinvd_exit,
 
-	.set_tsc_khz = svm_set_tsc_khz,
 	.read_tsc_offset = svm_read_tsc_offset,
 	.write_tsc_offset = svm_write_tsc_offset,
 	.adjust_tsc_offset = svm_adjust_tsc_offset,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 6407674..1751537 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2255,22 +2255,6 @@ static u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
 	return host_tsc + tsc_offset;
 }
 
-/*
- * Engage any workarounds for mis-matched TSC rates.  Currently limited to
- * software catchup for faster rates on slower CPUs.
- */
-static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
-{
-	if (!scale)
-		return;
-
-	if (user_tsc_khz > tsc_khz) {
-		vcpu->arch.tsc_catchup = 1;
-		vcpu->arch.tsc_always_catchup = 1;
-	} else
-		WARN(1, "user requested TSC rate below hardware speed\n");
-}
-
 static u64 vmx_read_tsc_offset(struct kvm_vcpu *vcpu)
 {
 	return vmcs_read64(TSC_OFFSET);
@@ -10380,7 +10364,6 @@ static struct kvm_x86_ops vmx_x86_ops = {
 
 	.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
 
-	.set_tsc_khz = vmx_set_tsc_khz,
 	.read_tsc_offset = vmx_read_tsc_offset,
 	.write_tsc_offset = vmx_write_tsc_offset,
 	.adjust_tsc_offset = vmx_adjust_tsc_offset,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 920c302..e2e1fdb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1248,6 +1248,45 @@ static u32 adjust_tsc_khz(u32 khz, s32 ppm)
 	return v;
 }
 
+static void set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
+{
+	u64 ratio, khz;
+	s8 shift;
+
+	/* Guest TSC same frequency as host TSC? */
+	if (!scale) {
+		vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
+		return;
+	}
+
+	/* TSC scaling supported? */
+	if (!kvm_has_tsc_control) {
+		if (user_tsc_khz > tsc_khz) {
+			vcpu->arch.tsc_catchup = 1;
+			vcpu->arch.tsc_always_catchup = 1;
+		} else
+			WARN(1, "user requested TSC rate below hardware speed\n");
+		return;
+	}
+
+	khz = user_tsc_khz;
+
+	/* TSC scaling required  - calculate ratio */
+	shift = (kvm_tsc_scaling_ratio_frac_bits <= 32) ?
+		kvm_tsc_scaling_ratio_frac_bits : 32;
+	ratio = khz << shift;
+	do_div(ratio, tsc_khz);
+	ratio <<= (kvm_tsc_scaling_ratio_frac_bits - shift);
+
+	if (ratio == 0 || ratio & kvm_tsc_scaling_ratio_rsvd) {
+		WARN_ONCE(1, "Invalid TSC scaling ratio - virtual-tsc-khz=%u\n",
+			  user_tsc_khz);
+		return;
+	}
+
+	vcpu->arch.tsc_scaling_ratio = ratio;
+}
+
 static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
 {
 	u32 thresh_lo, thresh_hi;
@@ -1275,7 +1314,7 @@ static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
 		pr_debug("kvm: requested TSC rate %u falls outside tolerance [%u,%u]\n", this_tsc_khz, thresh_lo, thresh_hi);
 		use_scaling = 1;
 	}
-	kvm_x86_ops->set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
+	set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
 }
 
 static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 05/12] KVM: x86: Replace call-back compute_tsc_offset() with a common function
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (3 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset() Haozhong Zhang
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

Both VMX and SVM calculate the tsc-offset in the same way, so this
patch removes the call-back compute_tsc_offset() and replaces it with a
common function kvm_compute_tsc_offset().

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/kvm_host.h |  1 -
 arch/x86/kvm/svm.c              | 10 ----------
 arch/x86/kvm/vmx.c              |  6 ------
 arch/x86/kvm/x86.c              | 15 ++++++++++++---
 4 files changed, 12 insertions(+), 20 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 5a0c435..0bbb2a7 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -845,7 +845,6 @@ struct kvm_x86_ops {
 	u64 (*read_tsc_offset)(struct kvm_vcpu *vcpu);
 	void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
 
-	u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
 	u64 (*read_l1_tsc)(struct kvm_vcpu *vcpu, u64 host_tsc);
 
 	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 d46dcf3..c49cd28 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1062,15 +1062,6 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
 	mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
 }
 
-static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
-{
-	u64 tsc;
-
-	tsc = kvm_scale_tsc(vcpu, rdtsc());
-
-	return target_tsc - tsc;
-}
-
 static void svm_set_guest_pat(struct vcpu_svm *svm, u64 *g_pat)
 {
 	struct kvm_vcpu *vcpu = &svm->vcpu;
@@ -4475,7 +4466,6 @@ static struct kvm_x86_ops svm_x86_ops = {
 	.read_tsc_offset = svm_read_tsc_offset,
 	.write_tsc_offset = svm_write_tsc_offset,
 	.adjust_tsc_offset = svm_adjust_tsc_offset,
-	.compute_tsc_offset = svm_compute_tsc_offset,
 	.read_l1_tsc = svm_read_l1_tsc,
 
 	.set_tdp_cr3 = set_tdp_cr3,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 1751537..7a71191 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2299,11 +2299,6 @@ static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
 					   offset + adjustment);
 }
 
-static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
-{
-	return target_tsc - rdtsc();
-}
-
 static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
 {
 	struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0);
@@ -10367,7 +10362,6 @@ static struct kvm_x86_ops vmx_x86_ops = {
 	.read_tsc_offset = vmx_read_tsc_offset,
 	.write_tsc_offset = vmx_write_tsc_offset,
 	.adjust_tsc_offset = vmx_adjust_tsc_offset,
-	.compute_tsc_offset = vmx_compute_tsc_offset,
 	.read_l1_tsc = vmx_read_l1_tsc,
 
 	.set_tdp_cr3 = vmx_set_cr3,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e2e1fdb..7c372ad 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1418,6 +1418,15 @@ u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
 }
 EXPORT_SYMBOL_GPL(kvm_scale_tsc);
 
+static u64 kvm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+{
+	u64 tsc;
+
+	tsc = kvm_scale_tsc(vcpu, rdtsc());
+
+	return target_tsc - tsc;
+}
+
 void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -1429,7 +1438,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
 	u64 data = msr->data;
 
 	raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
-	offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
+	offset = kvm_compute_tsc_offset(vcpu, data);
 	ns = get_kernel_ns();
 	elapsed = ns - kvm->arch.last_tsc_nsec;
 
@@ -1486,7 +1495,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
 		} else {
 			u64 delta = nsec_to_cycles(vcpu, elapsed);
 			data += delta;
-			offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
+			offset = kvm_compute_tsc_offset(vcpu, data);
 			pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
 		}
 		matched = true;
@@ -2720,7 +2729,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 		if (tsc_delta < 0)
 			mark_tsc_unstable("KVM discovered backwards TSC");
 		if (check_tsc_unstable()) {
-			u64 offset = kvm_x86_ops->compute_tsc_offset(vcpu,
+			u64 offset = kvm_compute_tsc_offset(vcpu,
 						vcpu->arch.last_guest_tsc);
 			kvm_x86_ops->write_tsc_offset(vcpu, offset);
 			vcpu->arch.tsc_catchup = 1;
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset()
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (4 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 05/12] KVM: x86: Replace call-back compute_tsc_offset() " Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28 20:14   ` Paolo Bonzini
  2015-09-28  5:38 ` [PATCH 07/12] KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc() Haozhong Zhang
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

For both VMX and SVM, if the 2nd argument of call-back
adjust_tsc_offset() is the host TSC, then adjust_tsc_offset() will scale
it first. This patch moves this common TSC scaling logic to its caller
adjust_tsc_offset_host().

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/kvm_host.h | 13 -------------
 arch/x86/kvm/svm.c              |  6 ------
 include/linux/kvm_host.h        | 15 +++++++++++++++
 3 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 0bbb2a7..67b4a96 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -895,19 +895,6 @@ struct kvm_arch_async_pf {
 	bool direct_map;
 };
 
-extern struct kvm_x86_ops *kvm_x86_ops;
-
-static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
-					   s64 adjustment)
-{
-	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
-}
-
-static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
-{
-	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
-}
-
 int kvm_mmu_module_init(void);
 void kvm_mmu_module_exit(void);
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index c49cd28..239263f3 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1045,12 +1045,6 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
 
-	if (host) {
-		if (vcpu->arch.tsc_scaling_ratio != TSC_RATIO_DEFAULT)
-			WARN_ON(adjustment < 0);
-		adjustment = kvm_scale_tsc(vcpu, (u64)adjustment);
-	}
-
 	svm->vmcb->control.tsc_offset += adjustment;
 	if (is_guest_mode(vcpu))
 		svm->nested.hsave->control.tsc_offset += adjustment;
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 3c43e3e..2a21845 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1146,5 +1146,20 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
 #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
 
 u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc);
+extern struct kvm_x86_ops *kvm_x86_ops;
+
+static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
+					   s64 adjustment)
+{
+	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
+}
+
+static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+	if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
+		WARN_ON(adjustment < 0);
+	adjustment = kvm_scale_tsc(vcpu, (u64) adjustment);
+	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
+}
 
 #endif
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 07/12] KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc()
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (5 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset() Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 08/12] KVM: x86: Use the correct vcpu's TSC rate to compute time scale Haozhong Zhang
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

Both VMX and SVM scales the host TSC in the same way in call-back
read_l1_tsc(), so this patch moves the scaling logic from call-back
read_l1_tsc() to a common function kvm_read_l1_tsc().

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/kvm/lapic.c     |  5 ++---
 arch/x86/kvm/svm.c       |  3 +--
 arch/x86/kvm/x86.c       | 11 ++++++++---
 include/linux/kvm_host.h |  2 ++
 4 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 8d9013c..b3bb4c9 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1,4 +1,3 @@
-
 /*
  * Local APIC virtualization
  *
@@ -1172,7 +1171,7 @@ void wait_lapic_expire(struct kvm_vcpu *vcpu)
 
 	tsc_deadline = apic->lapic_timer.expired_tscdeadline;
 	apic->lapic_timer.expired_tscdeadline = 0;
-	guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, rdtsc());
+	guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
 	trace_kvm_wait_lapic_expire(vcpu->vcpu_id, guest_tsc - tsc_deadline);
 
 	/* __delay is delay_tsc whenever the hardware has TSC, thus always.  */
@@ -1240,7 +1239,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
 		local_irq_save(flags);
 
 		now = apic->lapic_timer.timer.base->get_time();
-		guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, rdtsc());
+		guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
 		if (likely(tscdeadline > guest_tsc)) {
 			ns = (tscdeadline - guest_tsc) * 1000000ULL;
 			do_div(ns, this_tsc_khz);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 239263f3..32ebe76 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -3075,8 +3075,7 @@ static int cr8_write_interception(struct vcpu_svm *svm)
 static u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
 {
 	struct vmcb *vmcb = get_host_vmcb(to_svm(vcpu));
-	return vmcb->control.tsc_offset +
-		kvm_scale_tsc(vcpu, host_tsc);
+	return vmcb->control.tsc_offset + host_tsc;
 }
 
 static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 7c372ad..d404a7e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1427,6 +1427,12 @@ static u64 kvm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
 	return target_tsc - tsc;
 }
 
+u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
+{
+	return kvm_x86_ops->read_l1_tsc(vcpu, kvm_scale_tsc(vcpu, host_tsc));
+}
+EXPORT_SYMBOL_GPL(kvm_read_l1_tsc);
+
 void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
 {
 	struct kvm *kvm = vcpu->kvm;
@@ -1750,7 +1756,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 		kernel_ns = get_kernel_ns();
 	}
 
-	tsc_timestamp = kvm_x86_ops->read_l1_tsc(v, host_tsc);
+	tsc_timestamp = kvm_read_l1_tsc(v, host_tsc);
 
 	/*
 	 * We may have to catch up the TSC to match elapsed wall clock
@@ -6493,8 +6499,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
 	if (hw_breakpoint_active())
 		hw_breakpoint_restore();
 
-	vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu,
-							   rdtsc());
+	vcpu->arch.last_guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
 
 	vcpu->mode = OUTSIDE_GUEST_MODE;
 	smp_wmb();
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 2a21845..75ecb7c 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1146,6 +1146,8 @@ static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
 #endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
 
 u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc);
+u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
+
 extern struct kvm_x86_ops *kvm_x86_ops;
 
 static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 08/12] KVM: x86: Use the correct vcpu's TSC rate to compute time scale
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (6 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 07/12] KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc() Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-10-05 20:12   ` Radim Krčmář
  2015-09-28  5:38 ` [PATCH 09/12] KVM: VMX: Enable and initialize VMX TSC scaling Haozhong Zhang
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patch makes KVM use virtual_tsc_khz rather than the host TSC rate
as vcpu's TSC rate to compute the time scale if TSC scaling is enabled.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/kvm/x86.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d404a7e..a3999b5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1719,7 +1719,7 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
 
 static int kvm_guest_time_update(struct kvm_vcpu *v)
 {
-	unsigned long flags, this_tsc_khz;
+	unsigned long flags, this_tsc_khz, tgt_tsc_khz;
 	struct kvm_vcpu_arch *vcpu = &v->arch;
 	struct kvm_arch *ka = &v->kvm->arch;
 	s64 kernel_ns;
@@ -1782,7 +1782,9 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
 		return 0;
 
 	if (unlikely(vcpu->hw_tsc_khz != this_tsc_khz)) {
-		kvm_get_time_scale(NSEC_PER_SEC / 1000, this_tsc_khz,
+		tgt_tsc_khz = kvm_has_tsc_control ?
+			vcpu->virtual_tsc_khz : this_tsc_khz;
+		kvm_get_time_scale(NSEC_PER_SEC / 1000, tgt_tsc_khz,
 				   &vcpu->hv_clock.tsc_shift,
 				   &vcpu->hv_clock.tsc_to_system_mul);
 		vcpu->hw_tsc_khz = this_tsc_khz;
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 09/12] KVM: VMX: Enable and initialize VMX TSC scaling
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (7 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 08/12] KVM: x86: Use the correct vcpu's TSC rate to compute time scale Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 10/12] KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded Haozhong Zhang
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patch exhances kvm-intel module to enable VMX TSC scaling and
collects information of TSC scaling ratio during initialization.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/include/asm/vmx.h |  4 +++-
 arch/x86/kvm/vmx.c         | 20 +++++++++++++++++++-
 2 files changed, 22 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 448b7ca..7f3c152 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -72,7 +72,7 @@
 #define SECONDARY_EXEC_SHADOW_VMCS              0x00004000
 #define SECONDARY_EXEC_ENABLE_PML               0x00020000
 #define SECONDARY_EXEC_XSAVES			0x00100000
-
+#define SECONDARY_EXEC_TSC_SCALING              0x02000000
 
 #define PIN_BASED_EXT_INTR_MASK                 0x00000001
 #define PIN_BASED_NMI_EXITING                   0x00000008
@@ -167,6 +167,8 @@ enum vmcs_field {
 	VMWRITE_BITMAP                  = 0x00002028,
 	XSS_EXIT_BITMAP                 = 0x0000202C,
 	XSS_EXIT_BITMAP_HIGH            = 0x0000202D,
+	TSC_MULTIPLIER                  = 0x00002032,
+	TSC_MULTIPLIER_HIGH             = 0x00002033,
 	GUEST_PHYSICAL_ADDRESS          = 0x00002400,
 	GUEST_PHYSICAL_ADDRESS_HIGH     = 0x00002401,
 	VMCS_LINK_POINTER               = 0x00002800,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 7a71191..ef19eb8 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -105,6 +105,9 @@ static u64 __read_mostly host_xss;
 static bool __read_mostly enable_pml = 1;
 module_param_named(pml, enable_pml, bool, S_IRUGO);
 
+#define KVM_VMX_TSC_MULTIPLIER_DEFAULT 0x0001000000000000ULL
+#define KVM_VMX_TSC_MULTIPLIER_MAX     0xffffffffffffffffULL
+
 #define KVM_GUEST_CR0_MASK (X86_CR0_NW | X86_CR0_CD)
 #define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST (X86_CR0_WP | X86_CR0_NE)
 #define KVM_VM_CR0_ALWAYS_ON						\
@@ -1113,6 +1116,12 @@ static inline bool cpu_has_vmx_pml(void)
 	return vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_ENABLE_PML;
 }
 
+static inline bool cpu_has_vmx_tsc_scaling(void)
+{
+	return vmcs_config.cpu_based_2nd_exec_ctrl &
+		SECONDARY_EXEC_TSC_SCALING;
+}
+
 static inline bool report_flexpriority(void)
 {
 	return flexpriority_enabled;
@@ -2994,7 +3003,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
 			SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
 			SECONDARY_EXEC_SHADOW_VMCS |
 			SECONDARY_EXEC_XSAVES |
-			SECONDARY_EXEC_ENABLE_PML;
+			SECONDARY_EXEC_ENABLE_PML |
+			SECONDARY_EXEC_TSC_SCALING;
 		if (adjust_vmx_controls(min2, opt2,
 					MSR_IA32_VMX_PROCBASED_CTLS2,
 					&_cpu_based_2nd_exec_control) < 0)
@@ -6021,6 +6031,14 @@ static __init int hardware_setup(void)
 	if (!cpu_has_vmx_apicv())
 		enable_apicv = 0;
 
+	if (cpu_has_vmx_tsc_scaling()) {
+		kvm_has_tsc_control = true;
+		kvm_max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX;
+		kvm_tsc_scaling_ratio_frac_bits = 48;
+		kvm_tsc_scaling_ratio_rsvd = 0x0ULL;
+	}
+	kvm_default_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_DEFAULT;
+
 	if (enable_apicv)
 		kvm_x86_ops->update_cr8_intercept = NULL;
 	else {
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 10/12] KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (8 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 09/12] KVM: VMX: Enable and initialize VMX TSC scaling Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 11/12] KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC Haozhong Zhang
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patch makes kvm-intel module to load TSC scaling ratio into TSC
multiplier field of VMCS when a vcpu is loaded, so that TSC scaling
ratio can take effect if VMX TSC scaling is enabled.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/kvm/vmx.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ef19eb8..e282eb8 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1952,6 +1952,12 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 
 		rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
 		vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
+
+		/* Setup TSC multiplier */
+		if (cpu_has_vmx_tsc_scaling())
+			vmcs_write64(TSC_MULTIPLIER,
+				     vcpu->arch.tsc_scaling_ratio);
+
 		vmx->loaded_vmcs->cpu = cpu;
 	}
 }
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 11/12] KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (9 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 10/12] KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-28  5:38 ` [PATCH 12/12] KVM: VMX: Dump TSC multiplier in dump_vmcs() Haozhong Zhang
  2015-09-29  4:00 ` [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Eric Northup
  12 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patch makes kvm-intel to return a scaled host TSC plus the TSC
offset when handling guest readings to MSR_IA32_TSC.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/kvm/vmx.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index e282eb8..d0a2928 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -2245,15 +2245,15 @@ static void setup_msrs(struct vcpu_vmx *vmx)
 
 /*
  * reads and returns guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset    -- 21.3
+ * guest_tsc = (host_tsc * tsc multiplier) >> 48 + tsc_offset
  */
-static u64 guest_read_tsc(void)
+static u64 guest_read_tsc(struct kvm_vcpu *vcpu)
 {
 	u64 host_tsc, tsc_offset;
 
 	host_tsc = rdtsc();
 	tsc_offset = vmcs_read64(TSC_OFFSET);
-	return host_tsc + tsc_offset;
+	return kvm_scale_tsc(vcpu, host_tsc) + tsc_offset;
 }
 
 /*
@@ -2636,7 +2636,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	case MSR_EFER:
 		return kvm_get_msr_common(vcpu, msr_info);
 	case MSR_IA32_TSC:
-		msr_info->data = guest_read_tsc();
+		msr_info->data = guest_read_tsc(vcpu);
 		break;
 	case MSR_IA32_SYSENTER_CS:
 		msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 12/12] KVM: VMX: Dump TSC multiplier in dump_vmcs()
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (10 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 11/12] KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC Haozhong Zhang
@ 2015-09-28  5:38 ` Haozhong Zhang
  2015-09-29  4:00 ` [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Eric Northup
  12 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-28  5:38 UTC (permalink / raw)
  To: kvm
  Cc: Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel,
	Haozhong Zhang

This patch enhances dump_vmcs() to dump the value of TSC multiplier
field in VMCS.

Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
---
 arch/x86/kvm/vmx.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index d0a2928..b19cdbe 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -7799,6 +7799,9 @@ static void dump_vmcs(void)
 	       vmcs_read32(IDT_VECTORING_INFO_FIELD),
 	       vmcs_read32(IDT_VECTORING_ERROR_CODE));
 	pr_err("TSC Offset = 0x%016lx\n", vmcs_readl(TSC_OFFSET));
+	if (secondary_exec_control & SECONDARY_EXEC_TSC_SCALING)
+		pr_err("TSC Multiplier = 0x%016lx\n",
+		       vmcs_readl(TSC_MULTIPLIER));
 	if (cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW)
 		pr_err("TPR Threshold = 0x%02x\n", vmcs_read32(TPR_THRESHOLD));
 	if (pin_based_exec_ctrl & PIN_BASED_POSTED_INTR)
-- 
2.4.8


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH 03/12] KVM: x86: Add a common TSC scaling function
  2015-09-28  5:38 ` [PATCH 03/12] KVM: x86: Add a common TSC scaling function Haozhong Zhang
@ 2015-09-28 20:12   ` Paolo Bonzini
  2015-09-29  1:51     ` Haozhong Zhang
  0 siblings, 1 reply; 30+ messages in thread
From: Paolo Bonzini @ 2015-09-28 20:12 UTC (permalink / raw)
  To: Haozhong Zhang, kvm
  Cc: Gleb Natapov, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86,
	Joerg Roedel, Wanpeng Li, Xiao Guangrong, Mihai Donțu,
	Andy Lutomirski, Kai Huang, linux-kernel



On 28/09/2015 07:38, Haozhong Zhang wrote:
>  
> -static u64 __scale_tsc(u64 ratio, u64 tsc)
> -{
> -	u64 mult, frac, _tsc;
> -
> -	mult  = ratio >> 32;
> -	frac  = ratio & ((1ULL << 32) - 1);
> -
> -	_tsc  = tsc;
> -	_tsc *= mult;
> -	_tsc += (tsc >> 32) * frac;
> -	_tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
> -
> -	return _tsc;
> -}

This is basically

	return mul_u64_u64_shr(ratio, tsc,
			       kvm_tsc_scaling_ratio_frac_bits);

except that Linux has no mul_u64_u64_shr function, only mul_u64_u32_shr.

We should implement that function in include/linux/math64.h instead.
For the x86_64 case (or any other CONFIG_ARCH_SUPPORTS_INT128
architecture) we can just write it directly, as is done already for
mul_u64_u32_shr.

For the 32-bit case, here is an implementation of both the
multiplication and the shift, lifted from QEMU:

static inline void mul64(uint64_t *lo, uint64_t *hi,
                         uint64_t a, uint64_t b)
{
    typedef union {
        uint64_t ll;
        struct {
#ifdef __BIG_ENDIAN
            uint32_t high, low;
#else
            uint32_t low, high;
#endif
        } l;
    } LL;
    LL rl, rm, rn, rh, a0, b0;
    uint64_t c;

    a0.ll = a;
    b0.ll = b;

    rl.ll = (uint64_t)a0.l.low * b0.l.low;
    rm.ll = (uint64_t)a0.l.low * b0.l.high;
    rn.ll = (uint64_t)a0.l.high * b0.l.low;
    rh.ll = (uint64_t)a0.l.high * b0.l.high;

    c = (uint64_t)rl.l.high + rm.l.low + rn.l.low;
    rl.l.high = c;
    c >>= 32;
    c = c + rm.l.high + rn.l.high + rh.l.low;
    rh.l.low = c;
    rh.l.high += (uint32_t)(c >> 32);

    *lo = rl.ll;
    *hi = rh.ll;
}

static inline void rshift128(uint64_t *lo, uint64_t *hi, int n)
{
    uint64_t h;
    if (!n) {
        return;
    }
    h = *hi >> (n & 63);
    if (n >= 64) {
        *hi = 0;
        *lo = h;
    } else {
        *lo = (*lo >> n) | (*hi << (64 - n));
        *hi = h;
    }
}

and you can easily reuse this code in Linux with just uintNN_t types
changed to uNN + some extra cleanups when it's placed in a single functions.

Paolo

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset()
  2015-09-28  5:38 ` [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset() Haozhong Zhang
@ 2015-09-28 20:14   ` Paolo Bonzini
  2015-09-29  1:47     ` Haozhong Zhang
  0 siblings, 1 reply; 30+ messages in thread
From: Paolo Bonzini @ 2015-09-28 20:14 UTC (permalink / raw)
  To: Haozhong Zhang, kvm
  Cc: Gleb Natapov, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86,
	Joerg Roedel, Wanpeng Li, Xiao Guangrong, Mihai Donțu,
	Andy Lutomirski, Kai Huang, linux-kernel



On 28/09/2015 07:38, Haozhong Zhang wrote:
> +
> +static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
> +					   s64 adjustment)
> +{
> +	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
> +}
> +
> +static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
> +{
> +	if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
> +		WARN_ON(adjustment < 0);
> +	adjustment = kvm_scale_tsc(vcpu, (u64) adjustment);
> +	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
> +}

You can remove the final argument to the callback (and possibly change
the callback's name to adjust_tsc_offset_guest), because it is now unused.

Paolo

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset()
  2015-09-28 20:14   ` Paolo Bonzini
@ 2015-09-29  1:47     ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-29  1:47 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: kvm, Gleb Natapov, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong, Mihai Donțu,
	Andy Lutomirski, Kai Huang, linux-kernel

On Mon, Sep 28, 2015 at 10:14:19PM +0200, Paolo Bonzini wrote:
> 
> 
> On 28/09/2015 07:38, Haozhong Zhang wrote:
> > +
> > +static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
> > +					   s64 adjustment)
> > +{
> > +	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
> > +}
> > +
> > +static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
> > +{
> > +	if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
> > +		WARN_ON(adjustment < 0);
> > +	adjustment = kvm_scale_tsc(vcpu, (u64) adjustment);
> > +	kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
> > +}
> 
> You can remove the final argument to the callback (and possibly change
> the callback's name to adjust_tsc_offset_guest), because it is now unused.
> 
> Paolo

Thanks! will do it.

- Haozhong

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 03/12] KVM: x86: Add a common TSC scaling function
  2015-09-28 20:12   ` Paolo Bonzini
@ 2015-09-29  1:51     ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-29  1:51 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: kvm, Gleb Natapov, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong, Mihai Donțu,
	Andy Lutomirski, Kai Huang, linux-kernel

On Mon, Sep 28, 2015 at 10:12:37PM +0200, Paolo Bonzini wrote:
> 
> 
> On 28/09/2015 07:38, Haozhong Zhang wrote:
> >  
> > -static u64 __scale_tsc(u64 ratio, u64 tsc)
> > -{
> > -	u64 mult, frac, _tsc;
> > -
> > -	mult  = ratio >> 32;
> > -	frac  = ratio & ((1ULL << 32) - 1);
> > -
> > -	_tsc  = tsc;
> > -	_tsc *= mult;
> > -	_tsc += (tsc >> 32) * frac;
> > -	_tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
> > -
> > -	return _tsc;
> > -}
> 
> This is basically
> 
> 	return mul_u64_u64_shr(ratio, tsc,
> 			       kvm_tsc_scaling_ratio_frac_bits);
> 
> except that Linux has no mul_u64_u64_shr function, only mul_u64_u32_shr.
> 
> We should implement that function in include/linux/math64.h instead.
> For the x86_64 case (or any other CONFIG_ARCH_SUPPORTS_INT128
> architecture) we can just write it directly, as is done already for
> mul_u64_u32_shr.
> 
> For the 32-bit case, here is an implementation of both the
> multiplication and the shift, lifted from QEMU:
> 
> static inline void mul64(uint64_t *lo, uint64_t *hi,
>                          uint64_t a, uint64_t b)
> {
>     typedef union {
>         uint64_t ll;
>         struct {
> #ifdef __BIG_ENDIAN
>             uint32_t high, low;
> #else
>             uint32_t low, high;
> #endif
>         } l;
>     } LL;
>     LL rl, rm, rn, rh, a0, b0;
>     uint64_t c;
> 
>     a0.ll = a;
>     b0.ll = b;
> 
>     rl.ll = (uint64_t)a0.l.low * b0.l.low;
>     rm.ll = (uint64_t)a0.l.low * b0.l.high;
>     rn.ll = (uint64_t)a0.l.high * b0.l.low;
>     rh.ll = (uint64_t)a0.l.high * b0.l.high;
> 
>     c = (uint64_t)rl.l.high + rm.l.low + rn.l.low;
>     rl.l.high = c;
>     c >>= 32;
>     c = c + rm.l.high + rn.l.high + rh.l.low;
>     rh.l.low = c;
>     rh.l.high += (uint32_t)(c >> 32);
> 
>     *lo = rl.ll;
>     *hi = rh.ll;
> }
> 
> static inline void rshift128(uint64_t *lo, uint64_t *hi, int n)
> {
>     uint64_t h;
>     if (!n) {
>         return;
>     }
>     h = *hi >> (n & 63);
>     if (n >= 64) {
>         *hi = 0;
>         *lo = h;
>     } else {
>         *lo = (*lo >> n) | (*hi << (64 - n));
>         *hi = h;
>     }
> }
> 
> and you can easily reuse this code in Linux with just uintNN_t types
> changed to uNN + some extra cleanups when it's placed in a single functions.
> 
> Paolo

Thanks! I'll add mul_u64_u64_shr() and replace __scale_tsc().

- Haozhong

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio
  2015-09-28  5:38 ` [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio Haozhong Zhang
@ 2015-09-29  3:28   ` Eric Northup
  2015-09-29  4:01     ` Haozhong Zhang
  0 siblings, 1 reply; 30+ messages in thread
From: Eric Northup @ 2015-09-29  3:28 UTC (permalink / raw)
  To: Haozhong Zhang
  Cc: KVM, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, the arch/x86 maintainers, Joerg Roedel,
	Wanpeng Li, Xiao Guangrong, Mihai Donțu, Andy Lutomirski,
	Kai Huang, Linux Kernel Mailing List

On Sun, Sep 27, 2015 at 10:38 PM, Haozhong Zhang
<haozhong.zhang@intel.com> wrote:
>
> The number of bits of the fractional part of the 64-bit TSC scaling
> ratio in VMX and SVM is different. This patch makes the architecture
> code to collect the number of fractional bits and other related
> information into variables that can be accessed in the common code.
>
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
>  arch/x86/include/asm/kvm_host.h | 8 ++++++++
>  arch/x86/kvm/svm.c              | 5 +++++
>  arch/x86/kvm/x86.c              | 8 ++++++++
>  3 files changed, 21 insertions(+)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 2beee03..5b9b86e 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -965,6 +965,14 @@ extern bool kvm_has_tsc_control;
>  extern u32  kvm_min_guest_tsc_khz;
>  /* maximum supported tsc_khz for guests */
>  extern u32  kvm_max_guest_tsc_khz;
> +/* number of bits of the fractional part of the TSC scaling ratio */
> +extern u8   kvm_tsc_scaling_ratio_frac_bits;
> +/* reserved bits of TSC scaling ratio (SBZ) */
> +extern u64  kvm_tsc_scaling_ratio_rsvd;
> +/* default TSC scaling ratio (= 1.0) */
> +extern u64  kvm_default_tsc_scaling_ratio;
> +/* maximum allowed value of TSC scaling ratio */
> +extern u64  kvm_max_tsc_scaling_ratio;

Do we need all 3 of kvm_max_guest_tsc_khz, kvm_max_tsc_scaling_ratio,
and kvm_tsc_scaling_ratio_rsvd (since only SVM has reserved bits - and
just for complaining if the high bits are set, which can already be
expressed by max_tsc_scaling ratio)

kvm_max_tsc_scaling_ratio seems to be write-only.

>
>  enum emulation_result {
>         EMULATE_DONE,         /* no further processing */
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 94b7d15..eff7db7 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -963,7 +963,12 @@ static __init int svm_hardware_setup(void)
>                 max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
>
>                 kvm_max_guest_tsc_khz = max;
> +
> +               kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX;
> +               kvm_tsc_scaling_ratio_frac_bits = 32;
> +               kvm_tsc_scaling_ratio_rsvd = TSC_RATIO_RSVD;
>         }
> +       kvm_default_tsc_scaling_ratio = TSC_RATIO_DEFAULT;
>
>         if (nested) {
>                 printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 991466b..f888225 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -106,6 +106,14 @@ bool kvm_has_tsc_control;
>  EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
>  u32  kvm_max_guest_tsc_khz;
>  EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
> +u8   kvm_tsc_scaling_ratio_frac_bits;
> +EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits);
> +u64  kvm_tsc_scaling_ratio_rsvd;
> +EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_rsvd);
> +u64  kvm_default_tsc_scaling_ratio;
> +EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio);
> +u64  kvm_max_tsc_scaling_ratio;
> +EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
>
>  /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
>  static u32 tsc_tolerance_ppm = 250;
> --
> 2.4.8
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
       [not found]   ` <CAG7+5M3z2-OKsy0wxxks2oW9+7WmFpO4JQETTx3KsaW-hWMGqw@mail.gmail.com>
@ 2015-09-29  3:47     ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-29  3:47 UTC (permalink / raw)
  To: Eric Northup
  Cc: KVM, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, the arch/x86 maintainers, Joerg Roedel,
	Wanpeng Li, Xiao Guangrong, Mihai Donțu, Andy Lutomirski,
	Kai Huang, Linux Kernel Mailing List

On Mon, Sep 28, 2015 at 08:27:02PM -0700, Eric Northup wrote:
> On Sun, Sep 27, 2015 at 10:38 PM, Haozhong Zhang <haozhong.zhang@intel.com>
> wrote:
> 
> > Both VMX and SVM propagate virtual_tsc_khz in the same way, so this
> > patch removes the call-back set_tsc_khz() and replaces it with a common
> > function.
> >
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> >  arch/x86/include/asm/kvm_host.h |  1 -
> >  arch/x86/kvm/svm.c              | 36 ------------------------------------
> >  arch/x86/kvm/vmx.c              | 17 -----------------
> >  arch/x86/kvm/x86.c              | 41
> > ++++++++++++++++++++++++++++++++++++++++-
> >  4 files changed, 40 insertions(+), 55 deletions(-)
> >
> > diff --git a/arch/x86/include/asm/kvm_host.h
> > b/arch/x86/include/asm/kvm_host.h
> > index 4f32c68..5a0c435 100644
> > --- a/arch/x86/include/asm/kvm_host.h
> > +++ b/arch/x86/include/asm/kvm_host.h
> > @@ -842,7 +842,6 @@ struct kvm_x86_ops {
> >
> >         bool (*has_wbinvd_exit)(void);
> >
> > -       void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool
> > scale);
> >         u64 (*read_tsc_offset)(struct kvm_vcpu *vcpu);
> >         void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
> >
> > diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> > index 1a333bd..d46dcf3 100644
> > --- a/arch/x86/kvm/svm.c
> > +++ b/arch/x86/kvm/svm.c
> > @@ -1015,41 +1015,6 @@ static void init_sys_seg(struct vmcb_seg *seg,
> > uint32_t type)
> >         seg->base = 0;
> >  }
> >
> > -static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool
> > scale)
> > -{
> > -       u64 ratio;
> > -       u64 khz;
> > -
> > -       /* Guest TSC same frequency as host TSC? */
> > -       if (!scale) {
> > -               vcpu->arch.tsc_scaling_ratio = TSC_RATIO_DEFAULT;
> > -               return;
> > -       }
> > -
> > -       /* TSC scaling supported? */
> > -       if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
> > -               if (user_tsc_khz > tsc_khz) {
> > -                       vcpu->arch.tsc_catchup = 1;
> > -                       vcpu->arch.tsc_always_catchup = 1;
> > -               } else
> > -                       WARN(1, "user requested TSC rate below hardware
> > speed\n");
> > -               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.tsc_scaling_ratio = ratio;
> > -}
> > -
> >  static u64 svm_read_tsc_offset(struct kvm_vcpu *vcpu)
> >  {
> >         struct vcpu_svm *svm = to_svm(vcpu);
> > @@ -4507,7 +4472,6 @@ static struct kvm_x86_ops svm_x86_ops = {
> >
> >         .has_wbinvd_exit = svm_has_wbinvd_exit,
> >
> > -       .set_tsc_khz = svm_set_tsc_khz,
> >         .read_tsc_offset = svm_read_tsc_offset,
> >         .write_tsc_offset = svm_write_tsc_offset,
> >         .adjust_tsc_offset = svm_adjust_tsc_offset,
> > diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> > index 6407674..1751537 100644
> > --- a/arch/x86/kvm/vmx.c
> > +++ b/arch/x86/kvm/vmx.c
> > @@ -2255,22 +2255,6 @@ static u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu,
> > u64 host_tsc)
> >         return host_tsc + tsc_offset;
> >  }
> >
> > -/*
> > - * Engage any workarounds for mis-matched TSC rates.  Currently limited to
> > - * software catchup for faster rates on slower CPUs.
> > - */
> > -static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool
> > scale)
> > -{
> > -       if (!scale)
> > -               return;
> > -
> > -       if (user_tsc_khz > tsc_khz) {
> > -               vcpu->arch.tsc_catchup = 1;
> > -               vcpu->arch.tsc_always_catchup = 1;
> > -       } else
> > -               WARN(1, "user requested TSC rate below hardware speed\n");
> > -}
> > -
> >  static u64 vmx_read_tsc_offset(struct kvm_vcpu *vcpu)
> >  {
> >         return vmcs_read64(TSC_OFFSET);
> > @@ -10380,7 +10364,6 @@ static struct kvm_x86_ops vmx_x86_ops = {
> >
> >         .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
> >
> > -       .set_tsc_khz = vmx_set_tsc_khz,
> >         .read_tsc_offset = vmx_read_tsc_offset,
> >         .write_tsc_offset = vmx_write_tsc_offset,
> >         .adjust_tsc_offset = vmx_adjust_tsc_offset,
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > index 920c302..e2e1fdb 100644
> > --- a/arch/x86/kvm/x86.c
> > +++ b/arch/x86/kvm/x86.c
> > @@ -1248,6 +1248,45 @@ static u32 adjust_tsc_khz(u32 khz, s32 ppm)
> >         return v;
> >  }
> >
> > +static void set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool
> > scale)
> > +{
> > +       u64 ratio, khz;
> > +       s8 shift;
> > +
> > +       /* Guest TSC same frequency as host TSC? */
> > +       if (!scale) {
> > +               vcpu->arch.tsc_scaling_ratio =
> > kvm_default_tsc_scaling_ratio;
> > +               return;
> > +       }
> > +
> > +       /* TSC scaling supported? */
> > +       if (!kvm_has_tsc_control) {
> > +               if (user_tsc_khz > tsc_khz) {
> > +                       vcpu->arch.tsc_catchup = 1;
> > +                       vcpu->arch.tsc_always_catchup = 1;
> > +               } else
> > +                       WARN(1, "user requested TSC rate below hardware
> > speed\n");
> >
> 
> It was like this before, but why should KVM_SET_TSC_KHZ ioctl have return
> value of 0 in this case?  Failing the request would be better than kernel
> log spew (and below).
> 
>

Yes, failing the request is a better way. I'll change this and below.

> > +               return;
> > +       }
> > +
> > +       khz = user_tsc_khz;
> > +
> > +       /* TSC scaling required  - calculate ratio */
> > +       shift = (kvm_tsc_scaling_ratio_frac_bits <= 32) ?
> > +               kvm_tsc_scaling_ratio_frac_bits : 32;
> > +       ratio = khz << shift;
> > +       do_div(ratio, tsc_khz);
> > +       ratio <<= (kvm_tsc_scaling_ratio_frac_bits - shift);
> > +
> > +       if (ratio == 0 || ratio & kvm_tsc_scaling_ratio_rsvd) {
> > +               WARN_ONCE(1, "Invalid TSC scaling ratio -
> > virtual-tsc-khz=%u\n",
> > +                         user_tsc_khz);
> > +               return;
> > +       }
> > +
> > +       vcpu->arch.tsc_scaling_ratio = ratio;
> > +}
> > +
> >  static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
> >  {
> >         u32 thresh_lo, thresh_hi;
> > @@ -1275,7 +1314,7 @@ static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu,
> > u32 this_tsc_khz)
> >                 pr_debug("kvm: requested TSC rate %u falls outside
> > tolerance [%u,%u]\n", this_tsc_khz, thresh_lo, thresh_hi);
> >                 use_scaling = 1;
> >         }
> > -       kvm_x86_ops->set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
> > +       set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
> >  }
> >
> >  static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
> > --
> > 2.4.8
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> >

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 00/12] KVM: x86: add support for VMX TSC scaling
  2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
                   ` (11 preceding siblings ...)
  2015-09-28  5:38 ` [PATCH 12/12] KVM: VMX: Dump TSC multiplier in dump_vmcs() Haozhong Zhang
@ 2015-09-29  4:00 ` Eric Northup
  2015-09-29  4:03   ` Haozhong Zhang
  12 siblings, 1 reply; 30+ messages in thread
From: Eric Northup @ 2015-09-29  4:00 UTC (permalink / raw)
  To: Haozhong Zhang
  Cc: KVM, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, the arch/x86 maintainers, Joerg Roedel,
	Wanpeng Li, Xiao Guangrong, Mihai Donțu, Andy Lutomirski,
	Kai Huang, Linux Kernel Mailing List

On Sun, Sep 27, 2015 at 10:37 PM, Haozhong Zhang
<haozhong.zhang@intel.com> wrote:
> This patchset adds support for VMX TSC scaling feature which is
> available on Intel Skylake CPU. The specification of VMX TSC scaling
> can be found at
> http://www.intel.com/content/www/us/en/processors/timestamp-counter-scaling-virtualization-white-paper.html
>
> VMX TSC scaling allows guest TSC which is read by guest rdtsc(p)
> instructions increases in a rate that is customized by the hypervisor
> and can be different than the host TSC rate. Basically, VMX TSC
> scaling adds a 64-bit field called TSC multiplier in VMCS so that, if
> VMX TSC scaling is enabled, TSC read by guest rdtsc(p) instructions
> will be calculated by the following formula:
>
>   guest EDX:EAX = (Host TSC * TSC multiplier) >> 48 + VMX TSC Offset
>
> where, Host TSC = Host MSR_IA32_TSC + Host MSR_IA32_TSC_ADJUST.
>
> This patchset, when cooperating with another QEMU patchset (sent in
> another email "target-i386: save/restore vcpu's TSC rate during
> migration"), allows guest programs observe a consistent TSC rate even
> though they are migrated among machines with different host TSC rates.
>
> VMX TSC scaling shares some common logics with SVM TSC scaling which
> is already supported by KVM. Patch 1 ~ 8 move those common logics from
> SVM code to the common code. Upon them, patch 9 ~ 12 add VMX-specific
> support for VMX TSC scaling.

reviewed-by: Eric Northup <digitaleric@google.com>

>
> Haozhong Zhang (12):
>   KVM: x86: Collect information for setting TSC scaling ratio
>   KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch
>   KVM: x86: Add a common TSC scaling function
>   KVM: x86: Replace call-back set_tsc_khz() with a common function
>   KVM: x86: Replace call-back compute_tsc_offset() with a common function
>   KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset()
>   KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc()
>   KVM: x86: Use the correct vcpu's TSC rate to compute time scale
>   KVM: VMX: Enable and initialize VMX TSC scaling
>   KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded
>   KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC
>   KVM: VMX: Dump TSC multiplier in dump_vmcs()
>
>  arch/x86/include/asm/kvm_host.h |  24 +++----
>  arch/x86/include/asm/vmx.h      |   4 +-
>  arch/x86/kvm/lapic.c            |   5 +-
>  arch/x86/kvm/svm.c              | 113 +++--------------------------
>  arch/x86/kvm/vmx.c              |  60 ++++++++--------
>  arch/x86/kvm/x86.c              | 154 +++++++++++++++++++++++++++++++++++++---
>  include/linux/kvm_host.h        |  21 +++++-
>  7 files changed, 221 insertions(+), 160 deletions(-)
>
> --
> 2.4.8
>
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio
  2015-09-29  3:28   ` Eric Northup
@ 2015-09-29  4:01     ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-29  4:01 UTC (permalink / raw)
  To: Eric Northup
  Cc: KVM, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, the arch/x86 maintainers, Joerg Roedel,
	Wanpeng Li, Xiao Guangrong, Mihai Donțu, Andy Lutomirski,
	Kai Huang, Linux Kernel Mailing List

On Mon, Sep 28, 2015 at 08:28:57PM -0700, Eric Northup wrote:
> On Sun, Sep 27, 2015 at 10:38 PM, Haozhong Zhang
> <haozhong.zhang@intel.com> wrote:
> >
> > The number of bits of the fractional part of the 64-bit TSC scaling
> > ratio in VMX and SVM is different. This patch makes the architecture
> > code to collect the number of fractional bits and other related
> > information into variables that can be accessed in the common code.
> >
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> >  arch/x86/include/asm/kvm_host.h | 8 ++++++++
> >  arch/x86/kvm/svm.c              | 5 +++++
> >  arch/x86/kvm/x86.c              | 8 ++++++++
> >  3 files changed, 21 insertions(+)
> >
> > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> > index 2beee03..5b9b86e 100644
> > --- a/arch/x86/include/asm/kvm_host.h
> > +++ b/arch/x86/include/asm/kvm_host.h
> > @@ -965,6 +965,14 @@ extern bool kvm_has_tsc_control;
> >  extern u32  kvm_min_guest_tsc_khz;
> >  /* maximum supported tsc_khz for guests */
> >  extern u32  kvm_max_guest_tsc_khz;
> > +/* number of bits of the fractional part of the TSC scaling ratio */
> > +extern u8   kvm_tsc_scaling_ratio_frac_bits;
> > +/* reserved bits of TSC scaling ratio (SBZ) */
> > +extern u64  kvm_tsc_scaling_ratio_rsvd;
> > +/* default TSC scaling ratio (= 1.0) */
> > +extern u64  kvm_default_tsc_scaling_ratio;
> > +/* maximum allowed value of TSC scaling ratio */
> > +extern u64  kvm_max_tsc_scaling_ratio;
> 
> Do we need all 3 of kvm_max_guest_tsc_khz, kvm_max_tsc_scaling_ratio,
> and kvm_tsc_scaling_ratio_rsvd (since only SVM has reserved bits - and
> just for complaining if the high bits are set, which can already be
> expressed by max_tsc_scaling ratio)
> 
> kvm_max_tsc_scaling_ratio seems to be write-only.
>

You are right. I'll remove kvm_tsc_scaling_ratio_rsvd and just use
kvm_max_tsc_scaling_ratio to verify TSC scaling ratio in
set_tsc_khz().

> >
> >  enum emulation_result {
> >         EMULATE_DONE,         /* no further processing */
> > diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> > index 94b7d15..eff7db7 100644
> > --- a/arch/x86/kvm/svm.c
> > +++ b/arch/x86/kvm/svm.c
> > @@ -963,7 +963,12 @@ static __init int svm_hardware_setup(void)
> >                 max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
> >
> >                 kvm_max_guest_tsc_khz = max;
> > +
> > +               kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX;
> > +               kvm_tsc_scaling_ratio_frac_bits = 32;
> > +               kvm_tsc_scaling_ratio_rsvd = TSC_RATIO_RSVD;
> >         }
> > +       kvm_default_tsc_scaling_ratio = TSC_RATIO_DEFAULT;
> >
> >         if (nested) {
> >                 printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > index 991466b..f888225 100644
> > --- a/arch/x86/kvm/x86.c
> > +++ b/arch/x86/kvm/x86.c
> > @@ -106,6 +106,14 @@ bool kvm_has_tsc_control;
> >  EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
> >  u32  kvm_max_guest_tsc_khz;
> >  EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
> > +u8   kvm_tsc_scaling_ratio_frac_bits;
> > +EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits);
> > +u64  kvm_tsc_scaling_ratio_rsvd;
> > +EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_rsvd);
> > +u64  kvm_default_tsc_scaling_ratio;
> > +EXPORT_SYMBOL_GPL(kvm_default_tsc_scaling_ratio);
> > +u64  kvm_max_tsc_scaling_ratio;
> > +EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
> >
> >  /* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
> >  static u32 tsc_tolerance_ppm = 250;
> > --
> > 2.4.8
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 00/12] KVM: x86: add support for VMX TSC scaling
  2015-09-29  4:00 ` [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Eric Northup
@ 2015-09-29  4:03   ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-09-29  4:03 UTC (permalink / raw)
  To: Eric Northup
  Cc: KVM, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, the arch/x86 maintainers, Joerg Roedel,
	Wanpeng Li, Xiao Guangrong, Mihai Donțu, Andy Lutomirski,
	Kai Huang, Linux Kernel Mailing List

On Mon, Sep 28, 2015 at 09:00:39PM -0700, Eric Northup wrote:
> On Sun, Sep 27, 2015 at 10:37 PM, Haozhong Zhang
> <haozhong.zhang@intel.com> wrote:
> > This patchset adds support for VMX TSC scaling feature which is
> > available on Intel Skylake CPU. The specification of VMX TSC scaling
> > can be found at
> > http://www.intel.com/content/www/us/en/processors/timestamp-counter-scaling-virtualization-white-paper.html
> >
> > VMX TSC scaling allows guest TSC which is read by guest rdtsc(p)
> > instructions increases in a rate that is customized by the hypervisor
> > and can be different than the host TSC rate. Basically, VMX TSC
> > scaling adds a 64-bit field called TSC multiplier in VMCS so that, if
> > VMX TSC scaling is enabled, TSC read by guest rdtsc(p) instructions
> > will be calculated by the following formula:
> >
> >   guest EDX:EAX = (Host TSC * TSC multiplier) >> 48 + VMX TSC Offset
> >
> > where, Host TSC = Host MSR_IA32_TSC + Host MSR_IA32_TSC_ADJUST.
> >
> > This patchset, when cooperating with another QEMU patchset (sent in
> > another email "target-i386: save/restore vcpu's TSC rate during
> > migration"), allows guest programs observe a consistent TSC rate even
> > though they are migrated among machines with different host TSC rates.
> >
> > VMX TSC scaling shares some common logics with SVM TSC scaling which
> > is already supported by KVM. Patch 1 ~ 8 move those common logics from
> > SVM code to the common code. Upon them, patch 9 ~ 12 add VMX-specific
> > support for VMX TSC scaling.
> 
> reviewed-by: Eric Northup <digitaleric@google.com>
>

Thank you for the review!

> >
> > Haozhong Zhang (12):
> >   KVM: x86: Collect information for setting TSC scaling ratio
> >   KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch
> >   KVM: x86: Add a common TSC scaling function
> >   KVM: x86: Replace call-back set_tsc_khz() with a common function
> >   KVM: x86: Replace call-back compute_tsc_offset() with a common function
> >   KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset()
> >   KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc()
> >   KVM: x86: Use the correct vcpu's TSC rate to compute time scale
> >   KVM: VMX: Enable and initialize VMX TSC scaling
> >   KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded
> >   KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC
> >   KVM: VMX: Dump TSC multiplier in dump_vmcs()
> >
> >  arch/x86/include/asm/kvm_host.h |  24 +++----
> >  arch/x86/include/asm/vmx.h      |   4 +-
> >  arch/x86/kvm/lapic.c            |   5 +-
> >  arch/x86/kvm/svm.c              | 113 +++--------------------------
> >  arch/x86/kvm/vmx.c              |  60 ++++++++--------
> >  arch/x86/kvm/x86.c              | 154 +++++++++++++++++++++++++++++++++++++---
> >  include/linux/kvm_host.h        |  21 +++++-
> >  7 files changed, 221 insertions(+), 160 deletions(-)
> >
> > --
> > 2.4.8
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe kvm" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch
  2015-09-28  5:38 ` [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch Haozhong Zhang
@ 2015-10-05 19:26   ` Radim Krčmář
  2015-10-06  1:54     ` Haozhong Zhang
  0 siblings, 1 reply; 30+ messages in thread
From: Radim Krčmář @ 2015-10-05 19:26 UTC (permalink / raw)
  To: Haozhong Zhang
  Cc: kvm, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel

2015-09-28 13:38+0800, Haozhong Zhang:
> This patch moves the field of TSC scaling ratio from the architecture
> struct vcpu_svm to the common struct kvm_vcpu_arch.
> 
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> @@ -7080,6 +7080,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
>  
>  	vcpu = kvm_x86_ops->vcpu_create(kvm, id);
>  
> +	if (!IS_ERR(vcpu))
> +		vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;

This shouldn't be necessary, (and we can definitely do it without error
checking later)

 kvm_arch_vcpu_create
   (vmx|svm)_create_vcpu
     kvm_vcpu_init
       kvm_arch_vcpu_init
         kvm_set_tsc_khz

sets vcpu->arch.tsc_scaling_ratio to something reasonable and SVM didn't
overwrite that value.  (kvm_set_tsc_khz() only doesn't set the ration if
this_tsc_khz == 0, which we could extend to be extra safe.)

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
  2015-09-28  5:38 ` [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function Haozhong Zhang
       [not found]   ` <CAG7+5M3z2-OKsy0wxxks2oW9+7WmFpO4JQETTx3KsaW-hWMGqw@mail.gmail.com>
@ 2015-10-05 19:53   ` Radim Krčmář
  2015-10-05 20:46     ` David Matlack
  2015-10-06  4:06     ` Haozhong Zhang
  1 sibling, 2 replies; 30+ messages in thread
From: Radim Krčmář @ 2015-10-05 19:53 UTC (permalink / raw)
  To: Haozhong Zhang
  Cc: kvm, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel

2015-09-28 13:38+0800, Haozhong Zhang:
> Both VMX and SVM propagate virtual_tsc_khz in the same way, so this
> patch removes the call-back set_tsc_khz() and replaces it with a common
> function.
> 
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> +static void set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
> +{
> +	u64 ratio, khz;
| [...]
> +	khz = user_tsc_khz;

I'd use "user_tsc_khz" directly.

> +	/* TSC scaling required  - calculate ratio */
> +	shift = (kvm_tsc_scaling_ratio_frac_bits <= 32) ?
> +		kvm_tsc_scaling_ratio_frac_bits : 32;
> +	ratio = khz << shift;
> +	do_div(ratio, tsc_khz);
> +	ratio <<= (kvm_tsc_scaling_ratio_frac_bits - shift);

VMX is losing 16 bits by this operation;  normal fixed point division
could get us a smaller drift (and an one-liner here) ...
at 4.3 GHz, 32 instead of 48 bits after decimal point translate to one
"lost" TSC tick per second, in the worst case.

Please mention that we are truncating on purpose :)

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 08/12] KVM: x86: Use the correct vcpu's TSC rate to compute time scale
  2015-09-28  5:38 ` [PATCH 08/12] KVM: x86: Use the correct vcpu's TSC rate to compute time scale Haozhong Zhang
@ 2015-10-05 20:12   ` Radim Krčmář
  0 siblings, 0 replies; 30+ messages in thread
From: Radim Krčmář @ 2015-10-05 20:12 UTC (permalink / raw)
  To: Haozhong Zhang
  Cc: kvm, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel

2015-09-28 13:38+0800, Haozhong Zhang:
> This patch makes KVM use virtual_tsc_khz rather than the host TSC rate
> as vcpu's TSC rate to compute the time scale if TSC scaling is enabled.
> 
> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> ---
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> @@ -1782,7 +1782,9 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
>  		return 0;
>  
>  	if (unlikely(vcpu->hw_tsc_khz != this_tsc_khz)) {
> -		kvm_get_time_scale(NSEC_PER_SEC / 1000, this_tsc_khz,
> +		tgt_tsc_khz = kvm_has_tsc_control ?
> +			vcpu->virtual_tsc_khz : this_tsc_khz;
> +		kvm_get_time_scale(NSEC_PER_SEC / 1000, tgt_tsc_khz,
>  				   &vcpu->hv_clock.tsc_shift,
>  				   &vcpu->hv_clock.tsc_to_system_mul);

Good catch, it seems that SVM didn't scale kvmclock correctly ...
I think we'll want this patch in stable.

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
  2015-10-05 19:53   ` Radim Krčmář
@ 2015-10-05 20:46     ` David Matlack
  2015-10-06  4:06     ` Haozhong Zhang
  1 sibling, 0 replies; 30+ messages in thread
From: David Matlack @ 2015-10-05 20:46 UTC (permalink / raw)
  To: Radim Krčmář
  Cc: Haozhong Zhang, kvm list, Gleb Natapov, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86, Joerg Roedel,
	Wanpeng Li, Xiao Guangrong, Mihai Donțu, Andy Lutomirski,
	Kai Huang, linux-kernel

On Mon, Oct 5, 2015 at 12:53 PM, Radim Krčmář <rkrcmar@redhat.com> wrote:
> 2015-09-28 13:38+0800, Haozhong Zhang:
>> Both VMX and SVM propagate virtual_tsc_khz in the same way, so this
>> patch removes the call-back set_tsc_khz() and replaces it with a common
>> function.
>>
>> Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
>> ---
>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>> +static void set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
>> +{
>> +     u64 ratio, khz;
> | [...]
>> +     khz = user_tsc_khz;
>
> I'd use "user_tsc_khz" directly.
>
>> +     /* TSC scaling required  - calculate ratio */
>> +     shift = (kvm_tsc_scaling_ratio_frac_bits <= 32) ?
>> +             kvm_tsc_scaling_ratio_frac_bits : 32;
>> +     ratio = khz << shift;
>> +     do_div(ratio, tsc_khz);
>> +     ratio <<= (kvm_tsc_scaling_ratio_frac_bits - shift);
>
> VMX is losing 16 bits by this operation;  normal fixed point division
> could get us a smaller drift (and an one-liner here) ...
> at 4.3 GHz, 32 instead of 48 bits after decimal point translate to one
> "lost" TSC tick per second, in the worst case.

We can easily avoid losing precision on x86_64 (divq allows a 128-bit
dividend). 32-bit can just lose the 16 bits of precision (TSC scaling
is only available on SkyLake, and I'd be surprised if there were
many hosts running KVM in protected mode on SkyLake :)).

>
> Please mention that we are truncating on purpose :)
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch
  2015-10-05 19:26   ` Radim Krčmář
@ 2015-10-06  1:54     ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-10-06  1:54 UTC (permalink / raw)
  To: Radim Krčmář
  Cc: kvm, Gleb Natapov, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel

On Mon, Oct 05, 2015 at 09:26:30PM +0200, Radim Krčmář wrote:
> 2015-09-28 13:38+0800, Haozhong Zhang:
> > This patch moves the field of TSC scaling ratio from the architecture
> > struct vcpu_svm to the common struct kvm_vcpu_arch.
> > 
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > @@ -7080,6 +7080,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
> >  
> >  	vcpu = kvm_x86_ops->vcpu_create(kvm, id);
> >  
> > +	if (!IS_ERR(vcpu))
> > +		vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
> 
> This shouldn't be necessary, (and we can definitely do it without error
> checking later)
> 
>  kvm_arch_vcpu_create
>    (vmx|svm)_create_vcpu
>      kvm_vcpu_init
>        kvm_arch_vcpu_init
>          kvm_set_tsc_khz
> 
> sets vcpu->arch.tsc_scaling_ratio to something reasonable and SVM didn't
> overwrite that value.  (kvm_set_tsc_khz() only doesn't set the ration if
> this_tsc_khz == 0, which we could extend to be extra safe.)

Thanks Radim! I even didn't notice this path. I'll remove the ratio
setting in kvm_arch_vcpu_create(). In kvm_set_tsc_khz(), if
this_tsc_khz == 0, I'll make it set vcpu->arch.tsc_scaling_ratio to
kvm_default_tsc_scaling_ratio.

- Haozhong

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
  2015-10-05 19:53   ` Radim Krčmář
  2015-10-05 20:46     ` David Matlack
@ 2015-10-06  4:06     ` Haozhong Zhang
  2015-10-06 10:40       ` Paolo Bonzini
  1 sibling, 1 reply; 30+ messages in thread
From: Haozhong Zhang @ 2015-10-06  4:06 UTC (permalink / raw)
  To: Radim Krčmář
  Cc: David Matlack, kvm, Gleb Natapov, Paolo Bonzini, Thomas Gleixner,
	Ingo Molnar, H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li,
	Xiao Guangrong, Mihai Donțu, Andy Lutomirski, Kai Huang,
	linux-kernel

On Mon, Oct 05, 2015 at 09:53:26PM +0200, Radim Krčmář wrote:
> 2015-09-28 13:38+0800, Haozhong Zhang:
> > Both VMX and SVM propagate virtual_tsc_khz in the same way, so this
> > patch removes the call-back set_tsc_khz() and replaces it with a common
> > function.
> > 
> > Signed-off-by: Haozhong Zhang <haozhong.zhang@intel.com>
> > ---
> > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> > +static void set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
> > +{
> > +	u64 ratio, khz;
> | [...]
> > +	khz = user_tsc_khz;
> 
> I'd use "user_tsc_khz" directly.
>

I'll do so.

> > +	/* TSC scaling required  - calculate ratio */
> > +	shift = (kvm_tsc_scaling_ratio_frac_bits <= 32) ?
> > +		kvm_tsc_scaling_ratio_frac_bits : 32;
> > +	ratio = khz << shift;
> > +	do_div(ratio, tsc_khz);
> > +	ratio <<= (kvm_tsc_scaling_ratio_frac_bits - shift);
> 
> VMX is losing 16 bits by this operation;  normal fixed point division
> could get us a smaller drift (and an one-liner here) ...
> at 4.3 GHz, 32 instead of 48 bits after decimal point translate to one
> "lost" TSC tick per second, in the worst case.
>
> Please mention that we are truncating on purpose :)

It's intentional to avoid the potential overflow in
  khz << kvm_tsc_scaling_ratio_frac_bits.

For VMX where kvm_tsc_scaling_ratio_frac_bits == 48, the above
expression is only safe to left shift a pretty small khz (< 2^16 KHz
or 65.5 MHz). Thus, I decided to sacrifice the precision for safety.
I chose to truncate at the boundary of 32 bits which can handle
khz as large as 4294 GHz.

Though this truncation results in losing TSC ticks when khz is larger
than 4.3 GHz, the lost is however pretty small compared with the large
khz.

Alternatively, it's also possible to follow David's comment to use
divq on x86_64 to keep both precision and safety. On i386, it just
falls back to above truncating approach.

- Haozhong

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
  2015-10-06  4:06     ` Haozhong Zhang
@ 2015-10-06 10:40       ` Paolo Bonzini
  2015-10-06 11:32         ` Haozhong Zhang
  0 siblings, 1 reply; 30+ messages in thread
From: Paolo Bonzini @ 2015-10-06 10:40 UTC (permalink / raw)
  To: Radim Krčmář,
	David Matlack, kvm, Gleb Natapov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel



On 06/10/2015 06:06, Haozhong Zhang wrote:
> Alternatively, it's also possible to follow David's comment to use
> divq on x86_64 to keep both precision and safety. On i386, it just
> falls back to above truncating approach.

khz is just 32 bits, so we can do a 96/32 division.  And because this is
a slow path, we can code a generic u64*u32/u32 function and use it to do
(1 << kvm_tsc_scaling_ratio_frac_bits) * khz / tsc_khz:

diff --git a/include/linux/math64.h b/include/linux/math64.h
index c45c089bfdac..5b70af4fa386 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -142,6 +142,13 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul,
unsigned int shift)
 }
 #endif /* mul_u64_u32_shr */

+#ifndef mul_u64_u32_div
+static inline u64 mul_u64_u32_div(u64 x, u32 num, u32 den)
+{
+	return (u64)(((unsigned __int128)a * mul) / den);
+}
+#endif
+
 #else

 #ifndef mul_u64_u32_shr
@@ -161,6 +168,35 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul,
unsigned int shift)
 }
 #endif /* mul_u64_u32_shr */

+#ifndef mul_u64_u32_div
+static inline u64 mul_u64_u32_div(u64 a, u32 num, u32 den)
+{
+	union {
+		u64 ll;
+		struct {
+#ifdef __BIG_ENDIAN
+			u32 high, low;
+#else
+			u32 low, high;
+#endif
+		} l;
+	} u, rl, rh;
+
+	u.ll = a;
+	rl.ll = (u64)u.l.low * num;
+	rh.ll = (u64)u.l.high * num + rl.l.high;
+
+	/* Bits 32-63 of the result will be in rh.l.low.  */
+	rl.l.high = do_div(rh.ll, den);
+
+	/* Bits 0-31 of the result will be in rl.l.low.  */
+	do_div(rl.ll, den);
+
+	rl.l.high = rh.l.low;
+	return rl.ll;
+}
+#endif
+
 #endif

 #endif /* _LINUX_MATH64_H */

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function
  2015-10-06 10:40       ` Paolo Bonzini
@ 2015-10-06 11:32         ` Haozhong Zhang
  0 siblings, 0 replies; 30+ messages in thread
From: Haozhong Zhang @ 2015-10-06 11:32 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Radim Krčmář,
	David Matlack, kvm, Gleb Natapov, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, x86, Joerg Roedel, Wanpeng Li, Xiao Guangrong,
	Mihai Donțu, Andy Lutomirski, Kai Huang, linux-kernel

On Tue, Oct 06, 2015 at 12:40:49PM +0200, Paolo Bonzini wrote:
> 
> 
> On 06/10/2015 06:06, Haozhong Zhang wrote:
> > Alternatively, it's also possible to follow David's comment to use
> > divq on x86_64 to keep both precision and safety. On i386, it just
> > falls back to above truncating approach.
> 
> khz is just 32 bits, so we can do a 96/32 division.  And because this is
> a slow path, we can code a generic u64*u32/u32 function and use it to do
> (1 << kvm_tsc_scaling_ratio_frac_bits) * khz / tsc_khz:
>

This is much better! Thanks Paolo! I'll use this mul_u64_u32_shr() in
the next version.

> diff --git a/include/linux/math64.h b/include/linux/math64.h
> index c45c089bfdac..5b70af4fa386 100644
> --- a/include/linux/math64.h
> +++ b/include/linux/math64.h
> @@ -142,6 +142,13 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul,
> unsigned int shift)
>  }
>  #endif /* mul_u64_u32_shr */
> 
> +#ifndef mul_u64_u32_div
> +static inline u64 mul_u64_u32_div(u64 x, u32 num, u32 den)
> +{
> +	return (u64)(((unsigned __int128)a * mul) / den);
> +}
> +#endif
> +
>  #else
> 
>  #ifndef mul_u64_u32_shr
> @@ -161,6 +168,35 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul,
> unsigned int shift)
>  }
>  #endif /* mul_u64_u32_shr */
> 
> +#ifndef mul_u64_u32_div
> +static inline u64 mul_u64_u32_div(u64 a, u32 num, u32 den)
> +{
> +	union {
> +		u64 ll;
> +		struct {
> +#ifdef __BIG_ENDIAN
> +			u32 high, low;
> +#else
> +			u32 low, high;
> +#endif
> +		} l;
> +	} u, rl, rh;
> +
> +	u.ll = a;
> +	rl.ll = (u64)u.l.low * num;
> +	rh.ll = (u64)u.l.high * num + rl.l.high;
> +
> +	/* Bits 32-63 of the result will be in rh.l.low.  */
> +	rl.l.high = do_div(rh.ll, den);
> +
> +	/* Bits 0-31 of the result will be in rl.l.low.  */
> +	do_div(rl.ll, den);
> +
> +	rl.l.high = rh.l.low;
> +	return rl.ll;
> +}
> +#endif
> +
>  #endif
> 
>  #endif /* _LINUX_MATH64_H */
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2015-10-06 11:32 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-28  5:37 [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Haozhong Zhang
2015-09-28  5:38 ` [PATCH 01/12] KVM: x86: Collect information for setting TSC scaling ratio Haozhong Zhang
2015-09-29  3:28   ` Eric Northup
2015-09-29  4:01     ` Haozhong Zhang
2015-09-28  5:38 ` [PATCH 02/12] KVM: x86: Add a common TSC scaling ratio field in kvm_vcpu_arch Haozhong Zhang
2015-10-05 19:26   ` Radim Krčmář
2015-10-06  1:54     ` Haozhong Zhang
2015-09-28  5:38 ` [PATCH 03/12] KVM: x86: Add a common TSC scaling function Haozhong Zhang
2015-09-28 20:12   ` Paolo Bonzini
2015-09-29  1:51     ` Haozhong Zhang
2015-09-28  5:38 ` [PATCH 04/12] KVM: x86: Replace call-back set_tsc_khz() with a common function Haozhong Zhang
     [not found]   ` <CAG7+5M3z2-OKsy0wxxks2oW9+7WmFpO4JQETTx3KsaW-hWMGqw@mail.gmail.com>
2015-09-29  3:47     ` Haozhong Zhang
2015-10-05 19:53   ` Radim Krčmář
2015-10-05 20:46     ` David Matlack
2015-10-06  4:06     ` Haozhong Zhang
2015-10-06 10:40       ` Paolo Bonzini
2015-10-06 11:32         ` Haozhong Zhang
2015-09-28  5:38 ` [PATCH 05/12] KVM: x86: Replace call-back compute_tsc_offset() " Haozhong Zhang
2015-09-28  5:38 ` [PATCH 06/12] KVM: x86: Move TSC scaling logic out of call-back adjust_tsc_offset() Haozhong Zhang
2015-09-28 20:14   ` Paolo Bonzini
2015-09-29  1:47     ` Haozhong Zhang
2015-09-28  5:38 ` [PATCH 07/12] KVM: x86: Move TSC scaling logic out of call-back read_l1_tsc() Haozhong Zhang
2015-09-28  5:38 ` [PATCH 08/12] KVM: x86: Use the correct vcpu's TSC rate to compute time scale Haozhong Zhang
2015-10-05 20:12   ` Radim Krčmář
2015-09-28  5:38 ` [PATCH 09/12] KVM: VMX: Enable and initialize VMX TSC scaling Haozhong Zhang
2015-09-28  5:38 ` [PATCH 10/12] KVM: VMX: Setup TSC scaling ratio when a vcpu is loaded Haozhong Zhang
2015-09-28  5:38 ` [PATCH 11/12] KVM: VMX: Use a scaled host TSC for guest readings of MSR_IA32_TSC Haozhong Zhang
2015-09-28  5:38 ` [PATCH 12/12] KVM: VMX: Dump TSC multiplier in dump_vmcs() Haozhong Zhang
2015-09-29  4:00 ` [PATCH 00/12] KVM: x86: add support for VMX TSC scaling Eric Northup
2015-09-29  4:03   ` Haozhong Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).