aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-10-27 10:28:39 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2017-11-10 03:28:52 -0500
commit196b136498b35f1cd787b84465f235e69dbc757c (patch)
tree23890d9f31732cfb18203945c3bcb80ca52699fb
parent74fe55dc9ab77142e3c4783ecc5b87d494164452 (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.h8
-rw-r--r--virt/kvm/arm/arm.c6
-rw-r--r--virt/kvm/arm/vgic/vgic-v4.c104
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
374int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner); 374int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner);
375 375
376struct kvm_kernel_irq_routing_entry;
377
378int kvm_vgic_v4_set_forwarding(struct kvm *kvm, int irq,
379 struct kvm_kernel_irq_routing_entry *irq_entry);
380
381int 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}
1476void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons, 1477void 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
1485void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *cons) 1487void 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
86static 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
100int 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
150out:
151 mutex_unlock(&its->its_lock);
152 return ret;
153}
154
155int 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
184out:
185 mutex_unlock(&its->its_lock);
186 return ret;
187}