diff options
author | He, Qing <qing.he@intel.com> | 2007-09-03 10:07:41 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:26 -0400 |
commit | c5ec153402b6d276fe20029da1059ba42a4b55e5 (patch) | |
tree | a323fd0466f606b66fc7239e78569863d62f6300 /drivers/kvm/lapic.c | |
parent | 932f72adbe76f098922c746737cb0bd75fc21e27 (diff) |
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, | |||
312 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | 312 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, |
313 | int vector, int level, int trig_mode) | 313 | int vector, int level, int trig_mode) |
314 | { | 314 | { |
315 | int result = 0; | 315 | int orig_irr, result = 0; |
316 | int orig_irr; | 316 | struct kvm_vcpu *vcpu = apic->vcpu; |
317 | 317 | ||
318 | switch (delivery_mode) { | 318 | switch (delivery_mode) { |
319 | case APIC_DM_FIXED: | 319 | case APIC_DM_FIXED: |
@@ -335,7 +335,13 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
335 | } else | 335 | } else |
336 | apic_clear_vector(vector, apic->regs + APIC_TMR); | 336 | apic_clear_vector(vector, apic->regs + APIC_TMR); |
337 | 337 | ||
338 | kvm_vcpu_kick(apic->vcpu); | 338 | if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) |
339 | kvm_vcpu_kick(vcpu); | ||
340 | else if (vcpu->mp_state == VCPU_MP_STATE_HALTED) { | ||
341 | vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; | ||
342 | if (waitqueue_active(&vcpu->wq)) | ||
343 | wake_up_interruptible(&vcpu->wq); | ||
344 | } | ||
339 | 345 | ||
340 | result = (orig_irr == 0); | 346 | result = (orig_irr == 0); |
341 | break; | 347 | break; |
@@ -352,11 +358,30 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
352 | break; | 358 | break; |
353 | 359 | ||
354 | case APIC_DM_INIT: | 360 | case APIC_DM_INIT: |
355 | printk(KERN_DEBUG "Ignoring guest INIT\n"); | 361 | if (level) { |
362 | if (vcpu->mp_state == VCPU_MP_STATE_RUNNABLE) | ||
363 | printk(KERN_DEBUG | ||
364 | "INIT on a runnable vcpu %d\n", | ||
365 | vcpu->vcpu_id); | ||
366 | vcpu->mp_state = VCPU_MP_STATE_INIT_RECEIVED; | ||
367 | kvm_vcpu_kick(vcpu); | ||
368 | } else { | ||
369 | printk(KERN_DEBUG | ||
370 | "Ignoring de-assert INIT to vcpu %d\n", | ||
371 | vcpu->vcpu_id); | ||
372 | } | ||
373 | |||
356 | break; | 374 | break; |
357 | 375 | ||
358 | case APIC_DM_STARTUP: | 376 | case APIC_DM_STARTUP: |
359 | printk(KERN_DEBUG "Ignoring guest STARTUP\n"); | 377 | printk(KERN_DEBUG "SIPI to vcpu %d vector 0x%02x\n", |
378 | vcpu->vcpu_id, vector); | ||
379 | if (vcpu->mp_state == VCPU_MP_STATE_INIT_RECEIVED) { | ||
380 | vcpu->sipi_vector = vector; | ||
381 | vcpu->mp_state = VCPU_MP_STATE_SIPI_RECEIVED; | ||
382 | if (waitqueue_active(&vcpu->wq)) | ||
383 | wake_up_interruptible(&vcpu->wq); | ||
384 | } | ||
360 | break; | 385 | break; |
361 | 386 | ||
362 | default: | 387 | default: |
@@ -792,7 +817,7 @@ u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu) | |||
792 | } | 817 | } |
793 | EXPORT_SYMBOL_GPL(kvm_lapic_get_base); | 818 | EXPORT_SYMBOL_GPL(kvm_lapic_get_base); |
794 | 819 | ||
795 | static void lapic_reset(struct kvm_vcpu *vcpu) | 820 | void kvm_lapic_reset(struct kvm_vcpu *vcpu) |
796 | { | 821 | { |
797 | struct kvm_lapic *apic; | 822 | struct kvm_lapic *apic; |
798 | int i; | 823 | int i; |
@@ -839,6 +864,7 @@ static void lapic_reset(struct kvm_vcpu *vcpu) | |||
839 | vcpu, kvm_apic_id(apic), | 864 | vcpu, kvm_apic_id(apic), |
840 | vcpu->apic_base, apic->base_address); | 865 | vcpu->apic_base, apic->base_address); |
841 | } | 866 | } |
867 | EXPORT_SYMBOL_GPL(kvm_lapic_reset); | ||
842 | 868 | ||
843 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu) | 869 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu) |
844 | { | 870 | { |
@@ -867,7 +893,10 @@ static int __apic_timer_fn(struct kvm_lapic *apic) | |||
867 | 893 | ||
868 | atomic_inc(&apic->timer.pending); | 894 | atomic_inc(&apic->timer.pending); |
869 | if (waitqueue_active(q)) | 895 | if (waitqueue_active(q)) |
896 | { | ||
897 | apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE; | ||
870 | wake_up_interruptible(q); | 898 | wake_up_interruptible(q); |
899 | } | ||
871 | if (apic_lvtt_period(apic)) { | 900 | if (apic_lvtt_period(apic)) { |
872 | result = 1; | 901 | result = 1; |
873 | apic->timer.dev.expires = ktime_add_ns( | 902 | apic->timer.dev.expires = ktime_add_ns( |
@@ -928,7 +957,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) | |||
928 | apic->base_address = APIC_DEFAULT_PHYS_BASE; | 957 | apic->base_address = APIC_DEFAULT_PHYS_BASE; |
929 | vcpu->apic_base = APIC_DEFAULT_PHYS_BASE; | 958 | vcpu->apic_base = APIC_DEFAULT_PHYS_BASE; |
930 | 959 | ||
931 | lapic_reset(vcpu); | 960 | kvm_lapic_reset(vcpu); |
932 | apic->dev.read = apic_mmio_read; | 961 | apic->dev.read = apic_mmio_read; |
933 | apic->dev.write = apic_mmio_write; | 962 | apic->dev.write = apic_mmio_write; |
934 | apic->dev.in_range = apic_mmio_range; | 963 | apic->dev.in_range = apic_mmio_range; |