]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm: remove an atomic on EOI
authorMichael S. Tsirkin <mst@redhat.com>
Wed, 11 Apr 2012 11:44:24 +0000 (14:44 +0300)
committerMichael S. Tsirkin <mst@redhat.com>
Wed, 18 Apr 2012 20:00:03 +0000 (23:00 +0300)
TMR is set with IRR but does not need to be
cleared on EOI. So we can save an atomic
operation on EOI by checking whether ioapic
needs a specific vector first.

For consistency, don't clear TMR for handled
vectors either: the spec doesn't say that
it needs to be cleared on EOI.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
arch/x86/kvm/lapic.c
virt/kvm/ioapic.c
virt/kvm/ioapic.h

index 858432287ab626dee9ce4568404fdf4f968a89a2..992b4eaae684df0c8ed640946fdcd6119486f6d2 100644 (file)
@@ -92,6 +92,11 @@ static inline int apic_test_and_clear_vector(int vec, void *bitmap)
        return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
 }
 
+static inline int apic_test_vector(int vec, void *bitmap)
+{
+       return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
+}
+
 static inline void apic_set_vector(int vec, void *bitmap)
 {
        set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -480,7 +485,6 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
 static void apic_set_eoi(struct kvm_lapic *apic)
 {
        int vector = apic_find_highest_isr(apic);
-       int trigger_mode;
        /*
         * Not every write EOI will has corresponding ISR,
         * one example is when Kernel check timer on setup_IO_APIC
@@ -491,12 +495,15 @@ static void apic_set_eoi(struct kvm_lapic *apic)
        apic_clear_vector(vector, apic->regs + APIC_ISR);
        apic_update_ppr(apic);
 
-       if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
-               trigger_mode = IOAPIC_LEVEL_TRIG;
-       else
-               trigger_mode = IOAPIC_EDGE_TRIG;
-       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
+       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
+           kvm_ioapic_handles_vector(apic->vcpu->kvm, 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->kvm, vector, trigger_mode);
+       }
        kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
 }
 
index dcaf272c26c0e232d01b265e652488642e7cc496..26fd54dc459ec8900d83da38c9132878ee60780d 100644 (file)
@@ -254,13 +254,17 @@ static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
        }
 }
 
+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_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
 {
        struct kvm_ioapic *ioapic = kvm->arch.vioapic;
 
-       smp_rmb();
-       if (!test_bit(vector, ioapic->handled_vectors))
-               return;
        spin_lock(&ioapic->lock);
        __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
        spin_unlock(&ioapic->lock);
index 0b190c34ccc31bd398d4549996c57c3203952a82..32872a09b63f3b1d8147f2e8595ed1f45ea9db65 100644 (file)
@@ -71,6 +71,7 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
                int short_hand, int dest, int dest_mode);
 int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
 void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
+bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector);
 int kvm_ioapic_init(struct kvm *kvm);
 void kvm_ioapic_destroy(struct kvm *kvm);
 int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);