]> err.no Git - linux-2.6/blobdiff - drivers/kvm/lapic.c
sysctl: for irda update sysctl_checks list of binary paths
[linux-2.6] / drivers / kvm / lapic.c
index 2706ec36c2586e24b32a2d95f2b64b0d9269904f..a190587cf6a52d5806ec48c54e44cfc5c7cd18f4 100644 (file)
@@ -312,8 +312,8 @@ static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
 static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                             int vector, int level, int trig_mode)
 {
-       int result = 0;
-       int orig_irr;
+       int orig_irr, result = 0;
+       struct kvm_vcpu *vcpu = apic->vcpu;
 
        switch (delivery_mode) {
        case APIC_DM_FIXED:
@@ -335,7 +335,13 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                } else
                        apic_clear_vector(vector, apic->regs + APIC_TMR);
 
-               kvm_vcpu_kick(apic->vcpu);
+               if (vcpu->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;
+                       if (waitqueue_active(&vcpu->wq))
+                               wake_up_interruptible(&vcpu->wq);
+               }
 
                result = (orig_irr == 0);
                break;
@@ -352,11 +358,30 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                break;
 
        case APIC_DM_INIT:
-               printk(KERN_DEBUG "Ignoring guest INIT\n");
+               if (level) {
+                       if (vcpu->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;
+                       kvm_vcpu_kick(vcpu);
+               } else {
+                       printk(KERN_DEBUG
+                              "Ignoring de-assert INIT to vcpu %d\n",
+                              vcpu->vcpu_id);
+               }
+
                break;
 
        case APIC_DM_STARTUP:
-               printk(KERN_DEBUG "Ignoring guest STARTUP\n");
+               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 (waitqueue_active(&vcpu->wq))
+                               wake_up_interruptible(&vcpu->wq);
+               }
                break;
 
        default:
@@ -371,12 +396,35 @@ 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;
+
+       last = kvm->round_robin_prev_vcpu;
+       next = last;
+
+       do {
+               if (++next == KVM_MAX_VCPUS)
+                       next = 0;
+               if (kvm->vcpus[next] == NULL || !test_bit(next, &bitmap))
+                       continue;
+               apic = kvm->vcpus[next]->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;
+       }
 
-       /* TODO for real round robin */
-       vcpu_id = fls(bitmap) - 1;
-       if (vcpu_id < 0)
-               printk(KERN_DEBUG "vcpu not ready for apic_round_robin\n");
-       return kvm->vcpus[vcpu_id]->apic;
+       return apic;
 }
 
 static void apic_set_eoi(struct kvm_lapic *apic)
@@ -769,7 +817,7 @@ u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_get_base);
 
-static void lapic_reset(struct kvm_vcpu *vcpu)
+void kvm_lapic_reset(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic;
        int i;
@@ -788,6 +836,8 @@ static void lapic_reset(struct kvm_vcpu *vcpu)
 
        for (i = 0; i < APIC_LVT_NUM; i++)
                apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
+       apic_set_reg(apic, APIC_LVT0,
+                    SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
 
        apic_set_reg(apic, APIC_DFR, 0xffffffffU);
        apic_set_reg(apic, APIC_SPIV, 0xff);
@@ -814,6 +864,7 @@ static void lapic_reset(struct kvm_vcpu *vcpu)
                   vcpu, kvm_apic_id(apic),
                   vcpu->apic_base, apic->base_address);
 }
+EXPORT_SYMBOL_GPL(kvm_lapic_reset);
 
 int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
 {
@@ -842,7 +893,10 @@ static int __apic_timer_fn(struct kvm_lapic *apic)
 
        atomic_inc(&apic->timer.pending);
        if (waitqueue_active(q))
+       {
+               apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
                wake_up_interruptible(q);
+       }
        if (apic_lvtt_period(apic)) {
                result = 1;
                apic->timer.dev.expires = ktime_add_ns(
@@ -903,7 +957,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
        apic->base_address = APIC_DEFAULT_PHYS_BASE;
        vcpu->apic_base = APIC_DEFAULT_PHYS_BASE;
 
-       lapic_reset(vcpu);
+       kvm_lapic_reset(vcpu);
        apic->dev.read = apic_mmio_read;
        apic->dev.write = apic_mmio_write;
        apic->dev.in_range = apic_mmio_range;
@@ -932,6 +986,21 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
        return highest_irr;
 }
 
+int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
+{
+       u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
+       int r = 0;
+
+       if (vcpu->vcpu_id == 0) {
+               if (!apic_hw_enabled(vcpu->apic))
+                       r = 1;
+               if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+                   GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+                       r = 1;
+       }
+       return r;
+}
+
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->apic;