diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2017-10-27 10:28:39 -0400 |
---|---|---|
committer | Christoffer Dall <christoffer.dall@linaro.org> | 2017-11-10 03:28:52 -0500 |
commit | 196b136498b35f1cd787b84465f235e69dbc757c (patch) | |
tree | 23890d9f31732cfb18203945c3bcb80ca52699fb | |
parent | 74fe55dc9ab77142e3c4783ecc5b87d494164452 (diff) |
KVM: arm/arm64: GICv4: Wire mapping/unmapping of VLPIs in VFIO irq bypass
Let's use the irq bypass mechanism also used for x86 posted interrupts
to intercept the virtual PCIe endpoint configuration and establish our
LPI->VLPI mapping.
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
-rw-r--r-- | include/kvm/arm_vgic.h | 8 | ||||
-rw-r--r-- | virt/kvm/arm/arm.c | 6 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v4.c | 104 |
3 files changed, 116 insertions, 2 deletions
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 7eeb6c2a2f9c..2f750c770bf2 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h | |||
@@ -373,4 +373,12 @@ int kvm_vgic_setup_default_irq_routing(struct kvm *kvm); | |||
373 | 373 | ||
374 | int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner); | 374 | int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner); |
375 | 375 | ||
376 | struct kvm_kernel_irq_routing_entry; | ||
377 | |||
378 | int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int irq, | ||
379 | struct kvm_kernel_irq_routing_entry *irq_entry); | ||
380 | |||
381 | int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int irq, | ||
382 | struct kvm_kernel_irq_routing_entry *irq_entry); | ||
383 | |||
376 | #endif /* __KVM_ARM_VGIC_H */ | 384 | #endif /* __KVM_ARM_VGIC_H */ |
diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index e1e947fe9bc2..34a15c0c65ab 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c | |||
@@ -1471,7 +1471,8 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons, | |||
1471 | struct kvm_kernel_irqfd *irqfd = | 1471 | struct kvm_kernel_irqfd *irqfd = |
1472 | container_of(cons, struct kvm_kernel_irqfd, consumer); | 1472 | container_of(cons, struct kvm_kernel_irqfd, consumer); |
1473 | 1473 | ||
1474 | return 0; | 1474 | return kvm_vgic_v4_set_forwarding(irqfd->kvm, prod->irq, |
1475 | &irqfd->irq_entry); | ||
1475 | } | 1476 | } |
1476 | void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, | 1477 | void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, |
1477 | struct irq_bypass_producer *prod) | 1478 | struct irq_bypass_producer *prod) |
@@ -1479,7 +1480,8 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, | |||
1479 | struct kvm_kernel_irqfd *irqfd = | 1480 | struct kvm_kernel_irqfd *irqfd = |
1480 | container_of(cons, struct kvm_kernel_irqfd, consumer); | 1481 | container_of(cons, struct kvm_kernel_irqfd, consumer); |
1481 | 1482 | ||
1482 | return; | 1483 | kvm_vgic_v4_unset_forwarding(irqfd->kvm, prod->irq, |
1484 | &irqfd->irq_entry); | ||
1483 | } | 1485 | } |
1484 | 1486 | ||
1485 | void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *cons) | 1487 | void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *cons) |
diff --git a/virt/kvm/arm/vgic/vgic-v4.c b/virt/kvm/arm/vgic/vgic-v4.c index c794f0cef09e..2edfe23c8238 100644 --- a/virt/kvm/arm/vgic/vgic-v4.c +++ b/virt/kvm/arm/vgic/vgic-v4.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/irqdomain.h> | 19 | #include <linux/irqdomain.h> |
20 | #include <linux/kvm_host.h> | 20 | #include <linux/kvm_host.h> |
21 | #include <linux/irqchip/arm-gic-v3.h> | ||
21 | 22 | ||
22 | #include "vgic.h" | 23 | #include "vgic.h" |
23 | 24 | ||
@@ -81,3 +82,106 @@ void vgic_v4_teardown(struct kvm *kvm) | |||
81 | its_vm->nr_vpes = 0; | 82 | its_vm->nr_vpes = 0; |
82 | its_vm->vpes = NULL; | 83 | its_vm->vpes = NULL; |
83 | } | 84 | } |
85 | |||
86 | static struct vgic_its *vgic_get_its(struct kvm *kvm, | ||
87 | struct kvm_kernel_irq_routing_entry *irq_entry) | ||
88 | { | ||
89 | struct kvm_msi msi = (struct kvm_msi) { | ||
90 | .address_lo = irq_entry->msi.address_lo, | ||
91 | .address_hi = irq_entry->msi.address_hi, | ||
92 | .data = irq_entry->msi.data, | ||
93 | .flags = irq_entry->msi.flags, | ||
94 | .devid = irq_entry->msi.devid, | ||
95 | }; | ||
96 | |||
97 | return vgic_msi_to_its(kvm, &msi); | ||
98 | } | ||
99 | |||
100 | int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int virq, | ||
101 | struct kvm_kernel_irq_routing_entry *irq_entry) | ||
102 | { | ||
103 | struct vgic_its *its; | ||
104 | struct vgic_irq *irq; | ||
105 | struct its_vlpi_map map; | ||
106 | int ret; | ||
107 | |||
108 | if (!vgic_supports_direct_msis(kvm)) | ||
109 | return 0; | ||
110 | |||
111 | /* | ||
112 | * Get the ITS, and escape early on error (not a valid | ||
113 | * doorbell for any of our vITSs). | ||
114 | */ | ||
115 | its = vgic_get_its(kvm, irq_entry); | ||
116 | if (IS_ERR(its)) | ||
117 | return 0; | ||
118 | |||
119 | mutex_lock(&its->its_lock); | ||
120 | |||
121 | /* Perform then actual DevID/EventID -> LPI translation. */ | ||
122 | ret = vgic_its_resolve_lpi(kvm, its, irq_entry->msi.devid, | ||
123 | irq_entry->msi.data, &irq); | ||
124 | if (ret) | ||
125 | goto out; | ||
126 | |||
127 | /* | ||
128 | * Emit the mapping request. If it fails, the ITS probably | ||
129 | * isn't v4 compatible, so let's silently bail out. Holding | ||
130 | * the ITS lock should ensure that nothing can modify the | ||
131 | * target vcpu. | ||
132 | */ | ||
133 | map = (struct its_vlpi_map) { | ||
134 | .vm = &kvm->arch.vgic.its_vm, | ||
135 | .vpe = &irq->target_vcpu->arch.vgic_cpu.vgic_v3.its_vpe, | ||
136 | .vintid = irq->intid, | ||
137 | .properties = ((irq->priority & 0xfc) | | ||
138 | (irq->enabled ? LPI_PROP_ENABLED : 0) | | ||
139 | LPI_PROP_GROUP1), | ||
140 | .db_enabled = true, | ||
141 | }; | ||
142 | |||
143 | ret = its_map_vlpi(virq, &map); | ||
144 | if (ret) | ||
145 | goto out; | ||
146 | |||
147 | irq->hw = true; | ||
148 | irq->host_irq = virq; | ||
149 | |||
150 | out: | ||
151 | mutex_unlock(&its->its_lock); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int virq, | ||
156 | struct kvm_kernel_irq_routing_entry *irq_entry) | ||
157 | { | ||
158 | struct vgic_its *its; | ||
159 | struct vgic_irq *irq; | ||
160 | int ret; | ||
161 | |||
162 | if (!vgic_supports_direct_msis(kvm)) | ||
163 | return 0; | ||
164 | |||
165 | /* | ||
166 | * Get the ITS, and escape early on error (not a valid | ||
167 | * doorbell for any of our vITSs). | ||
168 | */ | ||
169 | its = vgic_get_its(kvm, irq_entry); | ||
170 | if (IS_ERR(its)) | ||
171 | return 0; | ||
172 | |||
173 | mutex_lock(&its->its_lock); | ||
174 | |||
175 | ret = vgic_its_resolve_lpi(kvm, its, irq_entry->msi.devid, | ||
176 | irq_entry->msi.data, &irq); | ||
177 | if (ret) | ||
178 | goto out; | ||
179 | |||
180 | WARN_ON(!(irq->hw && irq->host_irq == virq)); | ||
181 | irq->hw = false; | ||
182 | ret = its_unmap_vlpi(virq); | ||
183 | |||
184 | out: | ||
185 | mutex_unlock(&its->its_lock); | ||
186 | return ret; | ||
187 | } | ||