[PATCH 24/43] KVM: arm64: gic-v5: Call IRS init/teardown from vgic_v5 init/teardown

Sascha Bischoff
2026-04-27T16:15:21Z

As has been the case thus far with the GICv5 KVM implementation, it is
only possible to support PPIs without both interaction with the host
IRS and providing an emulated IRS for the guest to interact with. Once
an emulated IRS is added, it becomes possible to support both SPIs and
LPIs in the guest, and hence it becomes possible to run something
real.

It makes little sense to allow VM creation with only PPI
support. Hence, as part of initialising or tearing down the GIC, also
do the same for the emulated IRS.

As of this change, GICv5 VMs support all three GICv5 interrupt types;
PPIs, SPIs, and LPIs.

Note that further work is required to properly support SPIs and LPIs,
but this change represents a bit step towards supporting a full guest
OS such as Linux, rather than just supporting simple PPI-based unit
tests.

Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
---
arch/arm64/kvm/vgic/vgic-init.c | 29 ++++++++++++++++++++++-------
arch/arm64/kvm/vgic/vgic-v5.c | 6 ++++++
include/kvm/arm_vgic.h | 1 +
3 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index 984908a271c8d..cea8e963ade66 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -182,14 +182,26 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
kvm->arch.vgic.nassgicap = system_supports_direct_sgis();

- /*
- * We now know that we have a GICv5. The Arch Timer PPI interrupts may
- * have been initialised at this stage, but will have done so assuming
- * that we have an older GIC, meaning that the IntIDs won't be
- * correct. We init them again, and this time they will be correct.
- */
- if (type == KVM_DEV_TYPE_ARM_VGIC_V5)
+ if (type == KVM_DEV_TYPE_ARM_VGIC_V5) {
+ /* Allocate a vIRS for GICv5 systems */
+ kvm->arch.vgic.vgic_v5_irs_data = kzalloc_obj(struct vgic_v5_irs,
+ GFP_KERNEL_ACCOUNT);
+ if (!kvm->arch.vgic.vgic_v5_irs_data) {
+ kvm->arch.vgic.vgic_model = 0;
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+
+ /*
+ * We now know that we have a GICv5. The Arch Timer PPI
+ * interrupts may have been initialised at this stage, but will
+ * have done so assuming that we have an older GIC, meaning that
+ * the IntIDs won't be correct. We init them again, and this
+ * time they will be correct.
+ */
kvm_timer_init_vm(kvm);
+ }

out_unlock:
mutex_unlock(&kvm->arch.config_lock);
@@ -461,6 +473,9 @@ int vgic_init(struct kvm *kvm)
return ret;
}
} else {
+ if (!dist->nr_spis)
+ dist->nr_spis = VGIC_V5_DEFAULT_NR_SPIS;
+
ret = vgic_v5_init(kvm);
if (ret)
return ret;
diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
index f12e96bc5fa21..86cfc08c557ba 100644
--- a/arch/arm64/kvm/vgic/vgic-v5.c
+++ b/arch/arm64/kvm/vgic/vgic-v5.c
@@ -867,6 +867,9 @@ int vgic_v5_init(struct kvm *kvm)
return ret;
}

+ /* Init IRS (and alloc SPI IST) */
+ ret = kvm_vgic_v5_irs_init(kvm, kvm->arch.vgic.nr_spis);
+
return ret;
}

@@ -877,6 +880,9 @@ void vgic_v5_teardown(struct kvm *kvm)
unsigned long i;
int rc;

+ kfree(dist->vgic_v5_irs_data);
+ dist->vgic_v5_irs_data = NULL;
+
/*
* If the VM's ID isn't valid, then we failed init very early. Nothing
* to do here.
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index f8ecd19acc06d..3a2dfbd5210f2 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -25,6 +25,7 @@
#define VGIC_V3_MAX_CPUS 512
#define VGIC_V2_MAX_CPUS 8
#define VGIC_NR_IRQS_LEGACY 256
+#define VGIC_V5_DEFAULT_NR_SPIS 32
#define VGIC_NR_SGIS 16
#define VGIC_NR_PPIS 16
#define VGIC_NR_PRIVATE_IRQS (VGIC_NR_SGIS + VGIC_NR_PPIS)
--
2.34.1