diff options
author | He, Qing <qing.he@intel.com> | 2007-09-03 16:07:41 +0200 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 10:18:26 +0200 |
commit | c5ec153402b6d276fe20029da1059ba42a4b55e5 (patch) | |
tree | a323fd0466f606b66fc7239e78569863d62f6300 /drivers/kvm/lapic.c | |
parent | KVM: round robin for APIC lowest priority delivery mode (diff) | |
download | linux-c5ec153402b6d276fe20029da1059ba42a4b55e5.tar.xz linux-c5ec153402b6d276fe20029da1059ba42a4b55e5.zip |
KVM: enable in-kernel APIC INIT/SIPI handling
This patch enables INIT/SIPI handling using in-kernel APIC by
introducing a ->mp_state field to emulate the SMP state transition.
[avi: remove smp_processor_id() warning]
Signed-off-by: Qing He <qing.he@intel.com>
Signed-off-by: Xin Li <xin.b.li@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/lapic.c')
-rw-r--r-- | drivers/kvm/lapic.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c index ca1db3852ace..a190587cf6a5 100644 --- a/drivers/kvm/lapic.c +++ b/drivers/kvm/lapic.c @@ -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; |