1c383fe9cSSasha Levin #include "kvm/irq.h" 2c383fe9cSSasha Levin 3c383fe9cSSasha Levin #include <linux/types.h> 4c383fe9cSSasha Levin #include <linux/rbtree.h> 5c383fe9cSSasha Levin #include <linux/list.h> 6c383fe9cSSasha Levin 7c383fe9cSSasha Levin #include <stddef.h> 8c383fe9cSSasha Levin #include <stdlib.h> 9c383fe9cSSasha Levin 10c383fe9cSSasha Levin static u8 next_line = 3; 11c383fe9cSSasha Levin static u8 next_dev = 1; 12c383fe9cSSasha Levin static struct rb_root pci_tree = RB_ROOT; 13c383fe9cSSasha Levin 14c383fe9cSSasha Levin static struct pci_dev *search(struct rb_root *root, u32 id) 15c383fe9cSSasha Levin { 16c383fe9cSSasha Levin struct rb_node *node = root->rb_node; 17c383fe9cSSasha Levin 18c383fe9cSSasha Levin while (node) { 19c383fe9cSSasha Levin struct pci_dev *data = container_of(node, struct pci_dev, node); 20c383fe9cSSasha Levin int result; 21c383fe9cSSasha Levin 22c383fe9cSSasha Levin result = id - data->id; 23c383fe9cSSasha Levin 24c383fe9cSSasha Levin if (result < 0) 25c383fe9cSSasha Levin node = node->rb_left; 26c383fe9cSSasha Levin else if (result > 0) 27c383fe9cSSasha Levin node = node->rb_right; 28c383fe9cSSasha Levin else 29c383fe9cSSasha Levin return data; 30c383fe9cSSasha Levin } 31c383fe9cSSasha Levin return NULL; 32c383fe9cSSasha Levin } 33c383fe9cSSasha Levin 34c383fe9cSSasha Levin static int insert(struct rb_root *root, struct pci_dev *data) 35c383fe9cSSasha Levin { 36c383fe9cSSasha Levin struct rb_node **new = &(root->rb_node), *parent = NULL; 37c383fe9cSSasha Levin 38c383fe9cSSasha Levin /* Figure out where to put new node */ 39c383fe9cSSasha Levin while (*new) { 40c383fe9cSSasha Levin struct pci_dev *this = container_of(*new, struct pci_dev, node); 41c383fe9cSSasha Levin int result = data->id - this->id; 42c383fe9cSSasha Levin 43c383fe9cSSasha Levin parent = *new; 44c383fe9cSSasha Levin if (result < 0) 45c383fe9cSSasha Levin new = &((*new)->rb_left); 46c383fe9cSSasha Levin else if (result > 0) 47c383fe9cSSasha Levin new = &((*new)->rb_right); 48c383fe9cSSasha Levin else 49c383fe9cSSasha Levin return 0; 50c383fe9cSSasha Levin } 51c383fe9cSSasha Levin 52c383fe9cSSasha Levin /* Add new node and rebalance tree. */ 53c383fe9cSSasha Levin rb_link_node(&data->node, parent, new); 54c383fe9cSSasha Levin rb_insert_color(&data->node, root); 55c383fe9cSSasha Levin 56c383fe9cSSasha Levin return 1; 57c383fe9cSSasha Levin } 58c383fe9cSSasha Levin 59c383fe9cSSasha Levin int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line) 60c383fe9cSSasha Levin { 61c383fe9cSSasha Levin struct pci_dev *node; 62c383fe9cSSasha Levin 63c383fe9cSSasha Levin node = search(&pci_tree, dev); 64c383fe9cSSasha Levin 65c383fe9cSSasha Levin if (!node) { 66c383fe9cSSasha Levin /* We haven't found a node - First device of it's kind */ 67c383fe9cSSasha Levin node = malloc(sizeof(*node)); 68c383fe9cSSasha Levin if (node == NULL) 69c383fe9cSSasha Levin return -1; 70c383fe9cSSasha Levin 71c383fe9cSSasha Levin *node = (struct pci_dev) { 72c383fe9cSSasha Levin .id = dev, 73*33348d03SCyrill Gorcunov /* 74*33348d03SCyrill Gorcunov * PCI supports only INTA#,B#,C#,D# per device. 75*33348d03SCyrill Gorcunov * A#,B#,C#,D# are allowed for multifunctional 76*33348d03SCyrill Gorcunov * devices so stick with A# for our single 77*33348d03SCyrill Gorcunov * function devices. 78*33348d03SCyrill Gorcunov */ 79*33348d03SCyrill Gorcunov .pin = 1, 80c383fe9cSSasha Levin }; 81c383fe9cSSasha Levin 82c383fe9cSSasha Levin INIT_LIST_HEAD(&node->lines); 83c383fe9cSSasha Levin 84c383fe9cSSasha Levin if (insert(&pci_tree, node) != 1) { 85c383fe9cSSasha Levin free(node); 86c383fe9cSSasha Levin return -1; 87c383fe9cSSasha Levin } 88c383fe9cSSasha Levin } 89c383fe9cSSasha Levin 90c383fe9cSSasha Levin if (node) { 91c383fe9cSSasha Levin /* This device already has a pin assigned, give out a new line and device id */ 92c383fe9cSSasha Levin struct irq_line *new = malloc(sizeof(*new)); 93c383fe9cSSasha Levin if (new == NULL) 94c383fe9cSSasha Levin return -1; 95c383fe9cSSasha Levin 96c383fe9cSSasha Levin new->line = next_line++; 97c383fe9cSSasha Levin *line = new->line; 98c383fe9cSSasha Levin *pin = node->pin; 99c383fe9cSSasha Levin *num = next_dev++; 100c383fe9cSSasha Levin 101c383fe9cSSasha Levin list_add(&new->node, &node->lines); 102c383fe9cSSasha Levin 103c383fe9cSSasha Levin return 0; 104c383fe9cSSasha Levin } 105c383fe9cSSasha Levin 106c383fe9cSSasha Levin return -1; 107c383fe9cSSasha Levin } 108c383fe9cSSasha Levin 109c383fe9cSSasha Levin struct rb_node *irq__get_pci_tree(void) 110c383fe9cSSasha Levin { 111c383fe9cSSasha Levin return rb_first(&pci_tree); 112c383fe9cSSasha Levin } 113