Skip to content

Commit 03b3d00

Browse files
author
Marc Zyngier
committed
KVM: arm64: vgic: Allocate private interrupts on demand
Private interrupts are currently part of the CPU interface structure that is part of each and every vcpu we create. Currently, we have 32 of them per vcpu, resulting in a per-vcpu array that is just shy of 4kB. On its own, that's no big deal, but it gets in the way of other things: - each vcpu gets mapped at EL2 on nVHE/hVHE configurations. This requires memory that is physically contiguous. However, the EL2 code has no purpose looking at the interrupt structures and could do without them being mapped. - supporting features such as EPPIs, which extend the number of private interrupts past the 32 limit would make the array even larger, even for VMs that do not use the EPPI feature. Address these issues by moving the private interrupt array outside of the vcpu, and replace it with a simple pointer. We take this opportunity to make it obvious what gets initialised when, as that path was remarkably opaque, and tighten the locking. Reviewed-by: Oliver Upton <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Marc Zyngier <[email protected]>
1 parent e8533e5 commit 03b3d00

File tree

2 files changed

+64
-20
lines changed

2 files changed

+64
-20
lines changed

arch/arm64/kvm/vgic/vgic-init.c

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -182,27 +182,22 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
182182
return 0;
183183
}
184184

185-
/**
186-
* kvm_vgic_vcpu_init() - Initialize static VGIC VCPU data
187-
* structures and register VCPU-specific KVM iodevs
188-
*
189-
* @vcpu: pointer to the VCPU being created and initialized
190-
*
191-
* Only do initialization, but do not actually enable the
192-
* VGIC CPU interface
193-
*/
194-
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
185+
static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu)
195186
{
196187
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
197-
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
198-
int ret = 0;
199188
int i;
200189

201-
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
190+
lockdep_assert_held(&vcpu->kvm->arch.config_lock);
202191

203-
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
204-
raw_spin_lock_init(&vgic_cpu->ap_list_lock);
205-
atomic_set(&vgic_cpu->vgic_v3.its_vpe.vlpi_count, 0);
192+
if (vgic_cpu->private_irqs)
193+
return 0;
194+
195+
vgic_cpu->private_irqs = kcalloc(VGIC_NR_PRIVATE_IRQS,
196+
sizeof(struct vgic_irq),
197+
GFP_KERNEL_ACCOUNT);
198+
199+
if (!vgic_cpu->private_irqs)
200+
return -ENOMEM;
206201

207202
/*
208203
* Enable and configure all SGIs to be edge-triggered and
@@ -227,9 +222,48 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
227222
}
228223
}
229224

225+
return 0;
226+
}
227+
228+
static int vgic_allocate_private_irqs(struct kvm_vcpu *vcpu)
229+
{
230+
int ret;
231+
232+
mutex_lock(&vcpu->kvm->arch.config_lock);
233+
ret = vgic_allocate_private_irqs_locked(vcpu);
234+
mutex_unlock(&vcpu->kvm->arch.config_lock);
235+
236+
return ret;
237+
}
238+
239+
/**
240+
* kvm_vgic_vcpu_init() - Initialize static VGIC VCPU data
241+
* structures and register VCPU-specific KVM iodevs
242+
*
243+
* @vcpu: pointer to the VCPU being created and initialized
244+
*
245+
* Only do initialization, but do not actually enable the
246+
* VGIC CPU interface
247+
*/
248+
int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
249+
{
250+
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
251+
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
252+
int ret = 0;
253+
254+
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;
255+
256+
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
257+
raw_spin_lock_init(&vgic_cpu->ap_list_lock);
258+
atomic_set(&vgic_cpu->vgic_v3.its_vpe.vlpi_count, 0);
259+
230260
if (!irqchip_in_kernel(vcpu->kvm))
231261
return 0;
232262

263+
ret = vgic_allocate_private_irqs(vcpu);
264+
if (ret)
265+
return ret;
266+
233267
/*
234268
* If we are creating a VCPU with a GICv3 we must also register the
235269
* KVM io device for the redistributor that belongs to this VCPU.
@@ -285,10 +319,13 @@ int vgic_init(struct kvm *kvm)
285319

286320
/* Initialize groups on CPUs created before the VGIC type was known */
287321
kvm_for_each_vcpu(idx, vcpu, kvm) {
288-
struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
322+
ret = vgic_allocate_private_irqs_locked(vcpu);
323+
if (ret)
324+
goto out;
289325

290326
for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
291-
struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
327+
struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, i);
328+
292329
switch (dist->vgic_model) {
293330
case KVM_DEV_TYPE_ARM_VGIC_V3:
294331
irq->group = 1;
@@ -300,8 +337,12 @@ int vgic_init(struct kvm *kvm)
300337
break;
301338
default:
302339
ret = -EINVAL;
303-
goto out;
304340
}
341+
342+
vgic_put_irq(kvm, irq);
343+
344+
if (ret)
345+
goto out;
305346
}
306347
}
307348

@@ -381,6 +422,9 @@ static void __kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
381422
vgic_flush_pending_lpis(vcpu);
382423

383424
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
425+
kfree(vgic_cpu->private_irqs);
426+
vgic_cpu->private_irqs = NULL;
427+
384428
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
385429
vgic_unregister_redist_iodev(vcpu);
386430
vgic_cpu->rd_iodev.base_addr = VGIC_ADDR_UNDEF;

include/kvm/arm_vgic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ struct vgic_cpu {
330330
struct vgic_v3_cpu_if vgic_v3;
331331
};
332332

333-
struct vgic_irq private_irqs[VGIC_NR_PRIVATE_IRQS];
333+
struct vgic_irq *private_irqs;
334334

335335
raw_spinlock_t ap_list_lock; /* Protects the ap_list */
336336

0 commit comments

Comments
 (0)