diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-02-10 17:41:41 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-02-14 19:47:38 -0500 |
commit | b682b814e3cc340f905c14dff87ce8bdba7c5eba (patch) | |
tree | 315edc1c2990a57b6af99fda00e0445a2b175390 /arch/x86/kvm | |
parent | d7cff1c37664971aae32bb0de82231ed34933d8e (diff) |
KVM: x86: fix LAPIC pending count calculation
Simplify LAPIC TMCCT calculation by using hrtimer provided
function to query remaining time until expiration.
Fixes host hang with nested ESX.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r-- | arch/x86/kvm/irq.c | 7 | ||||
-rw-r--r-- | arch/x86/kvm/irq.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 66 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 1 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 1 |
6 files changed, 15 insertions, 63 deletions
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index c019b8edcdb7..cf17ed52f6fb 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c | |||
@@ -87,13 +87,6 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) | |||
87 | } | 87 | } |
88 | EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); | 88 | EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); |
89 | 89 | ||
90 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) | ||
91 | { | ||
92 | kvm_apic_timer_intr_post(vcpu, vec); | ||
93 | /* TODO: PIT, RTC etc. */ | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(kvm_timer_intr_post); | ||
96 | |||
97 | void __kvm_migrate_timers(struct kvm_vcpu *vcpu) | 90 | void __kvm_migrate_timers(struct kvm_vcpu *vcpu) |
98 | { | 91 | { |
99 | __kvm_migrate_apic_timer(vcpu); | 92 | __kvm_migrate_apic_timer(vcpu); |
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 2bf32a03ceec..82579ee538d0 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h | |||
@@ -89,7 +89,6 @@ static inline int irqchip_in_kernel(struct kvm *kvm) | |||
89 | 89 | ||
90 | void kvm_pic_reset(struct kvm_kpic_state *s); | 90 | void kvm_pic_reset(struct kvm_kpic_state *s); |
91 | 91 | ||
92 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); | ||
93 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); | 92 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); |
94 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); | 93 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); |
95 | void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); | 94 | void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index afac68c0815c..f0b67f2cdd69 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -35,6 +35,12 @@ | |||
35 | #include "kvm_cache_regs.h" | 35 | #include "kvm_cache_regs.h" |
36 | #include "irq.h" | 36 | #include "irq.h" |
37 | 37 | ||
38 | #ifndef CONFIG_X86_64 | ||
39 | #define mod_64(x, y) ((x) - (y) * div64_u64(x, y)) | ||
40 | #else | ||
41 | #define mod_64(x, y) ((x) % (y)) | ||
42 | #endif | ||
43 | |||
38 | #define PRId64 "d" | 44 | #define PRId64 "d" |
39 | #define PRIx64 "llx" | 45 | #define PRIx64 "llx" |
40 | #define PRIu64 "u" | 46 | #define PRIu64 "u" |
@@ -511,52 +517,22 @@ static void apic_send_ipi(struct kvm_lapic *apic) | |||
511 | 517 | ||
512 | static u32 apic_get_tmcct(struct kvm_lapic *apic) | 518 | static u32 apic_get_tmcct(struct kvm_lapic *apic) |
513 | { | 519 | { |
514 | u64 counter_passed; | 520 | ktime_t remaining; |
515 | ktime_t passed, now; | 521 | s64 ns; |
516 | u32 tmcct; | 522 | u32 tmcct; |
517 | 523 | ||
518 | ASSERT(apic != NULL); | 524 | ASSERT(apic != NULL); |
519 | 525 | ||
520 | now = apic->timer.dev.base->get_time(); | ||
521 | tmcct = apic_get_reg(apic, APIC_TMICT); | ||
522 | |||
523 | /* if initial count is 0, current count should also be 0 */ | 526 | /* if initial count is 0, current count should also be 0 */ |
524 | if (tmcct == 0) | 527 | if (apic_get_reg(apic, APIC_TMICT) == 0) |
525 | return 0; | 528 | return 0; |
526 | 529 | ||
527 | if (unlikely(ktime_to_ns(now) <= | 530 | remaining = hrtimer_expires_remaining(&apic->timer.dev); |
528 | ktime_to_ns(apic->timer.last_update))) { | 531 | if (ktime_to_ns(remaining) < 0) |
529 | /* Wrap around */ | 532 | remaining = ktime_set(0, 0); |
530 | passed = ktime_add(( { | 533 | |
531 | (ktime_t) { | 534 | ns = mod_64(ktime_to_ns(remaining), apic->timer.period); |
532 | .tv64 = KTIME_MAX - | 535 | tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); |
533 | (apic->timer.last_update).tv64}; } | ||
534 | ), now); | ||
535 | apic_debug("time elapsed\n"); | ||
536 | } else | ||
537 | passed = ktime_sub(now, apic->timer.last_update); | ||
538 | |||
539 | counter_passed = div64_u64(ktime_to_ns(passed), | ||
540 | (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); | ||
541 | |||
542 | if (counter_passed > tmcct) { | ||
543 | if (unlikely(!apic_lvtt_period(apic))) { | ||
544 | /* one-shot timers stick at 0 until reset */ | ||
545 | tmcct = 0; | ||
546 | } else { | ||
547 | /* | ||
548 | * periodic timers reset to APIC_TMICT when they | ||
549 | * hit 0. The while loop simulates this happening N | ||
550 | * times. (counter_passed %= tmcct) would also work, | ||
551 | * but might be slower or not work on 32-bit?? | ||
552 | */ | ||
553 | while (counter_passed > tmcct) | ||
554 | counter_passed -= tmcct; | ||
555 | tmcct -= counter_passed; | ||
556 | } | ||
557 | } else { | ||
558 | tmcct -= counter_passed; | ||
559 | } | ||
560 | 536 | ||
561 | return tmcct; | 537 | return tmcct; |
562 | } | 538 | } |
@@ -653,8 +629,6 @@ static void start_apic_timer(struct kvm_lapic *apic) | |||
653 | { | 629 | { |
654 | ktime_t now = apic->timer.dev.base->get_time(); | 630 | ktime_t now = apic->timer.dev.base->get_time(); |
655 | 631 | ||
656 | apic->timer.last_update = now; | ||
657 | |||
658 | apic->timer.period = apic_get_reg(apic, APIC_TMICT) * | 632 | apic->timer.period = apic_get_reg(apic, APIC_TMICT) * |
659 | APIC_BUS_CYCLE_NS * apic->timer.divide_count; | 633 | APIC_BUS_CYCLE_NS * apic->timer.divide_count; |
660 | atomic_set(&apic->timer.pending, 0); | 634 | atomic_set(&apic->timer.pending, 0); |
@@ -1110,16 +1084,6 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) | |||
1110 | } | 1084 | } |
1111 | } | 1085 | } |
1112 | 1086 | ||
1113 | void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec) | ||
1114 | { | ||
1115 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
1116 | |||
1117 | if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec) | ||
1118 | apic->timer.last_update = ktime_add_ns( | ||
1119 | apic->timer.last_update, | ||
1120 | apic->timer.period); | ||
1121 | } | ||
1122 | |||
1123 | int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) | 1087 | int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) |
1124 | { | 1088 | { |
1125 | int vector = kvm_apic_has_interrupt(vcpu); | 1089 | int vector = kvm_apic_has_interrupt(vcpu); |
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 81858881287e..45ab6ee71209 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -12,7 +12,6 @@ struct kvm_lapic { | |||
12 | atomic_t pending; | 12 | atomic_t pending; |
13 | s64 period; /* unit: ns */ | 13 | s64 period; /* unit: ns */ |
14 | u32 divide_count; | 14 | u32 divide_count; |
15 | ktime_t last_update; | ||
16 | struct hrtimer dev; | 15 | struct hrtimer dev; |
17 | } timer; | 16 | } timer; |
18 | struct kvm_vcpu *vcpu; | 17 | struct kvm_vcpu *vcpu; |
@@ -42,7 +41,6 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); | |||
42 | void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); | 41 | void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); |
43 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); | 42 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); |
44 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); | 43 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); |
45 | void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec); | ||
46 | 44 | ||
47 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); | 45 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); |
48 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); | 46 | void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 1452851ae258..a9e769e4e251 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -1600,7 +1600,6 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) | |||
1600 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ | 1600 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ |
1601 | intr_vector = kvm_cpu_get_interrupt(vcpu); | 1601 | intr_vector = kvm_cpu_get_interrupt(vcpu); |
1602 | svm_inject_irq(svm, intr_vector); | 1602 | svm_inject_irq(svm, intr_vector); |
1603 | kvm_timer_intr_post(vcpu, intr_vector); | ||
1604 | out: | 1603 | out: |
1605 | update_cr8_intercept(vcpu); | 1604 | update_cr8_intercept(vcpu); |
1606 | } | 1605 | } |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 07491c9c6ed0..b1fe1422afb1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3285,7 +3285,6 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) | |||
3285 | } | 3285 | } |
3286 | if (vcpu->arch.interrupt.pending) { | 3286 | if (vcpu->arch.interrupt.pending) { |
3287 | vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr); | 3287 | vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr); |
3288 | kvm_timer_intr_post(vcpu, vcpu->arch.interrupt.nr); | ||
3289 | if (kvm_cpu_has_interrupt(vcpu)) | 3288 | if (kvm_cpu_has_interrupt(vcpu)) |
3290 | enable_irq_window(vcpu); | 3289 | enable_irq_window(vcpu); |
3291 | } | 3290 | } |