xref: /kvmtool/irq.c (revision 8ccc85497ca3136688b015fecaa956fd95b936a1)
1 #include <stdlib.h>
2 #include <sys/ioctl.h>
3 #include <linux/types.h>
4 #include <linux/kvm.h>
5 #include <errno.h>
6 
7 #include "kvm/kvm.h"
8 #include "kvm/irq.h"
9 #include "kvm/kvm-arch.h"
10 
11 static u8 next_line = KVM_IRQ_OFFSET;
12 static int allocated_gsis = 0;
13 
14 int next_gsi;
15 
16 struct kvm_irq_routing *irq_routing = NULL;
17 
18 int irq__alloc_line(void)
19 {
20 	return next_line++;
21 }
22 
23 int irq__get_nr_allocated_lines(void)
24 {
25 	return next_line - KVM_IRQ_OFFSET;
26 }
27 
28 int irq__allocate_routing_entry(void)
29 {
30 	size_t table_size = sizeof(struct kvm_irq_routing);
31 	size_t old_size = table_size;
32 	int nr_entries = 0;
33 
34 	if (irq_routing)
35 		nr_entries = irq_routing->nr;
36 
37 	if (nr_entries < allocated_gsis)
38 		return 0;
39 
40 	old_size += sizeof(struct kvm_irq_routing_entry) * allocated_gsis;
41 	allocated_gsis = ALIGN(nr_entries + 1, 32);
42 	table_size += sizeof(struct kvm_irq_routing_entry) * allocated_gsis;
43 	irq_routing = realloc(irq_routing, table_size);
44 
45 	if (irq_routing == NULL)
46 		return -ENOMEM;
47 	memset((void *)irq_routing + old_size, 0, table_size - old_size);
48 
49 	irq_routing->nr = nr_entries;
50 	irq_routing->flags = 0;
51 
52 	return 0;
53 }
54 
55 static bool check_for_irq_routing(struct kvm *kvm)
56 {
57 	static int has_irq_routing = 0;
58 
59 	if (has_irq_routing == 0) {
60 		if (kvm__supports_extension(kvm, KVM_CAP_IRQ_ROUTING))
61 			has_irq_routing = 1;
62 		else
63 			has_irq_routing = -1;
64 	}
65 
66 	return has_irq_routing > 0;
67 }
68 
69 int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
70 {
71 	int r;
72 
73 	if (!check_for_irq_routing(kvm))
74 		return -ENXIO;
75 
76 	r = irq__allocate_routing_entry();
77 	if (r)
78 		return r;
79 
80 	irq_routing->entries[irq_routing->nr++] =
81 		(struct kvm_irq_routing_entry) {
82 			.gsi = next_gsi,
83 			.type = KVM_IRQ_ROUTING_MSI,
84 			.u.msi.address_hi = msg->address_hi,
85 			.u.msi.address_lo = msg->address_lo,
86 			.u.msi.data = msg->data,
87 		};
88 
89 	r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
90 	if (r)
91 		return r;
92 
93 	return next_gsi++;
94 }
95 
96 int __attribute__((weak)) irq__exit(struct kvm *kvm)
97 {
98 	free(irq_routing);
99 	return 0;
100 }
101 dev_base_exit(irq__exit);
102