aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/lapic.c
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2013-03-13 07:42:34 -0400
committerGleb Natapov <gleb@redhat.com>2013-03-13 10:08:10 -0400
commit66450a21f99636af4fafac2afd33f1a40631bc3a (patch)
tree81a71a5ad44edcb7317567b2a922e9a861bb2bb8 /arch/x86/kvm/lapic.c
parent5d218814328da91a27e982748443e7e375e11396 (diff)
KVM: x86: Rework INIT and SIPI handling
A VCPU sending INIT or SIPI to some other VCPU races for setting the remote VCPU's mp_state. When we were unlucky, KVM_MP_STATE_INIT_RECEIVED was overwritten by kvm_emulate_halt and, thus, got lost. This introduces APIC events for those two signals, keeping them in kvm_apic until kvm_apic_accept_events is run over the target vcpu context. kvm_apic_has_events reports to kvm_arch_vcpu_runnable if there are pending events, thus if vcpu blocking should end. The patch comes with the side effect of effectively obsoleting KVM_MP_STATE_SIPI_RECEIVED. We still accept it from user space, but immediately translate it to KVM_MP_STATE_INIT_RECEIVED + KVM_APIC_SIPI. The vcpu itself will no longer enter the KVM_MP_STATE_SIPI_RECEIVED state. That also means we no longer exit to user space after receiving a SIPI event. Furthermore, we already reset the VCPU on INIT, only fixing up the code segment later on when SIPI arrives. Moreover, we fix INIT handling for the BSP: it never enter wait-for-SIPI but directly starts over on INIT. Tested-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Gleb Natapov <gleb@redhat.com>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r--arch/x86/kvm/lapic.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 02b51dd4e4ad..a8e9369f41c5 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -731,7 +731,11 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
731 case APIC_DM_INIT: 731 case APIC_DM_INIT:
732 if (!trig_mode || level) { 732 if (!trig_mode || level) {
733 result = 1; 733 result = 1;
734 vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED; 734 /* assumes that there are only KVM_APIC_INIT/SIPI */
735 apic->pending_events = (1UL << KVM_APIC_INIT);
736 /* make sure pending_events is visible before sending
737 * the request */
738 smp_wmb();
735 kvm_make_request(KVM_REQ_EVENT, vcpu); 739 kvm_make_request(KVM_REQ_EVENT, vcpu);
736 kvm_vcpu_kick(vcpu); 740 kvm_vcpu_kick(vcpu);
737 } else { 741 } else {
@@ -743,13 +747,13 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
743 case APIC_DM_STARTUP: 747 case APIC_DM_STARTUP:
744 apic_debug("SIPI to vcpu %d vector 0x%02x\n", 748 apic_debug("SIPI to vcpu %d vector 0x%02x\n",
745 vcpu->vcpu_id, vector); 749 vcpu->vcpu_id, vector);
746 if (vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) { 750 result = 1;
747 result = 1; 751 apic->sipi_vector = vector;
748 vcpu->arch.sipi_vector = vector; 752 /* make sure sipi_vector is visible for the receiver */
749 vcpu->arch.mp_state = KVM_MP_STATE_SIPI_RECEIVED; 753 smp_wmb();
750 kvm_make_request(KVM_REQ_EVENT, vcpu); 754 set_bit(KVM_APIC_SIPI, &apic->pending_events);
751 kvm_vcpu_kick(vcpu); 755 kvm_make_request(KVM_REQ_EVENT, vcpu);
752 } 756 kvm_vcpu_kick(vcpu);
753 break; 757 break;
754 758
755 case APIC_DM_EXTINT: 759 case APIC_DM_EXTINT:
@@ -1860,6 +1864,34 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data)
1860 addr); 1864 addr);
1861} 1865}
1862 1866
1867void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
1868{
1869 struct kvm_lapic *apic = vcpu->arch.apic;
1870 unsigned int sipi_vector;
1871
1872 if (!kvm_vcpu_has_lapic(vcpu))
1873 return;
1874
1875 if (test_and_clear_bit(KVM_APIC_INIT, &apic->pending_events)) {
1876 kvm_lapic_reset(vcpu);
1877 kvm_vcpu_reset(vcpu);
1878 if (kvm_vcpu_is_bsp(apic->vcpu))
1879 vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
1880 else
1881 vcpu->arch.mp_state = KVM_MP_STATE_INIT_RECEIVED;
1882 }
1883 if (test_and_clear_bit(KVM_APIC_SIPI, &apic->pending_events) &&
1884 vcpu->arch.mp_state == KVM_MP_STATE_INIT_RECEIVED) {
1885 /* evaluate pending_events before reading the vector */
1886 smp_rmb();
1887 sipi_vector = apic->sipi_vector;
1888 pr_debug("vcpu %d received sipi with vector # %x\n",
1889 vcpu->vcpu_id, sipi_vector);
1890 kvm_vcpu_deliver_sipi_vector(vcpu, sipi_vector);
1891 vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
1892 }
1893}
1894
1863void kvm_lapic_init(void) 1895void kvm_lapic_init(void)
1864{ 1896{
1865 /* do not patch jump label more than once per second */ 1897 /* do not patch jump label more than once per second */