]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/kvm/lapic.c
KVM: enable in-kernel APIC INIT/SIPI handling
[mirror_ubuntu-artful-kernel.git] / drivers / kvm / lapic.c
index ca1db3852ace0a4759de0a57a44a3badda4f2570..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:
@@ -792,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;
@@ -839,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)
 {
@@ -867,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(
@@ -928,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;