2017-10-04 09:46+0800, Wanpeng Li: > 2017-10-04 1:06 GMT+08:00 Radim Krčmář <rkrc...@redhat.com>: > > 2017-09-28 18:04-0700, Wanpeng Li: > >> From: Wanpeng Li <wanpeng...@hotmail.com> > >> > >> If we take TSC-deadline mode timer out of the picture, the Intel SDM > >> does not say that the timer is disable when the timer mode is change, > >> either from one-shot to periodic or vice versa. > > > > I think it does, please see comment under [v2 1/4]. > > As I replied to [v2 1/4].
Right, so we probably shouldn't disable the timer. > >> After this patch, the timer is no longer disarmed on change of mode, so > >> the counter (TMCCT) keeps counting down. > >> > >> So what does a write to LVTT changes ? On baremetal, the change of mode > >> is probably taken into account only when the counter reach 0. When this > >> happen, LVTT is use to figure out if the counter should restard counting > >> down from TMICT (so periodic mode) or stop counting (if one-shot mode). > >> > >> This patch is based on observation of the behavior of the APIC timer on > >> baremetal as well as check that they does not go against the description > >> written in the Intel SDM. > >> > >> Cc: Paolo Bonzini <pbonz...@redhat.com> > >> Cc: Radim Krčmář <rkrc...@redhat.com> > >> Signed-off-by: Wanpeng Li <wanpeng...@hotmail.com> > >> --- > >> arch/x86/kvm/lapic.c | 40 ++++++++++++++++++++++++++++------------ > >> 1 file changed, 28 insertions(+), 12 deletions(-) > >> > >> diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c > >> index a739cbb..946c11b 100644 > >> --- a/arch/x86/kvm/lapic.c > >> +++ b/arch/x86/kvm/lapic.c > >> @@ -1301,7 +1301,7 @@ static void update_divide_count(struct kvm_lapic > >> *apic) > >> apic->divide_count); > >> } > >> > >> -static void apic_update_lvtt(struct kvm_lapic *apic) > >> +static bool apic_update_lvtt(struct kvm_lapic *apic) > >> { > >> u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) & > >> apic->lapic_timer.timer_mode_mask; > >> @@ -1309,7 +1309,9 @@ static void apic_update_lvtt(struct kvm_lapic *apic) > >> if (apic->lapic_timer.timer_mode != timer_mode) { > >> apic->lapic_timer.timer_mode = timer_mode; > >> hrtimer_cancel(&apic->lapic_timer.timer); > >> + return true; > >> } > >> + return false; > >> } > >> > >> static void apic_timer_expired(struct kvm_lapic *apic) > >> @@ -1729,7 +1744,8 @@ int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 > >> reg, u32 val) > >> val |= APIC_LVT_MASKED; > >> val &= (apic_lvt_mask[0] | > >> apic->lapic_timer.timer_mode_mask); > >> kvm_lapic_set_reg(apic, APIC_LVTT, val); > >> - apic_update_lvtt(apic); > >> + if (apic_update_lvtt(apic) && !apic_lvtt_tscdeadline(apic)) > >> + start_apic_timer(apic, true); Changing the timer from one-shot to periodic doesn't change the expected expiration -- I think we could instead skip hrtimer_cancel() in apic_update_lvtt().