1*8ccc8549SAndre Przywara #include <stdlib.h> 2*8ccc8549SAndre Przywara #include <sys/ioctl.h> 3*8ccc8549SAndre Przywara #include <linux/types.h> 4*8ccc8549SAndre Przywara #include <linux/kvm.h> 5*8ccc8549SAndre Przywara #include <errno.h> 6*8ccc8549SAndre Przywara 7*8ccc8549SAndre Przywara #include "kvm/kvm.h" 89dc5430cSWill Deacon #include "kvm/irq.h" 99dc5430cSWill Deacon #include "kvm/kvm-arch.h" 109dc5430cSWill Deacon 119dc5430cSWill Deacon static u8 next_line = KVM_IRQ_OFFSET; 12*8ccc8549SAndre Przywara static int allocated_gsis = 0; 13*8ccc8549SAndre Przywara 14*8ccc8549SAndre Przywara int next_gsi; 15*8ccc8549SAndre Przywara 16*8ccc8549SAndre Przywara struct kvm_irq_routing *irq_routing = NULL; 179dc5430cSWill Deacon 189dc5430cSWill Deacon int irq__alloc_line(void) 199dc5430cSWill Deacon { 209dc5430cSWill Deacon return next_line++; 219dc5430cSWill Deacon } 22cb87229bSMarc Zyngier 23cb87229bSMarc Zyngier int irq__get_nr_allocated_lines(void) 24cb87229bSMarc Zyngier { 25cb87229bSMarc Zyngier return next_line - KVM_IRQ_OFFSET; 26cb87229bSMarc Zyngier } 27*8ccc8549SAndre Przywara 28*8ccc8549SAndre Przywara int irq__allocate_routing_entry(void) 29*8ccc8549SAndre Przywara { 30*8ccc8549SAndre Przywara size_t table_size = sizeof(struct kvm_irq_routing); 31*8ccc8549SAndre Przywara size_t old_size = table_size; 32*8ccc8549SAndre Przywara int nr_entries = 0; 33*8ccc8549SAndre Przywara 34*8ccc8549SAndre Przywara if (irq_routing) 35*8ccc8549SAndre Przywara nr_entries = irq_routing->nr; 36*8ccc8549SAndre Przywara 37*8ccc8549SAndre Przywara if (nr_entries < allocated_gsis) 38*8ccc8549SAndre Przywara return 0; 39*8ccc8549SAndre Przywara 40*8ccc8549SAndre Przywara old_size += sizeof(struct kvm_irq_routing_entry) * allocated_gsis; 41*8ccc8549SAndre Przywara allocated_gsis = ALIGN(nr_entries + 1, 32); 42*8ccc8549SAndre Przywara table_size += sizeof(struct kvm_irq_routing_entry) * allocated_gsis; 43*8ccc8549SAndre Przywara irq_routing = realloc(irq_routing, table_size); 44*8ccc8549SAndre Przywara 45*8ccc8549SAndre Przywara if (irq_routing == NULL) 46*8ccc8549SAndre Przywara return -ENOMEM; 47*8ccc8549SAndre Przywara memset((void *)irq_routing + old_size, 0, table_size - old_size); 48*8ccc8549SAndre Przywara 49*8ccc8549SAndre Przywara irq_routing->nr = nr_entries; 50*8ccc8549SAndre Przywara irq_routing->flags = 0; 51*8ccc8549SAndre Przywara 52*8ccc8549SAndre Przywara return 0; 53*8ccc8549SAndre Przywara } 54*8ccc8549SAndre Przywara 55*8ccc8549SAndre Przywara static bool check_for_irq_routing(struct kvm *kvm) 56*8ccc8549SAndre Przywara { 57*8ccc8549SAndre Przywara static int has_irq_routing = 0; 58*8ccc8549SAndre Przywara 59*8ccc8549SAndre Przywara if (has_irq_routing == 0) { 60*8ccc8549SAndre Przywara if (kvm__supports_extension(kvm, KVM_CAP_IRQ_ROUTING)) 61*8ccc8549SAndre Przywara has_irq_routing = 1; 62*8ccc8549SAndre Przywara else 63*8ccc8549SAndre Przywara has_irq_routing = -1; 64*8ccc8549SAndre Przywara } 65*8ccc8549SAndre Przywara 66*8ccc8549SAndre Przywara return has_irq_routing > 0; 67*8ccc8549SAndre Przywara } 68*8ccc8549SAndre Przywara 69*8ccc8549SAndre Przywara int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg) 70*8ccc8549SAndre Przywara { 71*8ccc8549SAndre Przywara int r; 72*8ccc8549SAndre Przywara 73*8ccc8549SAndre Przywara if (!check_for_irq_routing(kvm)) 74*8ccc8549SAndre Przywara return -ENXIO; 75*8ccc8549SAndre Przywara 76*8ccc8549SAndre Przywara r = irq__allocate_routing_entry(); 77*8ccc8549SAndre Przywara if (r) 78*8ccc8549SAndre Przywara return r; 79*8ccc8549SAndre Przywara 80*8ccc8549SAndre Przywara irq_routing->entries[irq_routing->nr++] = 81*8ccc8549SAndre Przywara (struct kvm_irq_routing_entry) { 82*8ccc8549SAndre Przywara .gsi = next_gsi, 83*8ccc8549SAndre Przywara .type = KVM_IRQ_ROUTING_MSI, 84*8ccc8549SAndre Przywara .u.msi.address_hi = msg->address_hi, 85*8ccc8549SAndre Przywara .u.msi.address_lo = msg->address_lo, 86*8ccc8549SAndre Przywara .u.msi.data = msg->data, 87*8ccc8549SAndre Przywara }; 88*8ccc8549SAndre Przywara 89*8ccc8549SAndre Przywara r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing); 90*8ccc8549SAndre Przywara if (r) 91*8ccc8549SAndre Przywara return r; 92*8ccc8549SAndre Przywara 93*8ccc8549SAndre Przywara return next_gsi++; 94*8ccc8549SAndre Przywara } 95*8ccc8549SAndre Przywara 96*8ccc8549SAndre Przywara int __attribute__((weak)) irq__exit(struct kvm *kvm) 97*8ccc8549SAndre Przywara { 98*8ccc8549SAndre Przywara free(irq_routing); 99*8ccc8549SAndre Przywara return 0; 100*8ccc8549SAndre Przywara } 101*8ccc8549SAndre Przywara dev_base_exit(irq__exit); 102