diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 66 |
1 files changed, 15 insertions, 51 deletions
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); |