/* * irq_comm.c: Common API for in kernel interrupt controller * Copyright (c) 2007, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. * Authors: * Yaozu (Eddie) Dong <Eddie.dong@intel.com> * */ #include <linux/kvm_host.h> #include <asm/msidef.h> #include "irq.h" #include "ioapic.h" static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int level) { #ifdef CONFIG_X86 return kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level); #else return -1; #endif } static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int level) { return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); } static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm, int level) { int vcpu_id, r = -1; struct kvm_vcpu *vcpu; struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; int vector = (e->msi.data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, (unsigned long *)&e->msi.address_lo); int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, (unsigned long *)&e->msi.data); int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT, (unsigned long *)&e->msi.data); u32 deliver_bitmask; BUG_ON(!ioapic); deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, dest_id, dest_mode); /* IOAPIC delivery mode value is the same as MSI here */ switch (delivery_mode) { case IOAPIC_LOWEST_PRIORITY: vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, deliver_bitmask); if (vcpu != NULL) r = kvm_apic_set_irq(vcpu, vector, trig_mode); else printk(KERN_INFO "kvm: null lowest priority vcpu!\n"); break; case IOAPIC_FIXED: for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { if (!(deliver_bitmask & (1 << vcpu_id))) continue; deliver_bitmask &= ~(1 << vcpu_id); vcpu = ioapic->kvm->vcpus[vcpu_id]; if (vcpu) { if (r < 0) r = 0; r += kvm_apic_set_irq(vcpu, vector, trig_mode); } } break; default: break; } return r; } /* This should be called with the kvm->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) * > 0 Number of CPUs interrupt was delivered to */ int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) { struct kvm_kernel_irq_routing_entry *e; unsigned long *irq_state, sig_level; int ret = -1; if (irq < KVM_IOAPIC_NUM_PINS) { irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; /* Logical OR for level trig interrupt */ if (level) set_bit(irq_source_id, irq_state); else clear_bit(irq_source_id, irq_state); sig_level = !!(*irq_state); } else /* Deal with MSI/MSI-X */ sig_level = 1; /* Not possible to detect if the guest uses the PIC or the * IOAPIC. So set the bit in both. The guest will ignore * writes to the unused one. */ list_for_each_entry(e, &kvm->irq_routing, link) if (e->gsi == irq) { int r = e->set(e, kvm, sig_level); if (r < 0) continue; ret = r + ((ret < 0) ? 0 : ret); } return ret; } void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) { struct kvm_kernel_irq_routing_entry *e; struct kvm_irq_ack_notifier *kian; struct hlist_node *n; unsigned gsi = pin; list_for_each_entry(e, &kvm->irq_routing, link) if (e->irqchip.irqchip == irqchip && e->irqchip.pin == pin) { gsi = e->gsi; break; } hlist_for_each_entry(kian, n, &kvm->arch.irq_ack_notifier_list, link) if (kian->gsi == gsi) kian->irq_acked(kian); } void kvm_register_irq_ack_notifier(struct kvm *kvm, struct kvm_irq_ack_notifier *kian) { hlist_add_head(&kian->link, &kvm->arch.irq_ack_notifier_list); } void kvm_unregister_irq_ack_notifier(struct kvm_irq_ack_notifier *kian) { hlist_del_init(&kian->link); } /* 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, sizeof(kvm->arch.irq_sources_bitmap)); if (irq_source_id >= sizeof(kvm->arch.irq_sources_bitmap)) { printk(KERN_WARNING "kvm: exhaust allocatable IRQ sources!\n"); return -EFAULT; } ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); set_bit(irq_source_id, bitmap); return irq_source_id; } void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id) { int i; ASSERT(irq_source_id != KVM_USERSPACE_IRQ_SOURCE_ID); 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"); return; } 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); } void kvm_register_irq_mask_notifier(struct kvm *kvm, int irq, struct kvm_irq_mask_notifier *kimn) { kimn->irq = irq; hlist_add_head(&kimn->link, &kvm->mask_notifier_list); } void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, struct kvm_irq_mask_notifier *kimn) { hlist_del(&kimn->link); } void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask) { struct kvm_irq_mask_notifier *kimn; struct hlist_node *n; hlist_for_each_entry(kimn, n, &kvm->mask_notifier_list, link) if (kimn->irq == irq) kimn->func(kimn, mask); } static void __kvm_free_irq_routing(struct list_head *irq_routing) { struct kvm_kernel_irq_routing_entry *e, *n; list_for_each_entry_safe(e, n, irq_routing, link) kfree(e); } void kvm_free_irq_routing(struct kvm *kvm) { __kvm_free_irq_routing(&kvm->irq_routing); } static int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e, const struct kvm_irq_routing_entry *ue) { int r = -EINVAL; int delta; e->gsi = ue->gsi; switch (ue->type) { case KVM_IRQ_ROUTING_IRQCHIP: delta = 0; switch (ue->u.irqchip.irqchip) { case KVM_IRQCHIP_PIC_MASTER: e->set = kvm_set_pic_irq; break; case KVM_IRQCHIP_PIC_SLAVE: e->set = kvm_set_pic_irq; delta = 8; break; case KVM_IRQCHIP_IOAPIC: e->set = kvm_set_ioapic_irq; break; default: goto out; } e->irqchip.irqchip = ue->u.irqchip.irqchip; e->irqchip.pin = ue->u.irqchip.pin + delta; break; case KVM_IRQ_ROUTING_MSI: e->set = kvm_set_msi; e->msi.address_lo = ue->u.msi.address_lo; e->msi.address_hi = ue->u.msi.address_hi; e->msi.data = ue->u.msi.data; break; default: goto out; } r = 0; out: return r; } int kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *ue, unsigned nr, unsigned flags) { struct list_head irq_list = LIST_HEAD_INIT(irq_list); struct list_head tmp = LIST_HEAD_INIT(tmp); struct kvm_kernel_irq_routing_entry *e = NULL; unsigned i; int r; for (i = 0; i < nr; ++i) { r = -EINVAL; if (ue->gsi >= KVM_MAX_IRQ_ROUTES) goto out; if (ue->flags) goto out; r = -ENOMEM; e = kzalloc(sizeof(*e), GFP_KERNEL); if (!e) goto out; r = setup_routing_entry(e, ue); if (r) goto out; ++ue; list_add(&e->link, &irq_list); e = NULL; } mutex_lock(&kvm->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); r = 0; out: kfree(e); __kvm_free_irq_routing(&irq_list); return r; } #define IOAPIC_ROUTING_ENTRY(irq) \ { .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP, \ .u.irqchip.irqchip = KVM_IRQCHIP_IOAPIC, .u.irqchip.pin = (irq) } #define ROUTING_ENTRY1(irq) IOAPIC_ROUTING_ENTRY(irq) #ifdef CONFIG_X86 # define PIC_ROUTING_ENTRY(irq) \ { .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP, \ .u.irqchip.irqchip = SELECT_PIC(irq), .u.irqchip.pin = (irq) % 8 } # define ROUTING_ENTRY2(irq) \ IOAPIC_ROUTING_ENTRY(irq), PIC_ROUTING_ENTRY(irq) #else # define ROUTING_ENTRY2(irq) \ IOAPIC_ROUTING_ENTRY(irq) #endif static const struct kvm_irq_routing_entry default_routing[] = { ROUTING_ENTRY2(0), ROUTING_ENTRY2(1), ROUTING_ENTRY2(2), ROUTING_ENTRY2(3), ROUTING_ENTRY2(4), ROUTING_ENTRY2(5), ROUTING_ENTRY2(6), ROUTING_ENTRY2(7), ROUTING_ENTRY2(8), ROUTING_ENTRY2(9), ROUTING_ENTRY2(10), ROUTING_ENTRY2(11), ROUTING_ENTRY2(12), ROUTING_ENTRY2(13), ROUTING_ENTRY2(14), ROUTING_ENTRY2(15), ROUTING_ENTRY1(16), ROUTING_ENTRY1(17), ROUTING_ENTRY1(18), ROUTING_ENTRY1(19), ROUTING_ENTRY1(20), ROUTING_ENTRY1(21), ROUTING_ENTRY1(22), ROUTING_ENTRY1(23), #ifdef CONFIG_IA64 ROUTING_ENTRY1(24), ROUTING_ENTRY1(25), ROUTING_ENTRY1(26), ROUTING_ENTRY1(27), ROUTING_ENTRY1(28), ROUTING_ENTRY1(29), ROUTING_ENTRY1(30), ROUTING_ENTRY1(31), ROUTING_ENTRY1(32), ROUTING_ENTRY1(33), ROUTING_ENTRY1(34), ROUTING_ENTRY1(35), ROUTING_ENTRY1(36), ROUTING_ENTRY1(37), ROUTING_ENTRY1(38), ROUTING_ENTRY1(39), ROUTING_ENTRY1(40), ROUTING_ENTRY1(41), ROUTING_ENTRY1(42), ROUTING_ENTRY1(43), ROUTING_ENTRY1(44), ROUTING_ENTRY1(45), ROUTING_ENTRY1(46), ROUTING_ENTRY1(47), #endif }; int kvm_setup_default_irq_routing(struct kvm *kvm) { return kvm_set_irq_routing(kvm, default_routing, ARRAY_SIZE(default_routing), 0); }