diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/arm/vgic/vgic-init.c | 9 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-its.c | 8 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-v4.c | 83 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic.h | 2 |
4 files changed, 102 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c index 5801261f3add..40be908da238 100644 --- a/virt/kvm/arm/vgic/vgic-init.c +++ b/virt/kvm/arm/vgic/vgic-init.c | |||
@@ -285,6 +285,12 @@ int vgic_init(struct kvm *kvm) | |||
285 | if (ret) | 285 | if (ret) |
286 | goto out; | 286 | goto out; |
287 | 287 | ||
288 | if (vgic_supports_direct_msis(kvm)) { | ||
289 | ret = vgic_v4_init(kvm); | ||
290 | if (ret) | ||
291 | goto out; | ||
292 | } | ||
293 | |||
288 | kvm_for_each_vcpu(i, vcpu, kvm) | 294 | kvm_for_each_vcpu(i, vcpu, kvm) |
289 | kvm_vgic_vcpu_enable(vcpu); | 295 | kvm_vgic_vcpu_enable(vcpu); |
290 | 296 | ||
@@ -320,6 +326,9 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm) | |||
320 | 326 | ||
321 | kfree(dist->spis); | 327 | kfree(dist->spis); |
322 | dist->nr_spis = 0; | 328 | dist->nr_spis = 0; |
329 | |||
330 | if (vgic_supports_direct_msis(kvm)) | ||
331 | vgic_v4_teardown(kvm); | ||
323 | } | 332 | } |
324 | 333 | ||
325 | void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) | 334 | void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu) |
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index 09accdfed189..54f81eb24a07 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c | |||
@@ -1638,6 +1638,14 @@ static int vgic_its_create(struct kvm_device *dev, u32 type) | |||
1638 | if (!its) | 1638 | if (!its) |
1639 | return -ENOMEM; | 1639 | return -ENOMEM; |
1640 | 1640 | ||
1641 | if (vgic_initialized(dev->kvm)) { | ||
1642 | int ret = vgic_v4_init(dev->kvm); | ||
1643 | if (ret) { | ||
1644 | kfree(its); | ||
1645 | return ret; | ||
1646 | } | ||
1647 | } | ||
1648 | |||
1641 | mutex_init(&its->its_lock); | 1649 | mutex_init(&its->its_lock); |
1642 | mutex_init(&its->cmd_lock); | 1650 | mutex_init(&its->cmd_lock); |
1643 | 1651 | ||
diff --git a/virt/kvm/arm/vgic/vgic-v4.c b/virt/kvm/arm/vgic/vgic-v4.c new file mode 100644 index 000000000000..c794f0cef09e --- /dev/null +++ b/virt/kvm/arm/vgic/vgic-v4.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 ARM Ltd. | ||
3 | * Author: Marc Zyngier <marc.zyngier@arm.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irqdomain.h> | ||
20 | #include <linux/kvm_host.h> | ||
21 | |||
22 | #include "vgic.h" | ||
23 | |||
24 | /** | ||
25 | * vgic_v4_init - Initialize the GICv4 data structures | ||
26 | * @kvm: Pointer to the VM being initialized | ||
27 | * | ||
28 | * We may be called each time a vITS is created, or when the | ||
29 | * vgic is initialized. This relies on kvm->lock to be | ||
30 | * held. In both cases, the number of vcpus should now be | ||
31 | * fixed. | ||
32 | */ | ||
33 | int vgic_v4_init(struct kvm *kvm) | ||
34 | { | ||
35 | struct vgic_dist *dist = &kvm->arch.vgic; | ||
36 | struct kvm_vcpu *vcpu; | ||
37 | int i, nr_vcpus, ret; | ||
38 | |||
39 | if (dist->its_vm.vpes) | ||
40 | return 0; | ||
41 | |||
42 | nr_vcpus = atomic_read(&kvm->online_vcpus); | ||
43 | |||
44 | dist->its_vm.vpes = kzalloc(sizeof(*dist->its_vm.vpes) * nr_vcpus, | ||
45 | GFP_KERNEL); | ||
46 | if (!dist->its_vm.vpes) | ||
47 | return -ENOMEM; | ||
48 | |||
49 | dist->its_vm.nr_vpes = nr_vcpus; | ||
50 | |||
51 | kvm_for_each_vcpu(i, vcpu, kvm) | ||
52 | dist->its_vm.vpes[i] = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe; | ||
53 | |||
54 | ret = its_alloc_vcpu_irqs(&dist->its_vm); | ||
55 | if (ret < 0) { | ||
56 | kvm_err("VPE IRQ allocation failure\n"); | ||
57 | kfree(dist->its_vm.vpes); | ||
58 | dist->its_vm.nr_vpes = 0; | ||
59 | dist->its_vm.vpes = NULL; | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | return ret; | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * vgic_v4_teardown - Free the GICv4 data structures | ||
68 | * @kvm: Pointer to the VM being destroyed | ||
69 | * | ||
70 | * Relies on kvm->lock to be held. | ||
71 | */ | ||
72 | void vgic_v4_teardown(struct kvm *kvm) | ||
73 | { | ||
74 | struct its_vm *its_vm = &kvm->arch.vgic.its_vm; | ||
75 | |||
76 | if (!its_vm->vpes) | ||
77 | return; | ||
78 | |||
79 | its_free_vcpu_irqs(its_vm); | ||
80 | kfree(its_vm->vpes); | ||
81 | its_vm->nr_vpes = 0; | ||
82 | its_vm->vpes = NULL; | ||
83 | } | ||
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h index 67509b203cf5..bf03a9648fbb 100644 --- a/virt/kvm/arm/vgic/vgic.h +++ b/virt/kvm/arm/vgic/vgic.h | |||
@@ -242,5 +242,7 @@ int vgic_its_resolve_lpi(struct kvm *kvm, struct vgic_its *its, | |||
242 | struct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi); | 242 | struct vgic_its *vgic_msi_to_its(struct kvm *kvm, struct kvm_msi *msi); |
243 | 243 | ||
244 | bool vgic_supports_direct_msis(struct kvm *kvm); | 244 | bool vgic_supports_direct_msis(struct kvm *kvm); |
245 | int vgic_v4_init(struct kvm *kvm); | ||
246 | void vgic_v4_teardown(struct kvm *kvm); | ||
245 | 247 | ||
246 | #endif | 248 | #endif |