]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
KVM: arm64: GICv2: Extract LR computing primitive
authorMarc Zyngier <maz@kernel.org>
Thu, 20 Nov 2025 17:25:08 +0000 (17:25 +0000)
committerOliver Upton <oupton@kernel.org>
Mon, 24 Nov 2025 22:29:12 +0000 (14:29 -0800)
Split vgic_v2_populate_lr() into two helpers, so that we have another
primitive that computes the LR from a vgic_irq, but doesn't update
anything in the shadow structure.

Tested-by: Fuad Tabba <tabba@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Mark Brown <broonie@kernel.org>
Link: https://msgid.link/20251120172540.2267180-19-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>
arch/arm64/kvm/vgic/vgic-v2.c

index fb8efdd4196b192c62001aee7634c40bc66a7a13..5a2165a8d22c031b2b2f79344791f189eede83ac 100644 (file)
@@ -107,18 +107,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
        cpuif->used_lrs = 0;
 }
 
-/*
- * Populates the particular LR with the state of a given IRQ:
- * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
- * - for a level sensitive IRQ the pending state value is unchanged;
- *   it is dictated directly by the input level
- *
- * If @irq describes an SGI with multiple sources, we choose the
- * lowest-numbered source VCPU and clear that bit in the source bitmap.
- *
- * The irq_lock must be held by the caller.
- */
-void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+static u32 vgic_v2_compute_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq)
 {
        u32 val = irq->intid;
        bool allow_pending = true;
@@ -164,22 +153,52 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
        if (allow_pending && irq_is_pending(irq)) {
                val |= GICH_LR_PENDING_BIT;
 
-               if (irq->config == VGIC_CONFIG_EDGE)
-                       irq->pending_latch = false;
-
                if (vgic_irq_is_sgi(irq->intid)) {
                        u32 src = ffs(irq->source);
 
                        if (WARN_RATELIMIT(!src, "No SGI source for INTID %d\n",
                                           irq->intid))
-                               return;
+                               return 0;
 
                        val |= (src - 1) << GICH_LR_PHYSID_CPUID_SHIFT;
-                       irq->source &= ~(1 << (src - 1));
-                       if (irq->source) {
-                               irq->pending_latch = true;
+                       if (irq->source & ~BIT(src - 1))
                                val |= GICH_LR_EOI;
-                       }
+               }
+       }
+
+       /* The GICv2 LR only holds five bits of priority. */
+       val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
+
+       return val;
+}
+
+/*
+ * Populates the particular LR with the state of a given IRQ:
+ * - for an edge sensitive IRQ the pending state is cleared in struct vgic_irq
+ * - for a level sensitive IRQ the pending state value is unchanged;
+ *   it is dictated directly by the input level
+ *
+ * If @irq describes an SGI with multiple sources, we choose the
+ * lowest-numbered source VCPU and clear that bit in the source bitmap.
+ *
+ * The irq_lock must be held by the caller.
+ */
+void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
+{
+       u32 val = vgic_v2_compute_lr(vcpu, irq);
+
+       vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
+
+       if (val & GICH_LR_PENDING_BIT) {
+               if (irq->config == VGIC_CONFIG_EDGE)
+                       irq->pending_latch = false;
+
+               if (vgic_irq_is_sgi(irq->intid)) {
+                       u32 src = ffs(irq->source);
+
+                       irq->source &= ~BIT(src - 1);
+                       if (irq->source)
+                               irq->pending_latch = true;
                }
        }
 
@@ -196,8 +215,6 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
        val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
 
        irq->on_lr = true;
-
-       vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = val;
 }
 
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr)