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