]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: gic-v5: Support GICv5 interrupts with KVM_IRQ_LINE
authorSascha Bischoff <Sascha.Bischoff@arm.com>
Thu, 19 Mar 2026 15:56:43 +0000 (15:56 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 19 Mar 2026 18:21:28 +0000 (18:21 +0000)
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 <timothy.hayes@arm.com>
Signed-off-by: Timothy Hayes <timothy.hayes@arm.com>
Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Link: https://patch.msgid.link/20260319154937.3619520-28-sascha.bischoff@arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
Documentation/virt/kvm/api.rst
arch/arm64/kvm/arm.c
arch/arm64/kvm/vgic/vgic.c

index 032516783e9622f37dd3ad3ffffe6b9c04e6a302..03d87d9b97d9419d4301537da9fad78d42500906 100644 (file)
@@ -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)
 
index f68c4036afebdd89633505a9eb45451297269130..8577d7dd4d1ef5cad6a4b69e33ba5cd499220c5a 100644 (file)
@@ -45,6 +45,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"
 
@@ -1479,16 +1482,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 = vgic_v5_make_ppi(irq_num);
+               } 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 = vgic_v5_make_spi(irq_num);
+               } else {
+                       if (irq_num < VGIC_NR_PRIVATE_IRQS)
+                               return -EINVAL;
+               }
 
                return kvm_vgic_inject_irq(kvm, NULL, irq_num, level, NULL);
        }
index 9ac0ff60aa8a5d8f4431529b8c6ce5c3722bf8ec..1e9fe8764584de17c295f8b4fbca01617f8a4716 100644 (file)
@@ -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)) {