[PATCH v4 35/49] KVM: arm64: GICv3: nv: Plug L1 LR sync into deactivation primitive

Vishnu Pajjuri vishnu at os.amperecomputing.com
Mon Mar 30 04:51:51 PDT 2026


Hi Fuad Tabba,
    I'm trying to run nested VMs on Ampere platforms after this patch 
series(v6.19+) but nested VMs are not booting and triggering soft 
lockups on L0 and L0 hang. But just before this patch I could able to 
successfully boot the Nested VMs.

I bisected the failure to a single commit which is this patch which is 
causing the issue.

I would like to understand from you that did you observed anything like 
that?

Were you able to boot Nested VMs successfully after v6.19+?

LOG:
[  164.647367] Call trace:
[  164.647368]  smp_call_function_many_cond+0x334/0x7a0 (P)
[  164.647372]  smp_call_function_many+0x20/0x40
[  164.647374]  kvm_make_all_cpus_request+0xec/0x1b8
[  164.647377]  vgic_queue_irq_unlock+0x1c8/0x2c8
[  164.647380]  kvm_vgic_inject_irq+0x194/0x1e0
[  164.647381]  kvm_vm_ioctl_irq_line+0x170/0x400
[  164.647386]  kvm_vm_ioctl+0x7b8/0xc88
[  164.647389]  __arm64_sys_ioctl+0xb4/0x118
[  164.647393]  invoke_syscall+0x6c/0x100
[  164.647397]  el0_svc_common.constprop.0+0x48/0xf0
[  164.647398]  do_el0_svc+0x24/0x38
[  164.647400]  el0_svc+0x3c/0x170
[  164.647403]  el0t_64_sync_handler+0xa0/0xe8
[  164.647405]  el0t_64_sync+0x1b0/0x1b8



Regards,
-Vishnu.

On 20-11-2025 22:55, Marc Zyngier wrote:
> Pretty much like the rest of the LR handling, deactivation of an
> L2 interrupt gets reflected in the L1 LRs, and therefore must be
> propagated into the L1 shadow state if the interrupt is HW-bound.
> 
> Instead of directly handling the active state (which looks a bit
> off as it ignores locking and L1->L0 HW propagation), use the new
> deactivation primitive to perform the deactivation and deal with
> the required maintenance.
> 
> Tested-by: Fuad Tabba <tabba at google.com>
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>   arch/arm64/kvm/vgic/vgic-v3-nested.c | 19 +++++++++----------
>   1 file changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-v3-nested.c b/arch/arm64/kvm/vgic/vgic-v3-nested.c
> index 40f7a37e0685c..15e7033a7937e 100644
> --- a/arch/arm64/kvm/vgic/vgic-v3-nested.c
> +++ b/arch/arm64/kvm/vgic/vgic-v3-nested.c
> @@ -280,7 +280,6 @@ void vgic_v3_sync_nested(struct kvm_vcpu *vcpu)
>   
>   	for_each_set_bit(i, &shadow_if->lr_map, kvm_vgic_global_state.nr_lr) {
>   		u64 val, host_lr, lr;
> -		struct vgic_irq *irq;
>   
>   		host_lr = __gic_v3_get_lr(lr_map_idx_to_shadow_idx(shadow_if, i));
>   
> @@ -290,7 +289,14 @@ void vgic_v3_sync_nested(struct kvm_vcpu *vcpu)
>   		val |= host_lr & ICH_LR_STATE;
>   		__vcpu_assign_sys_reg(vcpu, ICH_LRN(i), val);
>   
> -		if (!(lr & ICH_LR_HW) || !(lr & ICH_LR_STATE))
> +		/*
> +		 * Deactivation of a HW interrupt: the LR must have the HW
> +		 * bit set, have been in a non-invalid state before the run,
> +		 * and now be in an invalid state. If any of that doesn't
> +		 * hold, we're done with this LR.
> +		 */
> +		if (!((lr & ICH_LR_HW) && (lr & ICH_LR_STATE) &&
> +		      !(host_lr & ICH_LR_STATE)))
>   			continue;
>   
>   		/*
> @@ -298,14 +304,7 @@ void vgic_v3_sync_nested(struct kvm_vcpu *vcpu)
>   		 * need to emulate the HW effect between the guest hypervisor
>   		 * and the nested guest.
>   		 */
> -		irq = vgic_get_vcpu_irq(vcpu, FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
> -		if (WARN_ON(!irq)) /* Shouldn't happen as we check on load */
> -			continue;
> -
> -		if (!(host_lr & ICH_LR_STATE))
> -			irq->active = false;
> -
> -		vgic_put_irq(vcpu->kvm, irq);
> +		vgic_v3_deactivate(vcpu, FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
>   	}
>   
>   	/* We need these to be synchronised to generate the MI */




More information about the linux-arm-kernel mailing list