1c383fe9cSSasha Levin #include "kvm/irq.h" 25f0a22b7SSasha Levin #include "kvm/kvm.h" 35f0a22b7SSasha Levin #include "kvm/util.h" 4c383fe9cSSasha Levin 5c383fe9cSSasha Levin #include <linux/types.h> 6c383fe9cSSasha Levin #include <linux/rbtree.h> 7c383fe9cSSasha Levin #include <linux/list.h> 85f0a22b7SSasha Levin #include <linux/kvm.h> 95f0a22b7SSasha Levin #include <sys/ioctl.h> 10c383fe9cSSasha Levin 11c383fe9cSSasha Levin #include <stddef.h> 12c383fe9cSSasha Levin #include <stdlib.h> 13c383fe9cSSasha Levin 145f0a22b7SSasha Levin #define IRQ_MAX_GSI 64 155f0a22b7SSasha Levin #define IRQCHIP_MASTER 0 165f0a22b7SSasha Levin #define IRQCHIP_SLAVE 1 175f0a22b7SSasha Levin #define IRQCHIP_IOAPIC 2 185f0a22b7SSasha Levin 1999de8863SSasha Levin static u8 next_line = 5; 20c383fe9cSSasha Levin static u8 next_dev = 1; 21c383fe9cSSasha Levin static struct rb_root pci_tree = RB_ROOT; 22c383fe9cSSasha Levin 235f0a22b7SSasha Levin /* First 24 GSIs are routed between IRQCHIPs and IOAPICs */ 245f0a22b7SSasha Levin static u32 gsi = 24; 255f0a22b7SSasha Levin 265f0a22b7SSasha Levin struct kvm_irq_routing *irq_routing; 275f0a22b7SSasha Levin 285f0a22b7SSasha Levin static int irq__add_routing(u32 gsi, u32 type, u32 irqchip, u32 pin) 295f0a22b7SSasha Levin { 305f0a22b7SSasha Levin if (gsi >= IRQ_MAX_GSI) 315f0a22b7SSasha Levin return -ENOSPC; 325f0a22b7SSasha Levin 335f0a22b7SSasha Levin irq_routing->entries[irq_routing->nr++] = 345f0a22b7SSasha Levin (struct kvm_irq_routing_entry) { 355f0a22b7SSasha Levin .gsi = gsi, 365f0a22b7SSasha Levin .type = type, 375f0a22b7SSasha Levin .u.irqchip.irqchip = irqchip, 385f0a22b7SSasha Levin .u.irqchip.pin = pin, 395f0a22b7SSasha Levin }; 405f0a22b7SSasha Levin 415f0a22b7SSasha Levin return 0; 425f0a22b7SSasha Levin } 435f0a22b7SSasha Levin 44c383fe9cSSasha Levin static struct pci_dev *search(struct rb_root *root, u32 id) 45c383fe9cSSasha Levin { 46c383fe9cSSasha Levin struct rb_node *node = root->rb_node; 47c383fe9cSSasha Levin 48c383fe9cSSasha Levin while (node) { 49c383fe9cSSasha Levin struct pci_dev *data = container_of(node, struct pci_dev, node); 50c383fe9cSSasha Levin int result; 51c383fe9cSSasha Levin 52c383fe9cSSasha Levin result = id - data->id; 53c383fe9cSSasha Levin 54c383fe9cSSasha Levin if (result < 0) 55c383fe9cSSasha Levin node = node->rb_left; 56c383fe9cSSasha Levin else if (result > 0) 57c383fe9cSSasha Levin node = node->rb_right; 58c383fe9cSSasha Levin else 59c383fe9cSSasha Levin return data; 60c383fe9cSSasha Levin } 61c383fe9cSSasha Levin return NULL; 62c383fe9cSSasha Levin } 63c383fe9cSSasha Levin 64c383fe9cSSasha Levin static int insert(struct rb_root *root, struct pci_dev *data) 65c383fe9cSSasha Levin { 66c383fe9cSSasha Levin struct rb_node **new = &(root->rb_node), *parent = NULL; 67c383fe9cSSasha Levin 68c383fe9cSSasha Levin /* Figure out where to put new node */ 69c383fe9cSSasha Levin while (*new) { 70c383fe9cSSasha Levin struct pci_dev *this = container_of(*new, struct pci_dev, node); 71c383fe9cSSasha Levin int result = data->id - this->id; 72c383fe9cSSasha Levin 73c383fe9cSSasha Levin parent = *new; 74c383fe9cSSasha Levin if (result < 0) 75c383fe9cSSasha Levin new = &((*new)->rb_left); 76c383fe9cSSasha Levin else if (result > 0) 77c383fe9cSSasha Levin new = &((*new)->rb_right); 78c383fe9cSSasha Levin else 79*e3c4f8aaSSasha Levin return -EEXIST; 80c383fe9cSSasha Levin } 81c383fe9cSSasha Levin 82c383fe9cSSasha Levin /* Add new node and rebalance tree. */ 83c383fe9cSSasha Levin rb_link_node(&data->node, parent, new); 84c383fe9cSSasha Levin rb_insert_color(&data->node, root); 85c383fe9cSSasha Levin 86*e3c4f8aaSSasha Levin return 0; 87c383fe9cSSasha Levin } 88c383fe9cSSasha Levin 89c383fe9cSSasha Levin int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line) 90c383fe9cSSasha Levin { 91c383fe9cSSasha Levin struct pci_dev *node; 92*e3c4f8aaSSasha Levin int r; 93c383fe9cSSasha Levin 94c383fe9cSSasha Levin node = search(&pci_tree, dev); 95c383fe9cSSasha Levin 96c383fe9cSSasha Levin if (!node) { 97c383fe9cSSasha Levin /* We haven't found a node - First device of it's kind */ 98c383fe9cSSasha Levin node = malloc(sizeof(*node)); 99c383fe9cSSasha Levin if (node == NULL) 100*e3c4f8aaSSasha Levin return -ENOMEM; 101c383fe9cSSasha Levin 102c383fe9cSSasha Levin *node = (struct pci_dev) { 103c383fe9cSSasha Levin .id = dev, 10433348d03SCyrill Gorcunov /* 10533348d03SCyrill Gorcunov * PCI supports only INTA#,B#,C#,D# per device. 10633348d03SCyrill Gorcunov * A#,B#,C#,D# are allowed for multifunctional 10733348d03SCyrill Gorcunov * devices so stick with A# for our single 10833348d03SCyrill Gorcunov * function devices. 10933348d03SCyrill Gorcunov */ 11033348d03SCyrill Gorcunov .pin = 1, 111c383fe9cSSasha Levin }; 112c383fe9cSSasha Levin 113c383fe9cSSasha Levin INIT_LIST_HEAD(&node->lines); 114c383fe9cSSasha Levin 115*e3c4f8aaSSasha Levin r = insert(&pci_tree, node); 116*e3c4f8aaSSasha Levin if (r) { 117c383fe9cSSasha Levin free(node); 118*e3c4f8aaSSasha Levin return r; 119c383fe9cSSasha Levin } 120c383fe9cSSasha Levin } 121c383fe9cSSasha Levin 122c383fe9cSSasha Levin if (node) { 123c383fe9cSSasha Levin /* This device already has a pin assigned, give out a new line and device id */ 124c383fe9cSSasha Levin struct irq_line *new = malloc(sizeof(*new)); 125c383fe9cSSasha Levin if (new == NULL) 126*e3c4f8aaSSasha Levin return -ENOMEM; 127c383fe9cSSasha Levin 128c383fe9cSSasha Levin new->line = next_line++; 129c383fe9cSSasha Levin *line = new->line; 130c383fe9cSSasha Levin *pin = node->pin; 131c383fe9cSSasha Levin *num = next_dev++; 132c383fe9cSSasha Levin 133c383fe9cSSasha Levin list_add(&new->node, &node->lines); 134c383fe9cSSasha Levin 135c383fe9cSSasha Levin return 0; 136c383fe9cSSasha Levin } 137c383fe9cSSasha Levin 138*e3c4f8aaSSasha Levin return -EFAULT; 139c383fe9cSSasha Levin } 140c383fe9cSSasha Levin 141*e3c4f8aaSSasha Levin int irq__init(struct kvm *kvm) 1425f0a22b7SSasha Levin { 1435f0a22b7SSasha Levin int i, r; 1445f0a22b7SSasha Levin 145beb8f24bSSasha Levin irq_routing = calloc(sizeof(struct kvm_irq_routing) + 146beb8f24bSSasha Levin IRQ_MAX_GSI * sizeof(struct kvm_irq_routing_entry), 1); 1475f0a22b7SSasha Levin if (irq_routing == NULL) 148*e3c4f8aaSSasha Levin return -ENOMEM; 1495f0a22b7SSasha Levin 1505f0a22b7SSasha Levin /* Hook first 8 GSIs to master IRQCHIP */ 1515f0a22b7SSasha Levin for (i = 0; i < 8; i++) 1522eb7ffa0SSasha Levin if (i != 2) 1535f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_MASTER, i); 1545f0a22b7SSasha Levin 1555f0a22b7SSasha Levin /* Hook next 8 GSIs to slave IRQCHIP */ 1565f0a22b7SSasha Levin for (i = 8; i < 16; i++) 1572eb7ffa0SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_SLAVE, i - 8); 1585f0a22b7SSasha Levin 1595f0a22b7SSasha Levin /* Last but not least, IOAPIC */ 1605f0a22b7SSasha Levin for (i = 0; i < 24; i++) { 1615f0a22b7SSasha Levin if (i == 0) 1625f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, 2); 1632eb7ffa0SSasha Levin else if (i != 2) 1645f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, i); 1655f0a22b7SSasha Levin } 1665f0a22b7SSasha Levin 1675f0a22b7SSasha Levin r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing); 168*e3c4f8aaSSasha Levin if (r) { 169*e3c4f8aaSSasha Levin free(irq_routing); 170*e3c4f8aaSSasha Levin return errno; 171*e3c4f8aaSSasha Levin } 172*e3c4f8aaSSasha Levin 173*e3c4f8aaSSasha Levin return 0; 174*e3c4f8aaSSasha Levin } 175*e3c4f8aaSSasha Levin 176*e3c4f8aaSSasha Levin int irq__exit(struct kvm *kvm) 177*e3c4f8aaSSasha Levin { 178*e3c4f8aaSSasha Levin free(irq_routing); 179*e3c4f8aaSSasha Levin 180*e3c4f8aaSSasha Levin return 0; 1815f0a22b7SSasha Levin } 1825f0a22b7SSasha Levin 1831de74957SSasha Levin int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg) 1845f0a22b7SSasha Levin { 1855f0a22b7SSasha Levin int r; 1865f0a22b7SSasha Levin 1875f0a22b7SSasha Levin irq_routing->entries[irq_routing->nr++] = 1885f0a22b7SSasha Levin (struct kvm_irq_routing_entry) { 1895f0a22b7SSasha Levin .gsi = gsi, 1905f0a22b7SSasha Levin .type = KVM_IRQ_ROUTING_MSI, 1911de74957SSasha Levin .u.msi.address_hi = msg->address_hi, 1921de74957SSasha Levin .u.msi.address_lo = msg->address_lo, 1931de74957SSasha Levin .u.msi.data = msg->data, 1945f0a22b7SSasha Levin }; 1955f0a22b7SSasha Levin 1965f0a22b7SSasha Levin r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing); 1975f0a22b7SSasha Levin if (r) 1985f0a22b7SSasha Levin return r; 1995f0a22b7SSasha Levin 2005f0a22b7SSasha Levin return gsi++; 2015f0a22b7SSasha Levin } 2025f0a22b7SSasha Levin 203c383fe9cSSasha Levin struct rb_node *irq__get_pci_tree(void) 204c383fe9cSSasha Levin { 205c383fe9cSSasha Levin return rb_first(&pci_tree); 206c383fe9cSSasha Levin } 207