KVM: x86: store IOAPIC-handled vectors in each VCPU
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 29 Jul 2015 08:43:18 +0000 (10:43 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 1 Oct 2015 13:06:23 +0000 (15:06 +0200)
We can reuse the algorithm that computes the EOI exit bitmap to figure
out which vectors are handled by the IOAPIC.  The only difference
between the two is for edge-triggered interrupts other than IRQ8
that have no notifiers active; however, the IOAPIC does not have to
do anything special for these interrupts anyway.

This again limits the interactions between the IOAPIC and the LAPIC,
making it easier to move the former to userspace.

Inspired by a patch from Steve Rutherford.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/ioapic.c
arch/x86/kvm/ioapic.h
arch/x86/kvm/lapic.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c

index 2beee03820889b6c6b436e884a4e83e023d76f9a..33609c2c743b31c4c7736a1244c4d29e2198bfd8 100644 (file)
@@ -396,6 +396,7 @@ struct kvm_vcpu_arch {
        u64 efer;
        u64 apic_base;
        struct kvm_lapic *apic;    /* kernel irqchip context */
+       u64 eoi_exit_bitmap[4];
        unsigned long apic_attention;
        int32_t apic_arb_prio;
        int mp_state;
@@ -822,7 +823,7 @@ struct kvm_x86_ops {
        int (*vm_has_apicv)(struct kvm *kvm);
        void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
        void (*hwapic_isr_update)(struct kvm *kvm, int isr);
-       void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
+       void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu);
        void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set);
        void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa);
        void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
index eaf4ec38d980d11174fce4e8a3f31f97584bb7d4..2dcda0f188bae49080ba5d8992dc87135dcfb525 100644 (file)
@@ -233,19 +233,6 @@ static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr)
 }
 
 
-static void update_handled_vectors(struct kvm_ioapic *ioapic)
-{
-       DECLARE_BITMAP(handled_vectors, 256);
-       int i;
-
-       memset(handled_vectors, 0, sizeof(handled_vectors));
-       for (i = 0; i < IOAPIC_NUM_PINS; ++i)
-               __set_bit(ioapic->redirtbl[i].fields.vector, handled_vectors);
-       memcpy(ioapic->handled_vectors, handled_vectors,
-              sizeof(handled_vectors));
-       smp_wmb();
-}
-
 void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
 {
        struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
@@ -310,7 +297,6 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
                        e->bits |= (u32) val;
                        e->fields.remote_irr = 0;
                }
-               update_handled_vectors(ioapic);
                mask_after = e->fields.mask;
                if (mask_before != mask_after)
                        kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
@@ -594,7 +580,6 @@ static void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
        ioapic->id = 0;
        memset(ioapic->irq_eoi, 0x00, IOAPIC_NUM_PINS);
        rtc_irq_eoi_tracking_reset(ioapic);
-       update_handled_vectors(ioapic);
 }
 
 static const struct kvm_io_device_ops ioapic_mmio_ops = {
@@ -623,8 +608,10 @@ int kvm_ioapic_init(struct kvm *kvm)
        if (ret < 0) {
                kvm->arch.vioapic = NULL;
                kfree(ioapic);
+               return ret;
        }
 
+       kvm_vcpu_request_scan_ioapic(kvm);
        return ret;
 }
 
@@ -661,7 +648,6 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
        memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
        ioapic->irr = 0;
        ioapic->irr_delivered = 0;
-       update_handled_vectors(ioapic);
        kvm_vcpu_request_scan_ioapic(kvm);
        kvm_ioapic_inject_all(ioapic, state->irr);
        spin_unlock(&ioapic->lock);
index 3dbd0e2aac4ee89cd1ef5f362af58b2b3ec9f999..bf36d66a195195a0d969f832b0c63029defbc83f 100644 (file)
@@ -73,7 +73,6 @@ struct kvm_ioapic {
        struct kvm *kvm;
        void (*ack_notifier)(void *opaque, int irq);
        spinlock_t lock;
-       DECLARE_BITMAP(handled_vectors, 256);
        struct rtc_status rtc_status;
        struct delayed_work eoi_inject;
        u32 irq_eoi[IOAPIC_NUM_PINS];
@@ -98,13 +97,6 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
        return kvm->arch.vioapic;
 }
 
-static inline bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector)
-{
-       struct kvm_ioapic *ioapic = kvm->arch.vioapic;
-       smp_rmb();
-       return test_bit(vector, ioapic->handled_vectors);
-}
-
 void kvm_rtc_eoi_tracking_restore_one(struct kvm_vcpu *vcpu);
 bool kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                int short_hand, unsigned int dest, int dest_mode);
index 5693dd9fc163b186717bb59e48c3a1b23b700cc4..4c30fb0a48a106bc1610181af5e7861e9ac7aa9e 100644 (file)
@@ -869,14 +869,20 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
        return vcpu1->arch.apic_arb_prio - vcpu2->arch.apic_arb_prio;
 }
 
+static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector)
+{
+       return test_bit(vector, (ulong *)apic->vcpu->arch.eoi_exit_bitmap);
+}
+
 static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
 {
-       if (kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
+       if (kvm_ioapic_handles_vector(apic, vector)) {
                int trigger_mode;
                if (apic_test_vector(vector, apic->regs + APIC_TMR))
                        trigger_mode = IOAPIC_LEVEL_TRIG;
                else
                        trigger_mode = IOAPIC_EDGE_TRIG;
+
                kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode);
        }
 }
@@ -1923,7 +1929,7 @@ static void apic_sync_pv_eoi_to_guest(struct kvm_vcpu *vcpu,
            /* Cache not set: could be safe but we don't bother. */
            apic->highest_isr_cache == -1 ||
            /* Need EOI to update ioapic. */
-           kvm_ioapic_handles_vector(vcpu->kvm, apic->highest_isr_cache)) {
+           kvm_ioapic_handles_vector(apic, apic->highest_isr_cache)) {
                /*
                 * PV EOI was disabled by apic_sync_pv_eoi_from_guest
                 * so we need not do anything here.
index 2f9ed1ff063260ed33bf845e1e523df0ad2bd58e..09582081276e3278b7f659ffe09be80c67c8ed8f 100644 (file)
@@ -3664,7 +3664,7 @@ static int svm_vm_has_apicv(struct kvm *kvm)
        return 0;
 }
 
-static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu)
 {
        return;
 }
index 06ef4908ba61d2e25ead615953a2f42c923a9219..9381b1d34313232c880ba1b4090f082e69a692f8 100644 (file)
@@ -8043,8 +8043,9 @@ static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
        }
 }
 
-static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu)
 {
+       u64 *eoi_exit_bitmap = vcpu->arch.eoi_exit_bitmap;
        if (!vmx_vm_has_apicv(vcpu->kvm))
                return;
 
index c1ed74ebc50287435d65ba5db1517cc4403b9653..c4adb8847b23515f00a939e9803c7a66ec76257b 100644 (file)
@@ -6143,15 +6143,13 @@ static void process_smi(struct kvm_vcpu *vcpu)
 
 static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
 {
-       u64 eoi_exit_bitmap[4];
-
        if (!kvm_apic_hw_enabled(vcpu->arch.apic))
                return;
 
-       memset(eoi_exit_bitmap, 0, 32);
+       memset(vcpu->arch.eoi_exit_bitmap, 0, 256 / 8);
 
-       kvm_ioapic_scan_entry(vcpu, eoi_exit_bitmap);
-       kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
+       kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmap);
+       kvm_x86_ops->load_eoi_exitmap(vcpu);
 }
 
 static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu)