1f6108d72SJean-Philippe Brucker #include <errno.h>
2f6108d72SJean-Philippe Brucker #include <stdlib.h>
3f6108d72SJean-Philippe Brucker
4f6108d72SJean-Philippe Brucker #include "kvm/irq.h"
5f6108d72SJean-Philippe Brucker #include "kvm/kvm.h"
6f6108d72SJean-Philippe Brucker #include "kvm/util.h"
7f6108d72SJean-Philippe Brucker
8f6108d72SJean-Philippe Brucker #include "arm-common/gic.h"
9f6108d72SJean-Philippe Brucker
10f6108d72SJean-Philippe Brucker #define GICV2M_MSI_TYPER 0x008
11f6108d72SJean-Philippe Brucker #define GICV2M_MSI_SETSPI 0x040
12f6108d72SJean-Philippe Brucker #define GICV2M_MSI_IIDR 0xfcc
13f6108d72SJean-Philippe Brucker
14f6108d72SJean-Philippe Brucker #define GICV2M_SPI_MASK 0x3ff
15f6108d72SJean-Philippe Brucker #define GICV2M_MSI_TYPER_VAL(start, nr) \
16f6108d72SJean-Philippe Brucker (((start) & GICV2M_SPI_MASK) << 16 | ((nr) & GICV2M_SPI_MASK))
17f6108d72SJean-Philippe Brucker
18f6108d72SJean-Philippe Brucker struct gicv2m_chip {
19f6108d72SJean-Philippe Brucker int first_spi;
20f6108d72SJean-Philippe Brucker int num_spis;
21f6108d72SJean-Philippe Brucker int *spis;
22f6108d72SJean-Philippe Brucker u64 base;
23f6108d72SJean-Philippe Brucker u64 size;
24f6108d72SJean-Philippe Brucker };
25f6108d72SJean-Philippe Brucker
26f6108d72SJean-Philippe Brucker static struct gicv2m_chip v2m;
27f6108d72SJean-Philippe Brucker
28f6108d72SJean-Philippe Brucker /*
29f6108d72SJean-Philippe Brucker * MSI routing is setup lazily, when the guest writes the MSI tables. The guest
30f6108d72SJean-Philippe Brucker * writes which SPI is associated to an MSI vector into the message data field.
31f6108d72SJean-Philippe Brucker * The IRQ code notifies us of any change to MSI routing via this callback.
32f6108d72SJean-Philippe Brucker * Store the MSI->SPI translation for later.
33f6108d72SJean-Philippe Brucker *
34f6108d72SJean-Philippe Brucker * Data is the GIC interrupt ID, that includes SGIs and PPIs. SGIs at 0-15, PPIs
35f6108d72SJean-Philippe Brucker * are 16-31 and SPIs are 32-1019. What we're saving for later is the MSI's GSI
36f6108d72SJean-Philippe Brucker * number, a logical ID used by KVM for routing. The GSI of an SPI is implicitly
37f6108d72SJean-Philippe Brucker * defined by KVM to be its pin number (SPI index), and the GSI of an MSI is
38f6108d72SJean-Philippe Brucker * allocated by kvmtool.
39f6108d72SJean-Philippe Brucker */
gicv2m_update_routing(struct kvm * kvm,struct kvm_irq_routing_entry * entry)40f6108d72SJean-Philippe Brucker static int gicv2m_update_routing(struct kvm *kvm,
41f6108d72SJean-Philippe Brucker struct kvm_irq_routing_entry *entry)
42f6108d72SJean-Philippe Brucker {
43f6108d72SJean-Philippe Brucker int spi;
44f6108d72SJean-Philippe Brucker
45*e3b0ade2SAlexandru Elisei if (entry->type != KVM_IRQ_ROUTING_MSI) {
46*e3b0ade2SAlexandru Elisei errno = EINVAL;
47*e3b0ade2SAlexandru Elisei return -errno;
48*e3b0ade2SAlexandru Elisei }
49f6108d72SJean-Philippe Brucker
50f6108d72SJean-Philippe Brucker if (!entry->u.msi.address_hi && !entry->u.msi.address_lo)
51f6108d72SJean-Philippe Brucker return 0;
52f6108d72SJean-Philippe Brucker
53f6108d72SJean-Philippe Brucker spi = entry->u.msi.data & GICV2M_SPI_MASK;
54f6108d72SJean-Philippe Brucker if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
55*e3b0ade2SAlexandru Elisei errno = EINVAL;
56*e3b0ade2SAlexandru Elisei return -errno;
57f6108d72SJean-Philippe Brucker }
58f6108d72SJean-Philippe Brucker
59f6108d72SJean-Philippe Brucker v2m.spis[spi - v2m.first_spi] = entry->gsi;
60f6108d72SJean-Philippe Brucker
61f6108d72SJean-Philippe Brucker return 0;
62f6108d72SJean-Philippe Brucker }
63f6108d72SJean-Philippe Brucker
64f6108d72SJean-Philippe Brucker /*
65f6108d72SJean-Philippe Brucker * Find SPI bound to the given MSI and return the associated GSI.
66f6108d72SJean-Philippe Brucker */
gicv2m_translate_gsi(struct kvm * kvm,u32 gsi)67f6108d72SJean-Philippe Brucker static int gicv2m_translate_gsi(struct kvm *kvm, u32 gsi)
68f6108d72SJean-Philippe Brucker {
69f6108d72SJean-Philippe Brucker int i;
70f6108d72SJean-Philippe Brucker
71f6108d72SJean-Philippe Brucker for (i = 0; i < v2m.num_spis; i++) {
72f6108d72SJean-Philippe Brucker if (v2m.spis[i] == (int)gsi)
73f6108d72SJean-Philippe Brucker return i + v2m.first_spi - KVM_IRQ_OFFSET;
74f6108d72SJean-Philippe Brucker }
75f6108d72SJean-Philippe Brucker
76f6108d72SJean-Philippe Brucker /* Not an MSI */
77f6108d72SJean-Philippe Brucker return gsi;
78f6108d72SJean-Philippe Brucker }
79f6108d72SJean-Philippe Brucker
gicv2m_can_signal_msi(struct kvm * kvm)80f6108d72SJean-Philippe Brucker static bool gicv2m_can_signal_msi(struct kvm *kvm)
81f6108d72SJean-Philippe Brucker {
82f6108d72SJean-Philippe Brucker return true;
83f6108d72SJean-Philippe Brucker }
84f6108d72SJean-Philippe Brucker
85f6108d72SJean-Philippe Brucker /*
86f6108d72SJean-Philippe Brucker * Instead of setting up MSI routes, virtual devices can also trigger them
87f6108d72SJean-Philippe Brucker * manually (like a direct write to MSI_SETSPI). In this case, trigger the SPI
88f6108d72SJean-Philippe Brucker * directly.
89f6108d72SJean-Philippe Brucker */
gicv2m_signal_msi(struct kvm * kvm,struct kvm_msi * msi)90f6108d72SJean-Philippe Brucker static int gicv2m_signal_msi(struct kvm *kvm, struct kvm_msi *msi)
91f6108d72SJean-Philippe Brucker {
92f6108d72SJean-Philippe Brucker int spi = msi->data & GICV2M_SPI_MASK;
93f6108d72SJean-Philippe Brucker
94f6108d72SJean-Philippe Brucker if (spi < v2m.first_spi || spi >= v2m.first_spi + v2m.num_spis) {
95f6108d72SJean-Philippe Brucker pr_err("invalid SPI number %d", spi);
96f6108d72SJean-Philippe Brucker return -EINVAL;
97f6108d72SJean-Philippe Brucker }
98f6108d72SJean-Philippe Brucker
99f6108d72SJean-Philippe Brucker kvm__irq_trigger(kvm, spi);
100f6108d72SJean-Philippe Brucker return 0;
101f6108d72SJean-Philippe Brucker }
102f6108d72SJean-Philippe Brucker
103f6108d72SJean-Philippe Brucker static struct msi_routing_ops gicv2m_routing = {
104f6108d72SJean-Philippe Brucker .update_route = gicv2m_update_routing,
105f6108d72SJean-Philippe Brucker .translate_gsi = gicv2m_translate_gsi,
106f6108d72SJean-Philippe Brucker .can_signal_msi = gicv2m_can_signal_msi,
107f6108d72SJean-Philippe Brucker .signal_msi = gicv2m_signal_msi,
108f6108d72SJean-Philippe Brucker };
109f6108d72SJean-Philippe Brucker
gicv2m_mmio_callback(struct kvm_cpu * vcpu,u64 addr,u8 * data,u32 len,u8 is_write,void * ptr)110f6108d72SJean-Philippe Brucker static void gicv2m_mmio_callback(struct kvm_cpu *vcpu, u64 addr, u8 *data,
111f6108d72SJean-Philippe Brucker u32 len, u8 is_write, void *ptr)
112f6108d72SJean-Philippe Brucker {
113f6108d72SJean-Philippe Brucker if (is_write)
114f6108d72SJean-Philippe Brucker return;
115f6108d72SJean-Philippe Brucker
116f6108d72SJean-Philippe Brucker addr -= v2m.base;
117f6108d72SJean-Philippe Brucker
118f6108d72SJean-Philippe Brucker switch (addr) {
119f6108d72SJean-Philippe Brucker case GICV2M_MSI_TYPER:
120f6108d72SJean-Philippe Brucker *(u32 *)data = GICV2M_MSI_TYPER_VAL(v2m.first_spi,
121f6108d72SJean-Philippe Brucker v2m.num_spis);
122f6108d72SJean-Philippe Brucker break;
123f6108d72SJean-Philippe Brucker case GICV2M_MSI_IIDR:
124f6108d72SJean-Philippe Brucker *(u32 *)data = 0x0;
125f6108d72SJean-Philippe Brucker break;
126f6108d72SJean-Philippe Brucker }
127f6108d72SJean-Philippe Brucker }
128f6108d72SJean-Philippe Brucker
gic__create_gicv2m_frame(struct kvm * kvm,u64 base)129f6108d72SJean-Philippe Brucker int gic__create_gicv2m_frame(struct kvm *kvm, u64 base)
130f6108d72SJean-Philippe Brucker {
131f6108d72SJean-Philippe Brucker int i;
132f6108d72SJean-Philippe Brucker int irq = irq__alloc_line();
133f6108d72SJean-Philippe Brucker
134f6108d72SJean-Philippe Brucker v2m = (struct gicv2m_chip) {
135f6108d72SJean-Philippe Brucker .first_spi = irq, /* Includes GIC_SPI_IRQ_BASE */
136f6108d72SJean-Philippe Brucker .num_spis = 64, /* arbitrary */
137f6108d72SJean-Philippe Brucker .base = base,
138f6108d72SJean-Philippe Brucker .size = KVM_VGIC_V2M_SIZE,
139f6108d72SJean-Philippe Brucker };
140f6108d72SJean-Philippe Brucker
141f6108d72SJean-Philippe Brucker v2m.spis = calloc(v2m.num_spis, sizeof(int));
142f6108d72SJean-Philippe Brucker if (!v2m.spis)
143f6108d72SJean-Philippe Brucker return -ENOMEM;
144f6108d72SJean-Philippe Brucker
145f6108d72SJean-Philippe Brucker v2m.spis[0] = -1;
146f6108d72SJean-Philippe Brucker for (i = 1; i < v2m.num_spis; i++) {
147f6108d72SJean-Philippe Brucker irq__alloc_line();
148f6108d72SJean-Philippe Brucker v2m.spis[i] = -1;
149f6108d72SJean-Philippe Brucker }
150f6108d72SJean-Philippe Brucker
151f6108d72SJean-Philippe Brucker msi_routing_ops = &gicv2m_routing;
152f6108d72SJean-Philippe Brucker
153f6108d72SJean-Philippe Brucker return kvm__register_mmio(kvm, base, KVM_VGIC_V2M_SIZE, false,
154f6108d72SJean-Philippe Brucker gicv2m_mmio_callback, kvm);
155f6108d72SJean-Philippe Brucker }
156