[PATCH v2 20/36] KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5

Sascha Bischoff Sascha.Bischoff at arm.com
Fri Dec 19 07:52:42 PST 2025


Initialise the private interrupts (PPIs, only) for GICv5. This means
that a GICv5-style intid is generated (which encodes the PPI type in
the top bits) instead of the 0-based index that is used for older
GICs.

Additionally, set all of the GICv5 PPIs to use Level for the handling
mode, with the exception of the SW_PPI which uses Edge. This matches
the architecturally-defined set in the GICv5 specification (the CTIIRQ
handling mode is IMPDEF, so pick Level has been picked for that).

Signed-off-by: Sascha Bischoff <sascha.bischoff at arm.com>
---
 arch/arm64/kvm/vgic/vgic-init.c    | 41 +++++++++++++++++++++++-------
 include/linux/irqchip/arm-gic-v5.h |  2 ++
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index bcc2c79f7833c..03f45816464b0 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -263,13 +263,19 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	int i;
+	u32 num_private_irqs;
+
+	if (vgic_is_v5(vcpu->kvm))
+		num_private_irqs = VGIC_V5_NR_PRIVATE_IRQS;
+	else
+		num_private_irqs = VGIC_NR_PRIVATE_IRQS;
 
 	lockdep_assert_held(&vcpu->kvm->arch.config_lock);
 
 	if (vgic_cpu->private_irqs)
 		return 0;
 
-	vgic_cpu->private_irqs = kcalloc(VGIC_NR_PRIVATE_IRQS,
+	vgic_cpu->private_irqs = kcalloc(num_private_irqs,
 					 sizeof(struct vgic_irq),
 					 GFP_KERNEL_ACCOUNT);
 
@@ -280,22 +286,39 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 	 * Enable and configure all SGIs to be edge-triggered and
 	 * configure all PPIs as level-triggered.
 	 */
-	for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
+	for (i = 0; i < num_private_irqs; i++) {
 		struct vgic_irq *irq = &vgic_cpu->private_irqs[i];
 
 		INIT_LIST_HEAD(&irq->ap_list);
 		raw_spin_lock_init(&irq->irq_lock);
-		irq->intid = i;
 		irq->vcpu = NULL;
 		irq->target_vcpu = vcpu;
 		refcount_set(&irq->refcount, 0);
-		if (vgic_irq_is_sgi(i)) {
-			/* SGIs */
-			irq->enabled = 1;
-			irq->config = VGIC_CONFIG_EDGE;
+		if (!vgic_is_v5(vcpu->kvm)) {
+			irq->intid = i;
+			if (vgic_irq_is_sgi(i)) {
+				/* SGIs */
+				irq->enabled = 1;
+				irq->config = VGIC_CONFIG_EDGE;
+			} else {
+				/* PPIs */
+				irq->config = VGIC_CONFIG_LEVEL;
+			}
 		} else {
-			/* PPIs */
-			irq->config = VGIC_CONFIG_LEVEL;
+			irq->intid = i | FIELD_PREP(GICV5_HWIRQ_TYPE,
+						    GICV5_HWIRQ_TYPE_PPI);
+
+			/*
+			 * The only architected PPI that is Edge is
+			 * the SW PPI.
+			 */
+			if (irq->intid == GICV5_SW_PPI)
+				irq->config = VGIC_CONFIG_EDGE;
+			else
+				irq->config = VGIC_CONFIG_LEVEL;
+
+			/* Register the GICv5-specific PPI ops */
+			vgic_v5_set_ppi_ops(irq);
 		}
 
 		switch (type) {
diff --git a/include/linux/irqchip/arm-gic-v5.h b/include/linux/irqchip/arm-gic-v5.h
index d2780fc99c344..2ab7ec718aaea 100644
--- a/include/linux/irqchip/arm-gic-v5.h
+++ b/include/linux/irqchip/arm-gic-v5.h
@@ -13,6 +13,8 @@
 
 #define GICV5_IPIS_PER_CPU		MAX_IPI
 
+#define GICV5_SW_PPI			0x20000003
+
 /*
  * INTID handling
  */
-- 
2.34.1



More information about the linux-arm-kernel mailing list