KVM: avoid taking ioapic mutex for non-ioapic EOIs
When the guest acknowledges an interrupt, it sends an EOI message to the local apic, which broadcasts it to the ioapic. To handle the EOI, we need to take the ioapic mutex. On large guests, this causes a lot of contention on this mutex. Since large guests usually don't route interrupts via the ioapic (they use msi instead), this is completely unnecessary. Avoid taking the mutex by introducing a handled_vectors bitmap. Before taking the mutex, check if the ioapic was actually responsible for the acked vector. If not, we can return early. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
parent
f4c9e87c83
commit
46a929bc15
|
@ -100,6 +100,19 @@ static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
|
||||||
return injected;
|
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)
|
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
|
||||||
{
|
{
|
||||||
unsigned index;
|
unsigned index;
|
||||||
|
@ -134,6 +147,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
|
||||||
e->bits |= (u32) val;
|
e->bits |= (u32) val;
|
||||||
e->fields.remote_irr = 0;
|
e->fields.remote_irr = 0;
|
||||||
}
|
}
|
||||||
|
update_handled_vectors(ioapic);
|
||||||
mask_after = e->fields.mask;
|
mask_after = e->fields.mask;
|
||||||
if (mask_before != mask_after)
|
if (mask_before != mask_after)
|
||||||
kvm_fire_mask_notifiers(ioapic->kvm, index, 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;
|
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
|
||||||
|
|
||||||
|
smp_rmb();
|
||||||
|
if (!test_bit(vector, ioapic->handled_vectors))
|
||||||
|
return;
|
||||||
mutex_lock(&ioapic->lock);
|
mutex_lock(&ioapic->lock);
|
||||||
__kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
|
__kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
|
||||||
mutex_unlock(&ioapic->lock);
|
mutex_unlock(&ioapic->lock);
|
||||||
|
@ -352,6 +369,7 @@ void kvm_ioapic_reset(struct kvm_ioapic *ioapic)
|
||||||
ioapic->ioregsel = 0;
|
ioapic->ioregsel = 0;
|
||||||
ioapic->irr = 0;
|
ioapic->irr = 0;
|
||||||
ioapic->id = 0;
|
ioapic->id = 0;
|
||||||
|
update_handled_vectors(ioapic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct kvm_io_device_ops ioapic_mmio_ops = {
|
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);
|
mutex_lock(&ioapic->lock);
|
||||||
memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
|
memcpy(ioapic, state, sizeof(struct kvm_ioapic_state));
|
||||||
|
update_handled_vectors(ioapic);
|
||||||
mutex_unlock(&ioapic->lock);
|
mutex_unlock(&ioapic->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ struct kvm_ioapic {
|
||||||
struct kvm *kvm;
|
struct kvm *kvm;
|
||||||
void (*ack_notifier)(void *opaque, int irq);
|
void (*ack_notifier)(void *opaque, int irq);
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
DECLARE_BITMAP(handled_vectors, 256);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
Loading…
Reference in New Issue