summaryrefslogtreecommitdiffstats
path: root/virt
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2017-10-27 10:28:48 -0400
committerChristoffer Dall <christoffer.dall@linaro.org>2017-11-10 03:42:59 -0500
commitbdb2d2ccac65dfee0db8fa4a8247df788a942439 (patch)
tree66518ebbcad8614c4d36d29ac10b0b4dd52590ed /virt
parentc971968071d3ec5e8605f9da9e867441e2edf000 (diff)
KVM: arm/arm64: GICv4: Add doorbell interrupt handling
When a vPE is not running, a VLPI being made pending results in a doorbell interrupt being delivered. Let's handle this interrupt and update the pending_last flag that indicates that VLPIs are pending. The corresponding vcpu is also kicked into action. Special care is taken to prevent the doorbell from being enabled at request time (this is controlled separately), and to make the disabling on the interrupt non-lazy. Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Reviewed-by: Eric Auger <eric.auger@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/arm/vgic/vgic-v4.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-v4.c b/virt/kvm/arm/vgic/vgic-v4.c
index 2edfe23c8238..796e00c77903 100644
--- a/virt/kvm/arm/vgic/vgic-v4.c
+++ b/virt/kvm/arm/vgic/vgic-v4.c
@@ -16,12 +16,24 @@
16 */ 16 */
17 17
18#include <linux/interrupt.h> 18#include <linux/interrupt.h>
19#include <linux/irq.h>
19#include <linux/irqdomain.h> 20#include <linux/irqdomain.h>
20#include <linux/kvm_host.h> 21#include <linux/kvm_host.h>
21#include <linux/irqchip/arm-gic-v3.h> 22#include <linux/irqchip/arm-gic-v3.h>
22 23
23#include "vgic.h" 24#include "vgic.h"
24 25
26static irqreturn_t vgic_v4_doorbell_handler(int irq, void *info)
27{
28 struct kvm_vcpu *vcpu = info;
29
30 vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last = true;
31 kvm_make_request(KVM_REQ_IRQ_PENDING, vcpu);
32 kvm_vcpu_kick(vcpu);
33
34 return IRQ_HANDLED;
35}
36
25/** 37/**
26 * vgic_v4_init - Initialize the GICv4 data structures 38 * vgic_v4_init - Initialize the GICv4 data structures
27 * @kvm: Pointer to the VM being initialized 39 * @kvm: Pointer to the VM being initialized
@@ -61,6 +73,33 @@ int vgic_v4_init(struct kvm *kvm)
61 return ret; 73 return ret;
62 } 74 }
63 75
76 kvm_for_each_vcpu(i, vcpu, kvm) {
77 int irq = dist->its_vm.vpes[i]->irq;
78
79 /*
80 * Don't automatically enable the doorbell, as we're
81 * flipping it back and forth when the vcpu gets
82 * blocked. Also disable the lazy disabling, as the
83 * doorbell could kick us out of the guest too
84 * early...
85 */
86 irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
87 ret = request_irq(irq, vgic_v4_doorbell_handler,
88 0, "vcpu", vcpu);
89 if (ret) {
90 kvm_err("failed to allocate vcpu IRQ%d\n", irq);
91 /*
92 * Trick: adjust the number of vpes so we know
93 * how many to nuke on teardown...
94 */
95 dist->its_vm.nr_vpes = i;
96 break;
97 }
98 }
99
100 if (ret)
101 vgic_v4_teardown(kvm);
102
64 return ret; 103 return ret;
65} 104}
66 105
@@ -73,10 +112,19 @@ int vgic_v4_init(struct kvm *kvm)
73void vgic_v4_teardown(struct kvm *kvm) 112void vgic_v4_teardown(struct kvm *kvm)
74{ 113{
75 struct its_vm *its_vm = &kvm->arch.vgic.its_vm; 114 struct its_vm *its_vm = &kvm->arch.vgic.its_vm;
115 int i;
76 116
77 if (!its_vm->vpes) 117 if (!its_vm->vpes)
78 return; 118 return;
79 119
120 for (i = 0; i < its_vm->nr_vpes; i++) {
121 struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, i);
122 int irq = its_vm->vpes[i]->irq;
123
124 irq_clear_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);
125 free_irq(irq, vcpu);
126 }
127
80 its_free_vcpu_irqs(its_vm); 128 its_free_vcpu_irqs(its_vm);
81 kfree(its_vm->vpes); 129 kfree(its_vm->vpes);
82 its_vm->nr_vpes = 0; 130 its_vm->nr_vpes = 0;