From patchwork Thu Jan 28 14:02:57 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paolo Bonzini X-Patchwork-Id: 8150651 Return-Path: X-Original-To: patchwork-qemu-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 330069F38B for ; Thu, 28 Jan 2016 14:03:33 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 257DF2020F for ; Thu, 28 Jan 2016 14:03:32 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id DBADF2010C for ; Thu, 28 Jan 2016 14:03:30 +0000 (UTC) Received: from localhost ([::1]:56871 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aOnAY-0000OL-9I for patchwork-qemu-devel@patchwork.kernel.org; Thu, 28 Jan 2016 09:03:30 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:50844) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aOnAE-0000Co-He for qemu-devel@nongnu.org; Thu, 28 Jan 2016 09:03:15 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aOnA9-0002gl-Dp for qemu-devel@nongnu.org; Thu, 28 Jan 2016 09:03:10 -0500 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:33999) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aOnA8-0002gX-W8 for qemu-devel@nongnu.org; Thu, 28 Jan 2016 09:03:05 -0500 Received: by mail-wm0-x241.google.com with SMTP id p63so3942851wmp.1 for ; Thu, 28 Jan 2016 06:03:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=VxzrAgO0apKB67lK5YY+cNbW4bsW/TcTURtQMEd9bp8=; b=QCZq3Ir0/2FJEhS97+Xfr/1TvnAcw0HAao+7I99g5473NIBBHZSQLDNixRek6Tc3nq H5Z3oOoPArD6ggHfVcRjAJTQ98fwAeTtIRMyNW13/7UEJEQcCDrzqB7TkphxDL/MSbZo FgUNvqMaE2AARhmyrLAVRfwp6o4lLPT73BWuDoNjfnaz/Fp2EDiXlTI0YW0ya78RfEde u2GCJjGtjASbXEk6QSiyb2gC4/v/osrHZJOoO+f4OdyZI5UmxXwhQL+V6SYR67Mawz9C gmzUYZQLLby3xniOjtVNmqHgXzatCI4vxN708qENmn699YWVQdEvIKwyrsuVxf6FECvg FljA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=VxzrAgO0apKB67lK5YY+cNbW4bsW/TcTURtQMEd9bp8=; b=Wk2oiV244YyUzpUu5nMhS65vT6FeOKTYW4ocYrNzUviQj0FhXmffyjK1FWa4kS/BGI TongBQkrCgnv1CZi217Y8AhsWa/yZTqWqpfobrhxgtDmlZB9drmOWGNhwcjaXOoN5s9l bjVgOR4Xdqp27YJCFu4yWwuLQ9SnWgL/bzg9igorEe97yRgx9/GEp6J97KqoMsMkEefy via4Hpmsgbo9o19N4//FDa+r0qjYDwyiAaLFOMeOc2tf+adUosEfSQ0v1F/sYUddNRmD 54A1QuC0d6PF4/GqlgPcuc1CRM1L50R2D/HM9kphbUzUOyU3zHL0IuklhAnhZiaROdDE gWvg== X-Gm-Message-State: AG10YOQij2cMcsCTrD0UN7DohR5GHgdU+L++DGO1heYeccW4Or6//LhpeQIZbngHqLpw8g== X-Received: by 10.194.113.227 with SMTP id jb3mr3404920wjb.49.1453989784320; Thu, 28 Jan 2016 06:03:04 -0800 (PST) Received: from 640k.lan (94-39-161-9.adsl-ull.clienti.tiscali.it. [94.39.161.9]) by smtp.gmail.com with ESMTPSA id i63sm3021546wmf.24.2016.01.28.06.03.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 28 Jan 2016 06:03:03 -0800 (PST) From: Paolo Bonzini To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Date: Thu, 28 Jan 2016 15:02:57 +0100 Message-Id: <1453989777-30181-3-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1453989777-30181-1-git-send-email-pbonzini@redhat.com> References: <1453989777-30181-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::241 Cc: Andrey Smetanin , "Denis V. Lunev" , Roman Kagan , qemu-devel@nongnu.org Subject: [Qemu-devel] [PATCH 2/2] kvm/x86: Hyper-V tsc page setup X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Andrey Smetanin Lately tsc page was implemented but filled with empty values. This patch setup tsc page scale and offset based on vcpu tsc, tsc_khz and HV_X64_MSR_TIME_REF_COUNT value. The valid tsc page drops HV_X64_MSR_TIME_REF_COUNT msr reads count to zero which potentially improves performance. Signed-off-by: Andrey Smetanin Reviewed-by: Peter Hornyack CC: Paolo Bonzini CC: Roman Kagan CC: Denis V. Lunev CC: qemu-devel@nongnu.org [Skip sequence number 0xFFFFFFFF as suggested by Peter Hornyack, enable only if KVM master clock is active. - Paolo] Signed-off-by: Paolo Bonzini --- There is an accuracy problem with this patch. See the kvm-unit-tests patch I'll send shortly. arch/x86/kvm/hyperv.c | 121 +++++++++++++++++++++++++++++++++++++++++++------- arch/x86/kvm/hyperv.h | 2 + arch/x86/kvm/x86.c | 6 ++- 3 files changed, 112 insertions(+), 17 deletions(-) diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c index c58ba67175ac..adb0e72464c0 100644 --- a/arch/x86/kvm/hyperv.c +++ b/arch/x86/kvm/hyperv.c @@ -756,6 +756,109 @@ static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, return 0; } +static u64 calc_tsc_page_scale(u32 tsc_khz) +{ + /* + * reftime (in 100ns) = tsc * tsc_scale / 2^64 + tsc_offset + * so reftime_delta = (tsc_delta * tsc_scale) / 2^64 + * so tsc_scale = (2^64 * reftime_delta)/tsc_delta + * so tsc_scale = (2^64 * 10 * 10^6) / tsc_hz = (2^64 * 10000) / tsc_khz + */ + u32 h, l; + + /* Long division */ + h = 10000; + l = do_shl32_div32(h, tsc_khz); + (void) do_shl32_div32(l, tsc_khz); + + return ((u64)h << 32) | l; +} + +/* If tsc_khz <= 10000, the scale doesn't fit in 64 bits. */ +#define MIN_VALID_TSC_KHZ 10001 + +static int write_tsc_page(struct kvm *kvm, u64 gfn, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_write_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + mark_page_dirty(kvm, gfn); + return 0; +} + +static int read_tsc_page(struct kvm *kvm, u64 gfn, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + if (kvm_read_guest(kvm, gfn_to_gpa(gfn), + tsc_ref, sizeof(*tsc_ref))) + return 1; + return 0; +} + +static u64 calc_tsc_page_time(struct kvm_vcpu *vcpu, + PHV_REFERENCE_TSC_PAGE tsc_ref) +{ + + u64 tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + return mul_u64_u64_shr(tsc, tsc_ref->tsc_scale, 64) + + tsc_ref->tsc_offset; +} + +int kvm_hv_setup_tsc_page(struct kvm *kvm, bool has_master_clock) +{ + struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, 0); + struct kvm_hv *hv = &kvm->arch.hyperv; + HV_REFERENCE_TSC_PAGE tsc_ref = { 0 }; + u32 tsc_khz; + int r; + u64 gfn, ref_time, tsc_scale, tsc_offset, tsc; + + if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE)) + return 0; + + gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; + kvm_debug("tsc page gfn 0x%llx\n", gfn); + + tsc_khz = vcpu->arch.virtual_tsc_khz; + if (!has_master_clock || WARN_ON_ONCE(!tsc_khz) || + tsc_khz < MIN_VALID_TSC_KHZ) { + /* Use reference time MSR. */ + goto done; + } + + r = read_tsc_page(kvm, gfn, &tsc_ref); + if (r) { + kvm_err("can't access tsc page gfn 0x%llx\n", gfn); + return r; + } + + tsc_scale = calc_tsc_page_scale(tsc_khz); + ref_time = get_time_ref_counter(kvm); + tsc = kvm_read_l1_tsc(vcpu, rdtsc()); + + /* tsc_offset = reftime - tsc * tsc_scale / 2^64 */ + tsc_offset = ref_time - mul_u64_u64_shr(tsc, tsc_scale, 64); + kvm_debug("tsc khz %u tsc %llu scale %llu offset %llu\n", + tsc_khz, tsc, tsc_scale, tsc_offset); + + tsc_ref.tsc_sequence++; + if (tsc_ref.tsc_sequence == 0xFFFFFFFF || + tsc_ref.tsc_sequence == 0) + tsc_ref.tsc_sequence = 1; + + tsc_ref.tsc_scale = tsc_scale; + tsc_ref.tsc_offset = tsc_offset; + + kvm_debug("tsc page calibration time %llu vs. reftime %llu\n", + calc_tsc_page_time(vcpu, &tsc_ref), + get_time_ref_counter(kvm)); + +done: + return write_tsc_page(kvm, gfn, &tsc_ref); +} + static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) { @@ -793,23 +896,11 @@ static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, mark_page_dirty(kvm, gfn); break; } - case HV_X64_MSR_REFERENCE_TSC: { - u64 gfn; - HV_REFERENCE_TSC_PAGE tsc_ref; - - memset(&tsc_ref, 0, sizeof(tsc_ref)); + case HV_X64_MSR_REFERENCE_TSC: hv->hv_tsc_page = data; - if (!(data & HV_X64_MSR_TSC_REFERENCE_ENABLE)) - break; - gfn = data >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; - if (kvm_write_guest( - kvm, - gfn << HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT, - &tsc_ref, sizeof(tsc_ref))) - return 1; - mark_page_dirty(kvm, gfn); + if (hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) + kvm_make_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu); break; - } case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: return kvm_hv_msr_set_crash_data(vcpu, msr - HV_X64_MSR_CRASH_P0, diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h index 60eccd4bd1d3..2e300d9cfdc0 100644 --- a/arch/x86/kvm/hyperv.h +++ b/arch/x86/kvm/hyperv.h @@ -84,4 +84,6 @@ static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu) void kvm_hv_process_stimers(struct kvm_vcpu *vcpu); +int kvm_hv_setup_tsc_page(struct kvm *kvm, bool has_master_clock); + #endif diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5b937fdebc66..2507cbb34537 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1231,9 +1231,7 @@ static void kvm_get_time_scale(uint32_t scaled_khz, uint32_t base_khz, __func__, base_khz, scaled_khz, shift, *pmultiplier); } -#ifdef CONFIG_X86_64 static atomic_t kvm_guest_has_master_clock = ATOMIC_INIT(0); -#endif static DEFINE_PER_CPU(unsigned long, cpu_tsc_khz); static unsigned long max_tsc_khz; @@ -1706,6 +1704,10 @@ static void kvm_gen_update_masterclock(struct kvm *kvm) spin_unlock(&ka->pvclock_gtod_sync_lock); #endif + + if (kvm->arch.hyperv.hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE) + kvm_hv_setup_tsc_page(kvm, + atomic_read(&kvm_guest_has_master_clock)); } static int kvm_guest_time_update(struct kvm_vcpu *v)