Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9da8f4e83a824dabf3fb7ad0890549257ae614a0
Commit:     9da8f4e83a824dabf3fb7ad0890549257ae614a0
Parent:     b33ac88b4c23330043acad930517282eb486db1d
Author:     Kevin Pedretti <[EMAIL PROTECTED]>
AuthorDate: Sun Oct 21 08:55:50 2007 +0200
Committer:  Avi Kivity <[EMAIL PROTECTED]>
CommitDate: Mon Oct 22 12:03:29 2007 +0200

    KVM: Improve local apic timer wraparound handling
    
    Better handle wrap-around cases when reading the APIC CCR
    (current count register).  Also, if ICR is 0, CCR should also
    be 0... previously reading CCR before setting ICR would result
    in a large kinda-random number.
    
    Signed-off-by: Kevin Pedretti <[EMAIL PROTECTED]>
    Signed-off-by: Avi Kivity <[EMAIL PROTECTED]>
---
 drivers/kvm/lapic.c |   36 ++++++++++++++++++++++++++----------
 1 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c
index 443730e..238fcad 100644
--- a/drivers/kvm/lapic.c
+++ b/drivers/kvm/lapic.c
@@ -494,12 +494,19 @@ static void apic_send_ipi(struct kvm_lapic *apic)
 
 static u32 apic_get_tmcct(struct kvm_lapic *apic)
 {
-       u32 counter_passed;
-       ktime_t passed, now = apic->timer.dev.base->get_time();
-       u32 tmcct = apic_get_reg(apic, APIC_TMICT);
+       u64 counter_passed;
+       ktime_t passed, now;
+       u32 tmcct;
 
        ASSERT(apic != NULL);
 
+       now = apic->timer.dev.base->get_time();
+       tmcct = apic_get_reg(apic, APIC_TMICT);
+
+       /* if initial count is 0, current count should also be 0 */
+       if (tmcct == 0)
+               return 0;
+
        if (unlikely(ktime_to_ns(now) <=
                ktime_to_ns(apic->timer.last_update))) {
                /* Wrap around */
@@ -514,15 +521,24 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
 
        counter_passed = div64_64(ktime_to_ns(passed),
                                  (APIC_BUS_CYCLE_NS * 
apic->timer.divide_count));
-       tmcct -= counter_passed;
 
-       if (tmcct <= 0) {
-               if (unlikely(!apic_lvtt_period(apic)))
+       if (counter_passed > tmcct) {
+               if (unlikely(!apic_lvtt_period(apic))) {
+                       /* one-shot timers stick at 0 until reset */
                        tmcct = 0;
-               else
-                       do {
-                               tmcct += apic_get_reg(apic, APIC_TMICT);
-                       } while (tmcct <= 0);
+               } else {
+                       /*
+                        * periodic timers reset to APIC_TMICT when they
+                        * hit 0. The while loop simulates this happening N
+                        * times. (counter_passed %= tmcct) would also work,
+                        * but might be slower or not work on 32-bit??
+                        */
+                       while (counter_passed > tmcct)
+                               counter_passed -= tmcct;
+                       tmcct -= counter_passed;
+               }
+       } else {
+               tmcct -= counter_passed;
        }
 
        return tmcct;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to