]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - virt/kvm/arm/vgic/vgic-v4.c
KVM: arm/arm64: GICv4: Use pending_last as a scheduling hint
[mirror_ubuntu-bionic-kernel.git] / virt / kvm / arm / vgic / vgic-v4.c
CommitLineData
74fe55dc
MZ
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>
196b1364 21#include <linux/irqchip/arm-gic-v3.h>
74fe55dc
MZ
22
23#include "vgic.h"
24
25/**
26 * vgic_v4_init - Initialize the GICv4 data structures
27 * @kvm: Pointer to the VM being initialized
28 *
29 * We may be called each time a vITS is created, or when the
30 * vgic is initialized. This relies on kvm->lock to be
31 * held. In both cases, the number of vcpus should now be
32 * fixed.
33 */
34int vgic_v4_init(struct kvm *kvm)
35{
36 struct vgic_dist *dist = &kvm->arch.vgic;
37 struct kvm_vcpu *vcpu;
38 int i, nr_vcpus, ret;
39
40 if (dist->its_vm.vpes)
41 return 0;
42
43 nr_vcpus = atomic_read(&kvm->online_vcpus);
44
45 dist->its_vm.vpes = kzalloc(sizeof(*dist->its_vm.vpes) * nr_vcpus,
46 GFP_KERNEL);
47 if (!dist->its_vm.vpes)
48 return -ENOMEM;
49
50 dist->its_vm.nr_vpes = nr_vcpus;
51
52 kvm_for_each_vcpu(i, vcpu, kvm)
53 dist->its_vm.vpes[i] = &vcpu->arch.vgic_cpu.vgic_v3.its_vpe;
54
55 ret = its_alloc_vcpu_irqs(&dist->its_vm);
56 if (ret < 0) {
57 kvm_err("VPE IRQ allocation failure\n");
58 kfree(dist->its_vm.vpes);
59 dist->its_vm.nr_vpes = 0;
60 dist->its_vm.vpes = NULL;
61 return ret;
62 }
63
64 return ret;
65}
66
67/**
68 * vgic_v4_teardown - Free the GICv4 data structures
69 * @kvm: Pointer to the VM being destroyed
70 *
71 * Relies on kvm->lock to be held.
72 */
73void vgic_v4_teardown(struct kvm *kvm)
74{
75 struct its_vm *its_vm = &kvm->arch.vgic.its_vm;
76
77 if (!its_vm->vpes)
78 return;
79
80 its_free_vcpu_irqs(its_vm);
81 kfree(its_vm->vpes);
82 its_vm->nr_vpes = 0;
83 its_vm->vpes = NULL;
84}
196b1364
MZ
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}