From patchwork Thu Oct 5 14:35:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Wanpeng Li X-Patchwork-Id: 9987349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 011B76029B for ; Thu, 5 Oct 2017 14:35:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E65B328BF0 for ; Thu, 5 Oct 2017 14:35:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D9D2A28C9C; Thu, 5 Oct 2017 14:35:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7927328BF0 for ; Thu, 5 Oct 2017 14:35:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751474AbdJEOfX (ORCPT ); Thu, 5 Oct 2017 10:35:23 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:35827 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751178AbdJEOfV (ORCPT ); Thu, 5 Oct 2017 10:35:21 -0400 Received: by mail-pg0-f65.google.com with SMTP id p5so13538302pgn.2; Thu, 05 Oct 2017 07:35:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Cpw7uaBZXzcurbZKriT3QwZkbHAbUcvwYx2xR+FFzgc=; b=QGUdGXMWoh48Pov131e9MrfM2DDLGu4Ue2YIa/uLo1urATQEGwYAl+hx9kjEw1Eiqo IJMZ8XthZInMCFeUXGBvp1uLNcofjPmAiOokSvOOkvpAwemUoFaLKaJan8jPHDX/8IZV /kRQrZZ0hqTUFVJWUlCiUY4iPSi4+WndSNLRIPkc8hHTBSEUBU8tgZ4ewej+PY9QJNPh GWvt10k/ynJlIgWTE1ir1fMaXtye/RQ+k6dHmIzyTZ+nM17tUkTX/bnpcB6JzCYAQZ1S mh4JQ/7BVntMCvk2+JPvn1wKgmmC9LtOg7D/iSLM94Ijm6LafL+pFeMATEwny+eoh9vx kCzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=Cpw7uaBZXzcurbZKriT3QwZkbHAbUcvwYx2xR+FFzgc=; b=UzIGyu0jRNH6l39+CXALrLqNkNkhvTHO/ZjvrVI2CqWVoUX1ENL1Os/tNKqc3kZvEL XBryCfBBUmptnOK+1YSRznhSE7fk2V6bZylXnhRaOlvq/l/asFRfXr2rzyAXRoEQJui0 ObH2YCoyWkFYSOtvcbriNE/vWnQIkkD/NI6kk50yRveq6jG2ptdMHc3VdlI3ZME5FAL6 NfJJxUboomSpkgXFk2BmLYfdlUqXE/JFhDgbunr95e2LN8P97UCCd0HmWIUpL1DxidR4 1/1tgoEJjrGO4hCS5T23tUybY/v0AIVaixIuMiHJoKoQ1neF2pAlYTfAVyn61SDztzv9 ia3A== X-Gm-Message-State: AMCzsaVGaz5C/v6MZKdwKO39ao86kDTC0Ooo6mJXb7U0JC1phJZx2NNk 0FFp8RUw6ja6nBYXPG74+csgMw== X-Google-Smtp-Source: AOwi7QDbe0b7TM8qpXiQDMWOWm6t+/BwBxAE1SjKlb4AMScjubAZAqZQBJdr/DLlzbEylqf2zlf5jQ== X-Received: by 10.99.120.141 with SMTP id t135mr4797862pgc.250.1507214120805; Thu, 05 Oct 2017 07:35:20 -0700 (PDT) Received: from localhost ([223.72.82.149]) by smtp.gmail.com with ESMTPSA id z8sm12276052pfl.135.2017.10.05.07.35.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 Oct 2017 07:35:20 -0700 (PDT) From: Wanpeng Li X-Google-Original-From: Wanpeng Li To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Wanpeng Li Subject: [PATCH v5 3/3] KVM: LAPIC: Apply change to TDCR right away to the timer Date: Thu, 5 Oct 2017 07:35:17 -0700 Message-Id: <1507214117-2899-1-git-send-email-wanpeng.li@hotmail.com> X-Mailer: git-send-email 2.7.4 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Wanpeng Li The description in the Intel SDM of how the divide configuration register is used: "The APIC timer frequency will be the processor's bus clock or core crystal clock frequency divided by the value specified in the divide configuration register." Observation of baremetal shown that when the TDCR is change, the TMCCT does not change or make a big jump in value, but the rate at which it count down change. The patch update the emulation to APIC timer to so that a change to the divide configuration would be reflected in the value of the counter and when the next interrupt is triggered. Cc: Paolo Bonzini Cc: Radim Krčmář Signed-off-by: Wanpeng Li --- arch/x86/kvm/lapic.c | 45 ++++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 6b366c1..36f9bc8 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1434,14 +1434,14 @@ static void start_sw_period(struct kvm_lapic *apic) HRTIMER_MODE_ABS_PINNED); } -static bool set_target_expiration(struct kvm_lapic *apic) +static bool set_target_expiration(struct kvm_lapic *apic, uint32_t old_divisor) { - ktime_t now; - u64 tscl = rdtsc(); + ktime_t now, remaining; + u64 tscl = rdtsc(), delta; now = ktime_get(); apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT) - * APIC_BUS_CYCLE_NS * apic->divide_count; + * APIC_BUS_CYCLE_NS * old_divisor; if (!apic->lapic_timer.period) return false; @@ -1474,9 +1474,24 @@ static bool set_target_expiration(struct kvm_lapic *apic) ktime_to_ns(ktime_add_ns(now, apic->lapic_timer.period))); + delta = apic->lapic_timer.period; + if (apic->divide_count != old_divisor) { + remaining = ktime_sub(apic->lapic_timer.target_expiration, now); + if (ktime_to_ns(remaining) < 0) + remaining = 0; + delta = mod_64(ktime_to_ns(remaining), apic->lapic_timer.period); + + if (!delta) + return false; + + apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT) + * APIC_BUS_CYCLE_NS * apic->divide_count; + delta = delta * apic->divide_count / old_divisor; + } + apic->lapic_timer.tscdeadline = kvm_read_l1_tsc(apic->vcpu, tscl) + - nsec_to_cycles(apic->vcpu, apic->lapic_timer.period); - apic->lapic_timer.target_expiration = ktime_add_ns(now, apic->lapic_timer.period); + nsec_to_cycles(apic->vcpu, delta); + apic->lapic_timer.target_expiration = ktime_add_ns(now, delta); return true; } @@ -1613,12 +1628,12 @@ void kvm_lapic_restart_hv_timer(struct kvm_vcpu *vcpu) restart_apic_timer(apic); } -static void start_apic_timer(struct kvm_lapic *apic) +static void start_apic_timer(struct kvm_lapic *apic, uint32_t old_divisor) { atomic_set(&apic->lapic_timer.pending, 0); if ((apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) - && !set_target_expiration(apic)) + && !set_target_expiration(apic, old_divisor)) return; restart_apic_timer(apic); @@ -1739,16 +1754,20 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) hrtimer_cancel(&apic->lapic_timer.timer); kvm_lapic_set_reg(apic, APIC_TMICT, val); - start_apic_timer(apic); + start_apic_timer(apic, apic->divide_count); break; - case APIC_TDCR: + case APIC_TDCR: { + uint32_t current_divisor = apic->divide_count; + if (val & 4) apic_debug("KVM_WRITE:TDCR %x\n", val); kvm_lapic_set_reg(apic, APIC_TDCR, val); update_divide_count(apic); + hrtimer_cancel(&apic->lapic_timer.timer); + start_apic_timer(apic, current_divisor); break; - + } case APIC_ESR: if (apic_x2apic_mode(apic) && val != 0) { apic_debug("KVM_WRITE:ESR not zero %x\n", val); @@ -1873,7 +1892,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data) hrtimer_cancel(&apic->lapic_timer.timer); apic->lapic_timer.tscdeadline = data; - start_apic_timer(apic); + start_apic_timer(apic, apic->divide_count); } void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8) @@ -2239,7 +2258,7 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct kvm_lapic_state *s) apic_update_lvtt(apic); apic_manage_nmi_watchdog(apic, kvm_lapic_get_reg(apic, APIC_LVT0)); update_divide_count(apic); - start_apic_timer(apic); + start_apic_timer(apic, apic->divide_count); apic->irr_pending = true; apic->isr_count = vcpu->arch.apicv_active ? 1 : count_vectors(apic->regs + APIC_ISR);