KVM: avoid taking ioapic mutex for non-ioapic EOIs
[linux-2.6.git] / virt / kvm / ioapic.c
index f01392f..a2edfd1 100644 (file)
@@ -100,6 +100,19 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
        return injected;
 }
 
+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();
+}
+
 static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
 {
        unsigned index;
@@ -134,6 +147,7 @@ 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, index, mask_after);
@@ -241,6 +255,9 @@ 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;
        mutex_lock(&ioapic->lock);
        __kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
        mutex_unlock(&ioapic->lock);
@@ -352,6 +369,7 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
        ioapic->ioregsel = 0;
        ioapic->irr = 0;
        ioapic->id = 0;
+       update_handled_vectors(ioapic);
 }
 
 static const struct kvm_io_device_ops ioapic_mmio_ops = {
@@ -401,6 +419,7 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)
 
        mutex_lock(&ioapic->lock);
        memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
+       update_handled_vectors(ioapic);
        mutex_unlock(&ioapic->lock);
        return 0;
 }