]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/kvm/lapic.c
KVM: Portability: Introduce kvm_vcpu_arch
[linux-2.6-omap-h63xx.git] / drivers / kvm / lapic.c
index a190587cf6a52d5806ec48c54e44cfc5c7cd18f4..5c9f46784c263db0e808af65be22a54bdf8e48bc 100644 (file)
@@ -18,6 +18,8 @@
  */
 
 #include "kvm.h"
+#include "x86.h"
+
 #include <linux/kvm.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
@@ -56,6 +58,7 @@
 
 #define VEC_POS(v) ((v) & (32 - 1))
 #define REG_POS(v) (((v) >> 5) << 4)
+
 static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
 {
        return *((u32 *) (apic->regs + reg_off));
@@ -88,7 +91,7 @@ static inline void apic_clear_vector(int vec, void *bitmap)
 
 static inline int apic_hw_enabled(struct kvm_lapic *apic)
 {
-       return (apic)->vcpu->apic_base & MSR_IA32_APICBASE_ENABLE;
+       return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
 }
 
 static inline int  apic_sw_enabled(struct kvm_lapic *apic)
@@ -172,7 +175,7 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
 
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
        int highest_irr;
 
        if (!apic)
@@ -183,8 +186,10 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr);
 
-int kvm_apic_set_irq(struct kvm_lapic *apic, u8 vec, u8 trig)
+int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
 {
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
        if (!apic_test_and_set_irr(vec, apic)) {
                /* a new pending irq is set in IRR */
                if (trig)
@@ -268,7 +273,7 @@ static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                           int short_hand, int dest, int dest_mode)
 {
        int result = 0;
-       struct kvm_lapic *target = vcpu->apic;
+       struct kvm_lapic *target = vcpu->arch.apic;
 
        apic_debug("target %p, source %p, dest 0x%x, "
                   "dest_mode 0x%x, short_hand 0x%x",
@@ -335,10 +340,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                } else
                        apic_clear_vector(vector, apic->regs + APIC_TMR);
 
-               if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+               if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE)
                        kvm_vcpu_kick(vcpu);
-               else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) {
-                       vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+               else if (vcpu->arch.mp_state == VCPU_MP_STATE_HALTED) {
+                       vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE;
                        if (waitqueue_active(&vcpu->wq))
                                wake_up_interruptible(&vcpu->wq);
                }
@@ -359,11 +364,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
 
        case APIC_DM_INIT:
                if (level) {
-                       if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE)
+                       if (vcpu->arch.mp_state == VCPU_MP_STATE_RUNNABLE)
                                printk(KERN_DEBUG
                                       "INIT on a runnable vcpu %d\n",
                                       vcpu->vcpu_id);
-                       vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED;
+                       vcpu->arch.mp_state = VCPU_MP_STATE_INIT_RECEIVED;
                        kvm_vcpu_kick(vcpu);
                } else {
                        printk(KERN_DEBUG
@@ -376,9 +381,9 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
        case APIC_DM_STARTUP:
                printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n",
                       vcpu->vcpu_id, vector);
-               if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
-                       vcpu->sipi_vector = vector;
-                       vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
+               if (vcpu->arch.mp_state == VCPU_MP_STATE_INIT_RECEIVED) {
+                       vcpu->arch.sipi_vector = vector;
+                       vcpu->arch.mp_state = VCPU_MP_STATE_SIPI_RECEIVED;
                        if (waitqueue_active(&vcpu->wq))
                                wake_up_interruptible(&vcpu->wq);
                }
@@ -392,13 +397,12 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
        return result;
 }
 
-struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
+static struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
                                       unsigned long bitmap)
 {
-       int vcpu_id;
        int last;
        int next;
-       struct kvm_lapic *apic;
+       struct kvm_lapic *apic = NULL;
 
        last = kvm->round_robin_prev_vcpu;
        next = last;
@@ -408,25 +412,30 @@ struct kvm_lapic *kvm_apic_round_robin(struct kvm *kvm, u8 vector,
                        next = 0;
                if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
                        continue;
-               apic = kvm->vcpus[next]->apic;
+               apic = kvm->vcpus[next]->arch.apic;
                if (apic && apic_enabled(apic))
                        break;
                apic = NULL;
        } while (next != last);
        kvm->round_robin_prev_vcpu = next;
 
-       if (!apic) {
-               vcpu_id = ffs(bitmap) - 1;
-               if (vcpu_id < 0) {
-                       vcpu_id = 0;
-                       printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
-               }
-               apic = kvm->vcpus[vcpu_id]->apic;
-       }
+       if (!apic)
+               printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
 
        return apic;
 }
 
+struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
+               unsigned long bitmap)
+{
+       struct kvm_lapic *apic;
+
+       apic = kvm_apic_round_robin(kvm, vector, bitmap);
+       if (apic)
+               return apic->vcpu;
+       return NULL;
+}
+
 static void apic_set_eoi(struct kvm_lapic *apic)
 {
        int vector = apic_find_highest_isr(apic);
@@ -458,7 +467,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
        unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
        unsigned int vector = icr_low & APIC_VECTOR_MASK;
 
-       struct kvm_lapic *target;
+       struct kvm_vcpu *target;
        struct kvm_vcpu *vcpu;
        unsigned long lpr_map = 0;
        int i;
@@ -474,32 +483,39 @@ static void apic_send_ipi(struct kvm_lapic *apic)
                if (!vcpu)
                        continue;
 
-               if (vcpu->apic &&
+               if (vcpu->arch.apic &&
                    apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) {
                        if (delivery_mode == APIC_DM_LOWEST)
                                set_bit(vcpu->vcpu_id, &lpr_map);
                        else
-                               __apic_accept_irq(vcpu->apic, delivery_mode,
+                               __apic_accept_irq(vcpu->arch.apic, delivery_mode,
                                                  vector, level, trig_mode);
                }
        }
 
        if (delivery_mode == APIC_DM_LOWEST) {
-               target = kvm_apic_round_robin(vcpu->kvm, vector, lpr_map);
+               target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
                if (target != NULL)
-                       __apic_accept_irq(target, delivery_mode,
+                       __apic_accept_irq(target->arch.apic, delivery_mode,
                                          vector, level, trig_mode);
        }
 }
 
 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 +530,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;
@@ -746,19 +771,17 @@ static int apic_mmio_range(struct kvm_io_device *this, gpa_t addr)
        return ret;
 }
 
-void kvm_free_apic(struct kvm_lapic *apic)
+void kvm_free_lapic(struct kvm_vcpu *vcpu)
 {
-       if (!apic)
+       if (!vcpu->arch.apic)
                return;
 
-       hrtimer_cancel(&apic->timer.dev);
+       hrtimer_cancel(&vcpu->arch.apic->timer.dev);
 
-       if (apic->regs_page) {
-               __free_page(apic->regs_page);
-               apic->regs_page = 0;
-       }
+       if (vcpu->arch.apic->regs_page)
+               __free_page(vcpu->arch.apic->regs_page);
 
-       kfree(apic);
+       kfree(vcpu->arch.apic);
 }
 
 /*
@@ -769,7 +792,7 @@ void kvm_free_apic(struct kvm_lapic *apic)
 
 void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
-       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        if (!apic)
                return;
@@ -778,7 +801,7 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
        u64 tpr;
 
        if (!apic)
@@ -791,29 +814,29 @@ EXPORT_SYMBOL_GPL(kvm_lapic_get_cr8);
 
 void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
 {
-       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        if (!apic) {
                value |= MSR_IA32_APICBASE_BSP;
-               vcpu->apic_base = value;
+               vcpu->arch.apic_base = value;
                return;
        }
        if (apic->vcpu->vcpu_id)
                value &= ~MSR_IA32_APICBASE_BSP;
 
-       vcpu->apic_base = value;
-       apic->base_address = apic->vcpu->apic_base &
+       vcpu->arch.apic_base = value;
+       apic->base_address = apic->vcpu->arch.apic_base &
                             MSR_IA32_APICBASE_BASE;
 
        /* with FSB delivery interrupt, we can restart APIC functionality */
        apic_debug("apic base msr is 0x%016" PRIx64 ", and base address is "
-                  "0x%lx.\n", apic->apic_base, apic->base_address);
+                  "0x%lx.\n", apic->vcpu->arch.apic_base, apic->base_address);
 
 }
 
 u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
 {
-       return vcpu->apic_base;
+       return vcpu->arch.apic_base;
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
 
@@ -825,7 +848,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
        apic_debug("%s\n", __FUNCTION__);
 
        ASSERT(vcpu);
-       apic = vcpu->apic;
+       apic = vcpu->arch.apic;
        ASSERT(apic != NULL);
 
        /* Stop the timer in case it's a reset to an active apic */
@@ -853,22 +876,22 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
                apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
        }
-       apic->timer.divide_count = 0;
+       update_divide_count(apic);
        atomic_set(&apic->timer.pending, 0);
        if (vcpu->vcpu_id == 0)
-               vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
+               vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
        apic_update_ppr(apic);
 
        apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr="
                   "0x%016" PRIx64 ", base_address=0x%0lx.\n", __FUNCTION__,
                   vcpu, kvm_apic_id(apic),
-                  vcpu->apic_base, apic->base_address);
+                  vcpu->arch.apic_base, apic->base_address);
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_reset);
 
 int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
        int ret = 0;
 
        if (!apic)
@@ -892,9 +915,8 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
        wait_queue_head_t *q = &apic->vcpu->wq;
 
        atomic_inc(&apic->timer.pending);
-       if (waitqueue_active(q))
-       {
-               apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
+       if (waitqueue_active(q)) {
+               apic->vcpu->arch.mp_state = VCPU_MP_STATE_RUNNABLE;
                wake_up_interruptible(q);
        }
        if (apic_lvtt_period(apic)) {
@@ -940,13 +962,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
        if (!apic)
                goto nomem;
 
-       vcpu->apic = apic;
+       vcpu->arch.apic = apic;
 
        apic->regs_page = alloc_page(GFP_KERNEL);
        if (apic->regs_page == NULL) {
                printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
                       vcpu->vcpu_id);
-               goto nomem;
+               goto nomem_free_apic;
        }
        apic->regs = page_address(apic->regs_page);
        memset(apic->regs, 0, PAGE_SIZE);
@@ -955,7 +977,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
        hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        apic->timer.dev.function = apic_timer_fn;
        apic->base_address = APIC_DEFAULT_PHYS_BASE;
-       vcpu->apic_base = APIC_DEFAULT_PHYS_BASE;
+       vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE;
 
        kvm_lapic_reset(vcpu);
        apic->dev.read = apic_mmio_read;
@@ -964,15 +986,16 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
        apic->dev.private = apic;
 
        return 0;
+nomem_free_apic:
+       kfree(apic);
 nomem:
-       kvm_free_apic(apic);
        return -ENOMEM;
 }
 EXPORT_SYMBOL_GPL(kvm_create_lapic);
 
 int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
        int highest_irr;
 
        if (!apic || !apic_enabled(apic))
@@ -988,11 +1011,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
 
 int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
 {
-       u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
+       u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
        int r = 0;
 
        if (vcpu->vcpu_id == 0) {
-               if (!apic_hw_enabled(vcpu->apic))
+               if (!apic_hw_enabled(vcpu->arch.apic))
                        r = 1;
                if ((lvt0 & APIC_LVT_MASKED) == 0 &&
                    GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
@@ -1003,7 +1026,7 @@ int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
 
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        if (apic && apic_lvt_enabled(apic, APIC_LVTT) &&
                atomic_read(&apic->timer.pending) > 0) {
@@ -1014,7 +1037,7 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
 
 void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
 {
-       struct kvm_lapic *apic = vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
                apic->timer.last_update = ktime_add_ns(
@@ -1025,7 +1048,7 @@ void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
 int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
 {
        int vector = kvm_apic_has_interrupt(vcpu);
-       struct kvm_lapic *apic = vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
        if (vector == -1)
                return -1;
@@ -1038,9 +1061,9 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
 
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
-       apic->base_address = vcpu->apic_base &
+       apic->base_address = vcpu->arch.apic_base &
                             MSR_IA32_APICBASE_BASE;
        apic_set_reg(apic, APIC_LVR, APIC_VERSION);
        apic_update_ppr(apic);
@@ -1051,7 +1074,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
 
 void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
        struct hrtimer *timer;
 
        if (!apic)