xref: /kvmtool/x86/irq.c (revision 33348d034d61a17f752f854052cbf843ffb7b146)
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