Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: arm64: GICv3: Handle LR overflow when EOImode==0

Now that we can identify interrupts that have not made it into the LRs,
it becomes relatively easy to use EOIcount to walk the overflow list.

What is a bit odd is that we compute a fake LR for the original
state of the interrupt, clear the active bit, and feed into the existing
logic for processing. In a way, this is what would have happened if
the interrupt was in an LR.

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-28-maz@kernel.org
Signed-off-by: Oliver Upton <oupton@kernel.org>

authored by

Marc Zyngier and committed by
Oliver Upton
3cfd59f8 a69e2d6f

+46
+46
arch/arm64/kvm/vgic/vgic-v3.c
··· 112 112 vgic_put_irq(vcpu->kvm, irq); 113 113 } 114 114 115 + static u64 vgic_v3_compute_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq); 116 + 117 + static void vgic_v3_deactivate_phys(u32 intid) 118 + { 119 + if (cpus_have_final_cap(ARM64_HAS_GICV5_LEGACY)) 120 + gic_insn(intid | FIELD_PREP(GICV5_GIC_CDDI_TYPE_MASK, 1), CDDI); 121 + else 122 + gic_write_dir(intid); 123 + } 124 + 115 125 void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu) 116 126 { 117 127 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu; 118 128 struct vgic_v3_cpu_if *cpuif = &vgic_cpu->vgic_v3; 129 + u32 eoicount = FIELD_GET(ICH_HCR_EL2_EOIcount, cpuif->vgic_hcr); 130 + struct vgic_irq *irq; 119 131 120 132 DEBUG_SPINLOCK_BUG_ON(!irqs_disabled()); 121 133 122 134 for (int lr = 0; lr < cpuif->used_lrs; lr++) 123 135 vgic_v3_fold_lr(vcpu, cpuif->vgic_lr[lr]); 136 + 137 + /* 138 + * EOIMode=0: use EOIcount to emulate deactivation. We are 139 + * guaranteed to deactivate in reverse order of the activation, so 140 + * just pick one active interrupt after the other in the ap_list, 141 + * and replay the deactivation as if the CPU was doing it. We also 142 + * rely on priority drop to have taken place, and the list to be 143 + * sorted by priority. 144 + */ 145 + list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) { 146 + u64 lr; 147 + 148 + /* 149 + * I would have loved to write this using a scoped_guard(), 150 + * but using 'continue' here is a total train wreck. 151 + */ 152 + if (!eoicount) { 153 + break; 154 + } else { 155 + guard(raw_spinlock)(&irq->irq_lock); 156 + 157 + if (!(likely(vgic_target_oracle(irq) == vcpu) && 158 + irq->active)) 159 + continue; 160 + 161 + lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT; 162 + } 163 + 164 + if (lr & ICH_LR_HW) 165 + vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr)); 166 + 167 + vgic_v3_fold_lr(vcpu, lr); 168 + eoicount--; 169 + } 124 170 125 171 cpuif->used_lrs = 0; 126 172 }