1c383fe9cSSasha Levin #include "kvm/irq.h" 2*5f0a22b7SSasha Levin #include "kvm/kvm.h" 3*5f0a22b7SSasha 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> 8*5f0a22b7SSasha Levin #include <linux/kvm.h> 9*5f0a22b7SSasha Levin #include <sys/ioctl.h> 10c383fe9cSSasha Levin 11c383fe9cSSasha Levin #include <stddef.h> 12c383fe9cSSasha Levin #include <stdlib.h> 13c383fe9cSSasha Levin 14*5f0a22b7SSasha Levin #define IRQ_MAX_GSI 64 15*5f0a22b7SSasha Levin #define IRQCHIP_MASTER 0 16*5f0a22b7SSasha Levin #define IRQCHIP_SLAVE 1 17*5f0a22b7SSasha Levin #define IRQCHIP_IOAPIC 2 18*5f0a22b7SSasha Levin 19c383fe9cSSasha Levin static u8 next_line = 3; 20c383fe9cSSasha Levin static u8 next_dev = 1; 21c383fe9cSSasha Levin static struct rb_root pci_tree = RB_ROOT; 22c383fe9cSSasha Levin 23*5f0a22b7SSasha Levin /* First 24 GSIs are routed between IRQCHIPs and IOAPICs */ 24*5f0a22b7SSasha Levin static u32 gsi = 24; 25*5f0a22b7SSasha Levin 26*5f0a22b7SSasha Levin struct kvm_irq_routing *irq_routing; 27*5f0a22b7SSasha Levin 28*5f0a22b7SSasha Levin static int irq__add_routing(u32 gsi, u32 type, u32 irqchip, u32 pin) 29*5f0a22b7SSasha Levin { 30*5f0a22b7SSasha Levin if (gsi >= IRQ_MAX_GSI) 31*5f0a22b7SSasha Levin return -ENOSPC; 32*5f0a22b7SSasha Levin 33*5f0a22b7SSasha Levin irq_routing->entries[irq_routing->nr++] = 34*5f0a22b7SSasha Levin (struct kvm_irq_routing_entry) { 35*5f0a22b7SSasha Levin .gsi = gsi, 36*5f0a22b7SSasha Levin .type = type, 37*5f0a22b7SSasha Levin .u.irqchip.irqchip = irqchip, 38*5f0a22b7SSasha Levin .u.irqchip.pin = pin, 39*5f0a22b7SSasha Levin }; 40*5f0a22b7SSasha Levin 41*5f0a22b7SSasha Levin return 0; 42*5f0a22b7SSasha Levin } 43*5f0a22b7SSasha 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 79c383fe9cSSasha Levin return 0; 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 86c383fe9cSSasha Levin return 1; 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; 92c383fe9cSSasha Levin 93c383fe9cSSasha Levin node = search(&pci_tree, dev); 94c383fe9cSSasha Levin 95c383fe9cSSasha Levin if (!node) { 96c383fe9cSSasha Levin /* We haven't found a node - First device of it's kind */ 97c383fe9cSSasha Levin node = malloc(sizeof(*node)); 98c383fe9cSSasha Levin if (node == NULL) 99c383fe9cSSasha Levin return -1; 100c383fe9cSSasha Levin 101c383fe9cSSasha Levin *node = (struct pci_dev) { 102c383fe9cSSasha Levin .id = dev, 10333348d03SCyrill Gorcunov /* 10433348d03SCyrill Gorcunov * PCI supports only INTA#,B#,C#,D# per device. 10533348d03SCyrill Gorcunov * A#,B#,C#,D# are allowed for multifunctional 10633348d03SCyrill Gorcunov * devices so stick with A# for our single 10733348d03SCyrill Gorcunov * function devices. 10833348d03SCyrill Gorcunov */ 10933348d03SCyrill Gorcunov .pin = 1, 110c383fe9cSSasha Levin }; 111c383fe9cSSasha Levin 112c383fe9cSSasha Levin INIT_LIST_HEAD(&node->lines); 113c383fe9cSSasha Levin 114c383fe9cSSasha Levin if (insert(&pci_tree, node) != 1) { 115c383fe9cSSasha Levin free(node); 116c383fe9cSSasha Levin return -1; 117c383fe9cSSasha Levin } 118c383fe9cSSasha Levin } 119c383fe9cSSasha Levin 120c383fe9cSSasha Levin if (node) { 121c383fe9cSSasha Levin /* This device already has a pin assigned, give out a new line and device id */ 122c383fe9cSSasha Levin struct irq_line *new = malloc(sizeof(*new)); 123c383fe9cSSasha Levin if (new == NULL) 124c383fe9cSSasha Levin return -1; 125c383fe9cSSasha Levin 126c383fe9cSSasha Levin new->line = next_line++; 127c383fe9cSSasha Levin *line = new->line; 128c383fe9cSSasha Levin *pin = node->pin; 129c383fe9cSSasha Levin *num = next_dev++; 130c383fe9cSSasha Levin 131c383fe9cSSasha Levin list_add(&new->node, &node->lines); 132c383fe9cSSasha Levin 133c383fe9cSSasha Levin return 0; 134c383fe9cSSasha Levin } 135c383fe9cSSasha Levin 136c383fe9cSSasha Levin return -1; 137c383fe9cSSasha Levin } 138c383fe9cSSasha Levin 139*5f0a22b7SSasha Levin void irq__init(struct kvm *kvm) 140*5f0a22b7SSasha Levin { 141*5f0a22b7SSasha Levin int i, r; 142*5f0a22b7SSasha Levin 143*5f0a22b7SSasha Levin irq_routing = malloc(sizeof(struct kvm_irq_routing) + 144*5f0a22b7SSasha Levin IRQ_MAX_GSI * sizeof(struct kvm_irq_routing_entry)); 145*5f0a22b7SSasha Levin if (irq_routing == NULL) 146*5f0a22b7SSasha Levin die("Failed allocating space for GSI table"); 147*5f0a22b7SSasha Levin 148*5f0a22b7SSasha Levin /* Hook first 8 GSIs to master IRQCHIP */ 149*5f0a22b7SSasha Levin for (i = 0; i < 8; i++) 150*5f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_MASTER, i); 151*5f0a22b7SSasha Levin 152*5f0a22b7SSasha Levin /* Hook next 8 GSIs to slave IRQCHIP */ 153*5f0a22b7SSasha Levin for (i = 8; i < 16; i++) 154*5f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_SLAVE, 8-i); 155*5f0a22b7SSasha Levin 156*5f0a22b7SSasha Levin /* Last but not least, IOAPIC */ 157*5f0a22b7SSasha Levin for (i = 0; i < 24; i++) { 158*5f0a22b7SSasha Levin if (i == 0) 159*5f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, 2); 160*5f0a22b7SSasha Levin else 161*5f0a22b7SSasha Levin irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, i); 162*5f0a22b7SSasha Levin } 163*5f0a22b7SSasha Levin 164*5f0a22b7SSasha Levin r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing); 165*5f0a22b7SSasha Levin if (r) 166*5f0a22b7SSasha Levin die("Failed setting GSI routes"); 167*5f0a22b7SSasha Levin } 168*5f0a22b7SSasha Levin 169*5f0a22b7SSasha Levin int irq__add_msix_route(struct kvm *kvm, u32 low, u32 high, u32 data) 170*5f0a22b7SSasha Levin { 171*5f0a22b7SSasha Levin int r; 172*5f0a22b7SSasha Levin 173*5f0a22b7SSasha Levin irq_routing->entries[irq_routing->nr++] = 174*5f0a22b7SSasha Levin (struct kvm_irq_routing_entry) { 175*5f0a22b7SSasha Levin .gsi = gsi, 176*5f0a22b7SSasha Levin .type = KVM_IRQ_ROUTING_MSI, 177*5f0a22b7SSasha Levin .u.msi.address_lo = low, 178*5f0a22b7SSasha Levin .u.msi.address_hi = high, 179*5f0a22b7SSasha Levin .u.msi.data = data, 180*5f0a22b7SSasha Levin }; 181*5f0a22b7SSasha Levin 182*5f0a22b7SSasha Levin r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing); 183*5f0a22b7SSasha Levin if (r) 184*5f0a22b7SSasha Levin return r; 185*5f0a22b7SSasha Levin 186*5f0a22b7SSasha Levin return gsi++; 187*5f0a22b7SSasha Levin } 188*5f0a22b7SSasha Levin 189c383fe9cSSasha Levin struct rb_node *irq__get_pci_tree(void) 190c383fe9cSSasha Levin { 191c383fe9cSSasha Levin return rb_first(&pci_tree); 192c383fe9cSSasha Levin } 193