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