|
Alexander Graf |
666609 |
From: Wanpeng Li <wanpeng.li@hotmail.com>
|
|
Alexander Graf |
666609 |
Date: Fri, 6 Oct 2017 07:38:32 -0700
|
|
Alexander Graf |
666609 |
Subject: KVM: LAPIC: Apply change to TDCR right away to the timer
|
|
Alexander Graf |
666609 |
MIME-Version: 1.0
|
|
Alexander Graf |
666609 |
Content-Type: text/plain; charset=UTF-8
|
|
Alexander Graf |
666609 |
Content-Transfer-Encoding: 8bit
|
|
Alexander Graf |
666609 |
Patch-mainline: v4.15-rc1
|
|
Alexander Graf |
666609 |
Git-commit: c301b909e4b94e6395251787e28b335c51309fff
|
|
Alexander Graf |
666609 |
References: bsc#1077761
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
The description in the Intel SDM of how the divide configuration
|
|
Alexander Graf |
666609 |
register is used: "The APIC timer frequency will be the processor's bus
|
|
Alexander Graf |
666609 |
clock or core crystal clock frequency divided by the value specified in
|
|
Alexander Graf |
666609 |
the divide configuration register."
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
Observation of baremetal shown that when the TDCR is change, the TMCCT
|
|
Alexander Graf |
666609 |
does not change or make a big jump in value, but the rate at which it
|
|
Alexander Graf |
666609 |
count down change.
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
The patch update the emulation to APIC timer to so that a change to the
|
|
Alexander Graf |
666609 |
divide configuration would be reflected in the value of the counter and
|
|
Alexander Graf |
666609 |
when the next interrupt is triggered.
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
Cc: Paolo Bonzini <pbonzini@redhat.com>
|
|
Alexander Graf |
666609 |
Cc: Radim Krčmář <rkrcmar@redhat.com>
|
|
Alexander Graf |
666609 |
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
|
|
Alexander Graf |
666609 |
[Fixed some whitespace and added a check for negative delta and running
|
|
Alexander Graf |
666609 |
timer. - Radim]
|
|
Alexander Graf |
666609 |
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
|
|
Alexander Graf |
666609 |
Acked-by: Alexander Graf <agraf@suse.de>
|
|
Alexander Graf |
666609 |
---
|
|
Alexander Graf |
666609 |
arch/x86/kvm/lapic.c | 36 ++++++++++++++++++++++++++++++++++--
|
|
Alexander Graf |
666609 |
1 file changed, 34 insertions(+), 2 deletions(-)
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
--- a/arch/x86/kvm/lapic.c
|
|
Alexander Graf |
666609 |
+++ b/arch/x86/kvm/lapic.c
|
|
Alexander Graf |
666609 |
@@ -1456,6 +1456,30 @@
|
|
Alexander Graf |
666609 |
HRTIMER_MODE_ABS_PINNED);
|
|
Alexander Graf |
666609 |
}
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
+static void update_target_expiration(struct kvm_lapic *apic, uint32_t old_divisor)
|
|
Alexander Graf |
666609 |
+{
|
|
Alexander Graf |
666609 |
+ ktime_t now, remaining;
|
|
Alexander Graf |
666609 |
+ u64 ns_remaining_old, ns_remaining_new;
|
|
Alexander Graf |
666609 |
+
|
|
Alexander Graf |
666609 |
+ apic->lapic_timer.period = (u64)kvm_lapic_get_reg(apic, APIC_TMICT)
|
|
Alexander Graf |
666609 |
+ * APIC_BUS_CYCLE_NS * apic->divide_count;
|
|
Alexander Graf |
666609 |
+ limit_periodic_timer_frequency(apic);
|
|
Alexander Graf |
666609 |
+
|
|
Alexander Graf |
666609 |
+ now = ktime_get();
|
|
Alexander Graf |
666609 |
+ remaining = ktime_sub(apic->lapic_timer.target_expiration, now);
|
|
Alexander Graf |
666609 |
+ if (ktime_to_ns(remaining) < 0)
|
|
Alexander Graf |
666609 |
+ remaining = 0;
|
|
Alexander Graf |
666609 |
+
|
|
Alexander Graf |
666609 |
+ ns_remaining_old = ktime_to_ns(remaining);
|
|
Alexander Graf |
666609 |
+ ns_remaining_new = mul_u64_u32_div(ns_remaining_old,
|
|
Alexander Graf |
666609 |
+ apic->divide_count, old_divisor);
|
|
Alexander Graf |
666609 |
+
|
|
Alexander Graf |
666609 |
+ apic->lapic_timer.tscdeadline +=
|
|
Alexander Graf |
666609 |
+ nsec_to_cycles(apic->vcpu, ns_remaining_new) -
|
|
Alexander Graf |
666609 |
+ nsec_to_cycles(apic->vcpu, ns_remaining_old);
|
|
Alexander Graf |
666609 |
+ apic->lapic_timer.target_expiration = ktime_add_ns(now, ns_remaining_new);
|
|
Alexander Graf |
666609 |
+}
|
|
Alexander Graf |
666609 |
+
|
|
Alexander Graf |
666609 |
static bool set_target_expiration(struct kvm_lapic *apic)
|
|
Alexander Graf |
666609 |
{
|
|
Alexander Graf |
666609 |
ktime_t now;
|
|
Alexander Graf |
666609 |
@@ -1748,13 +1772,21 @@
|
|
Alexander Graf |
666609 |
start_apic_timer(apic);
|
|
Alexander Graf |
666609 |
break;
|
|
Alexander Graf |
666609 |
|
|
Alexander Graf |
666609 |
- case APIC_TDCR:
|
|
Alexander Graf |
666609 |
+ case APIC_TDCR: {
|
|
Alexander Graf |
666609 |
+ uint32_t old_divisor = apic->divide_count;
|
|
Alexander Graf |
666609 |
+
|
|
Alexander Graf |
666609 |
if (val & 4)
|
|
Alexander Graf |
666609 |
apic_debug("KVM_WRITE:TDCR %x\n", val);
|
|
Alexander Graf |
666609 |
kvm_lapic_set_reg(apic, APIC_TDCR, val);
|
|
Alexander Graf |
666609 |
update_divide_count(apic);
|
|
Alexander Graf |
666609 |
+ if (apic->divide_count != old_divisor &&
|
|
Alexander Graf |
666609 |
+ apic->lapic_timer.period) {
|
|
Alexander Graf |
666609 |
+ hrtimer_cancel(&apic->lapic_timer.timer);
|
|
Alexander Graf |
666609 |
+ update_target_expiration(apic, old_divisor);
|
|
Alexander Graf |
666609 |
+ restart_apic_timer(apic);
|
|
Alexander Graf |
666609 |
+ }
|
|
Alexander Graf |
666609 |
break;
|
|
Alexander Graf |
666609 |
-
|
|
Alexander Graf |
666609 |
+ }
|
|
Alexander Graf |
666609 |
case APIC_ESR:
|
|
Alexander Graf |
666609 |
if (apic_x2apic_mode(apic) && val != 0) {
|
|
Alexander Graf |
666609 |
apic_debug("KVM_WRITE:ESR not zero %x\n", val);
|