diff options
Diffstat (limited to 'virt/kvm/irq_comm.c')
-rw-r--r-- | virt/kvm/irq_comm.c | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index ddc17f0e2f35..001663ff401a 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c @@ -20,6 +20,7 @@ */ #include <linux/kvm_host.h> +#include <trace/events/kvm.h> #include <asm/msidef.h> #ifdef CONFIG_IA64 @@ -62,14 +63,14 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, int i, r = -1; struct kvm_vcpu *vcpu, *lowest = NULL; + WARN_ON(!mutex_is_locked(&kvm->irq_lock)); + if (irq->dest_mode == 0 && irq->dest_id == 0xff && kvm_is_dm_lowest_prio(irq)) printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); - for (i = 0; i < KVM_MAX_VCPUS; i++) { - vcpu = kvm->vcpus[i]; - - if (!vcpu || !kvm_apic_present(vcpu)) + kvm_for_each_vcpu(i, vcpu, kvm) { + if (!kvm_apic_present(vcpu)) continue; if (!kvm_apic_match_dest(vcpu, src, irq->shorthand, @@ -99,6 +100,8 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, { struct kvm_lapic_irq irq; + trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data); + irq.dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; irq.vector = (e->msi.data & @@ -113,7 +116,7 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, return kvm_irq_delivery_to_apic(kvm, NULL, &irq); } -/* This should be called with the kvm->lock mutex held +/* This should be called with the kvm->irq_lock mutex held * Return value: * < 0 Interrupt was ignored (masked or not delivered for other reasons) * = 0 Interrupt was coalesced (previous irq is still pending) @@ -125,6 +128,10 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) unsigned long *irq_state, sig_level; int ret = -1; + trace_kvm_set_irq(irq, level, irq_source_id); + + WARN_ON(!mutex_is_locked(&kvm->irq_lock)); + if (irq < KVM_IOAPIC_NUM_PINS) { irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; @@ -134,7 +141,9 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) else clear_bit(irq_source_id, irq_state); sig_level = !!(*irq_state); - } else /* Deal with MSI/MSI-X */ + } else if (!level) + return ret; + else /* Deal with MSI/MSI-X */ sig_level = 1; /* Not possible to detect if the guest uses the PIC or the @@ -159,6 +168,8 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) struct hlist_node *n; unsigned gsi = pin; + trace_kvm_ack_irq(irqchip, pin); + list_for_each_entry(e, &kvm->irq_routing, link) if (e->type == KVM_IRQ_ROUTING_IRQCHIP && e->irqchip.irqchip == irqchip && @@ -175,19 +186,26 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) void kvm_register_irq_ack_notifier(struct kvm *kvm, struct kvm_irq_ack_notifier *kian) { + mutex_lock(&kvm->irq_lock); hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list); + mutex_unlock(&kvm->irq_lock); } -void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian) +void kvm_unregister_irq_ack_notifier(struct kvm *kvm, + struct kvm_irq_ack_notifier *kian) { + mutex_lock(&kvm->irq_lock); hlist_del_init(&kian->link); + mutex_unlock(&kvm->irq_lock); } -/* The caller must hold kvm->lock mutex */ int kvm_request_irq_source_id(struct kvm *kvm) { unsigned long *bitmap = &kvm->arch.irq_sources_bitmap; - int irq_source_id = find_first_zero_bit(bitmap, + int irq_source_id; + + mutex_lock(&kvm->irq_lock); + irq_source_id = find_first_zero_bit(bitmap, sizeof(kvm->arch.irq_sources_bitmap)); if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { @@ -197,6 +215,7 @@ int kvm_request_irq_source_id(struct kvm *kvm) ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); set_bit(irq_source_id, bitmap); + mutex_unlock(&kvm->irq_lock); return irq_source_id; } @@ -207,6 +226,7 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); + mutex_lock(&kvm->irq_lock); if (irq_source_id < 0 || irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { printk(KERN_ERR "kvm: IRQ source ID out of range!\n"); @@ -215,19 +235,24 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) clear_bit(irq_source_id, &kvm->arch.irq_states[i]); clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap); + mutex_unlock(&kvm->irq_lock); } void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq, struct kvm_irq_mask_notifier *kimn) { + mutex_lock(&kvm->irq_lock); kimn->irq = irq; hlist_add_head(&kimn->link, &kvm->mask_notifier_list); + mutex_unlock(&kvm->irq_lock); } void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, struct kvm_irq_mask_notifier *kimn) { + mutex_lock(&kvm->irq_lock); hlist_del(&kimn->link); + mutex_unlock(&kvm->irq_lock); } void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask) @@ -235,6 +260,8 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask) struct kvm_irq_mask_notifier *kimn; struct hlist_node *n; + WARN_ON(!mutex_is_locked(&kvm->irq_lock)); + hlist_for_each_entry(kimn, n, &kvm->mask_notifier_list, link) if (kimn->irq == irq) kimn->func(kimn, mask); @@ -250,7 +277,9 @@ static void __kvm_free_irq_routing(struct list_head *irq_routing) void kvm_free_irq_routing(struct kvm *kvm) { + mutex_lock(&kvm->irq_lock); __kvm_free_irq_routing(&kvm->irq_routing); + mutex_unlock(&kvm->irq_lock); } static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, @@ -325,13 +354,13 @@ int kvm_set_irq_routing(struct kvm *kvm, e = NULL; } - mutex_lock(&kvm->lock); + mutex_lock(&kvm->irq_lock); list_splice(&kvm->irq_routing, &tmp); INIT_LIST_HEAD(&kvm->irq_routing); list_splice(&irq_list, &kvm->irq_routing); INIT_LIST_HEAD(&irq_list); list_splice(&tmp, &irq_list); - mutex_unlock(&kvm->lock); + mutex_unlock(&kvm->irq_lock); r = 0; |