[PATCH v4 23/36] KVM: arm64: gic-v5: Support GICv5 interrupts with KVM_IRQ_LINE
From: Sascha Bischoff <hidden>
Date: 2026-01-28 18:06:33
Also in:
kvm, kvmarm
Subsystem:
arm64 port (aarch64 architecture), documentation, kernel virtual machine (kvm), kernel virtual machine for arm64 (kvm/arm64), the rest · Maintainers:
Catalin Marinas, Will Deacon, Jonathan Corbet, Paolo Bonzini, Marc Zyngier, Oliver Upton, Linus Torvalds
Interrupts under GICv5 look quite different to those from older Arm GICs. Specifically, the type is encoded in the top bits of the interrupt ID. Extend KVM_IRQ_LINE to cope with GICv5 PPIs and SPIs. The requires subtly changing the KVM_IRQ_LINE API for GICv5 guests. For older Arm GICs, PPIs had to be in the range of 16-31, and SPIs had to be 32-1019, but this no longer holds true for GICv5. Instead, for a GICv5 guest support PPIs in the range of 0-127, and SPIs in the range 0-65535. The documentation is updated accordingly. The SPI range doesn't cover the full SPI range that a GICv5 system can potentially cope with (GICv5 provides up to 24-bits of SPI ID space, and we only have 16 bits to work with in KVM_IRQ_LINE). However, 65k SPIs is more than would be reasonably expected on systems for years to come. In order to use vgic_is_v5(), the kvm/arm_vgic.h header is added to kvm/arm.c. Note: As the GICv5 KVM implementation currently doesn't support injecting SPIs attempts to do so will fail. This restriction will by lifted as the GICv5 KVM support evolves. Co-authored-by: Timothy Hayes [off-list ref] Signed-off-by: Timothy Hayes <redacted> Signed-off-by: Sascha Bischoff <redacted> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com> --- Documentation/virt/kvm/api.rst | 6 ++++-- arch/arm64/kvm/arm.c | 22 +++++++++++++++++++--- arch/arm64/kvm/vgic/vgic.c | 4 ++++ 3 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 01a3abef8abb..460a5511ebce 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst@@ -907,10 +907,12 @@ The irq_type field has the following values: - KVM_ARM_IRQ_TYPE_CPU: out-of-kernel GIC: irq_id 0 is IRQ, irq_id 1 is FIQ - KVM_ARM_IRQ_TYPE_SPI: - in-kernel GIC: SPI, irq_id between 32 and 1019 (incl.) + in-kernel GICv2/GICv3: SPI, irq_id between 32 and 1019 (incl.) (the vcpu_index field is ignored) + in-kernel GICv5: SPI, irq_id between 0 and 65535 (incl.) - KVM_ARM_IRQ_TYPE_PPI: - in-kernel GIC: PPI, irq_id between 16 and 31 (incl.) + in-kernel GICv2/GICv3: PPI, irq_id between 16 and 31 (incl.) + in-kernel GICv5: PPI, irq_id between 0 and 127 (incl.) (The irq_id field thus corresponds nicely to the IRQ ID in the ARM GIC specs)
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index f9458409d50a..08e255cabdbc 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c@@ -44,6 +44,9 @@ #include <kvm/arm_hypercalls.h> #include <kvm/arm_pmu.h> #include <kvm/arm_psci.h> +#include <kvm/arm_vgic.h> + +#include <linux/irqchip/arm-gic-v5.h> #include "sys_regs.h"
@@ -1431,16 +1434,29 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level, if (!vcpu) return -EINVAL; - if (irq_num < VGIC_NR_SGIS || irq_num >= VGIC_NR_PRIVATE_IRQS) + if (vgic_is_v5(kvm)) { + if (irq_num >= VGIC_V5_NR_PRIVATE_IRQS) + return -EINVAL; + + /* Build a GICv5-style IntID here */ + irq_num |= FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI); + } else if (irq_num < VGIC_NR_SGIS || + irq_num >= VGIC_NR_PRIVATE_IRQS) { return -EINVAL; + } return kvm_vgic_inject_irq(kvm, vcpu, irq_num, level, NULL); case KVM_ARM_IRQ_TYPE_SPI: if (!irqchip_in_kernel(kvm)) return -ENXIO; - if (irq_num < VGIC_NR_PRIVATE_IRQS) - return -EINVAL; + if (vgic_is_v5(kvm)) { + /* Build a GICv5-style IntID here */ + irq_num |= FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_SPI); + } else { + if (irq_num < VGIC_NR_PRIVATE_IRQS) + return -EINVAL; + } return kvm_vgic_inject_irq(kvm, NULL, irq_num, level, NULL); }
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index cd45e5db03d4..58a3fc66f2ce 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c@@ -86,6 +86,10 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid) */ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid) { + /* Non-private IRQs are not yet implemented for GICv5 */ + if (vgic_is_v5(kvm)) + return NULL; + /* SPIs */ if (intid >= VGIC_NR_PRIVATE_IRQS && intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) {
--
2.34.1