Re: [PATCH] LoongArch: KVM: Set max used FPU type with FPU exception

From: Bibo Mao

Date: Tue Mar 24 2026 - 21:55:02 EST


another more proactive method is to enabled FPU type with max VM supported, rather than ever used.

It is more direct and simpler, FPU none --> LASX, no middle state FPU --> LASX or LSX --> LASX.

Regards
Bibo Mao

On 2026/3/23 上午11:40, Bibo Mao wrote:
With FPU save and restore flow, the cost is the same with different
FPU width 8/16/32 bytes, whatever from CPU cycle and cache line impaction.

Here is to enable FPU with max used type, for example if application
ever uses LASX instrction, enable FPU with LASX type even with FPU
exeception. So it can avoid possible LSX/LASX exception in future.

With context switch microbench which may touch FPU and LASX, there is 9%
improvement when halt_poll_ns is disabled. The command is
"./context --test=pipe" and source code located at:
https://github.com/bibo-mao/context_switch/blob/main/context.c

Original Wih patch improvement
75232 82440 9%

Signed-off-by: Bibo Mao <maobibo@xxxxxxxxxxx>
---
arch/loongarch/include/asm/kvm_host.h | 1 +
arch/loongarch/kvm/exit.c | 6 +++---
arch/loongarch/kvm/vcpu.c | 25 ++++++++++---------------
3 files changed, 14 insertions(+), 18 deletions(-)

diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index 19eb5e5c3984..7d739fd5cda6 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -203,6 +203,7 @@ struct kvm_vcpu_arch {
/* Which auxiliary state is loaded (KVM_LARCH_*) */
unsigned int aux_inuse;
unsigned int aux_ldtype;
+ unsigned int aux_used;
/* FPU state */
struct loongarch_fpu fpu FPU_ALIGN;
diff --git a/arch/loongarch/kvm/exit.c b/arch/loongarch/kvm/exit.c
index da0ad89f2eb7..da8e330c8b20 100644
--- a/arch/loongarch/kvm/exit.c
+++ b/arch/loongarch/kvm/exit.c
@@ -754,7 +754,7 @@ static int kvm_handle_fpu_disabled(struct kvm_vcpu *vcpu, int ecode)
return RESUME_HOST;
}
- vcpu->arch.aux_ldtype = KVM_LARCH_FPU;
+ vcpu->arch.aux_ldtype = vcpu->arch.aux_used | KVM_LARCH_FPU;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
return RESUME_GUEST;
@@ -796,7 +796,7 @@ static int kvm_handle_lsx_disabled(struct kvm_vcpu *vcpu, int ecode)
if (!kvm_guest_has_lsx(&vcpu->arch))
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
else {
- vcpu->arch.aux_ldtype = KVM_LARCH_LSX;
+ vcpu->arch.aux_ldtype = vcpu->arch.aux_used | KVM_LARCH_LSX;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
}
@@ -816,7 +816,7 @@ static int kvm_handle_lasx_disabled(struct kvm_vcpu *vcpu, int ecode)
if (!kvm_guest_has_lasx(&vcpu->arch))
kvm_queue_exception(vcpu, EXCCODE_INE, 0);
else {
- vcpu->arch.aux_ldtype = KVM_LARCH_LASX;
+ vcpu->arch.aux_ldtype = vcpu->arch.aux_used | KVM_LARCH_LASX;
kvm_make_request(KVM_REQ_AUX_LOAD, vcpu);
}
diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
index 8810fcd7e26e..0a111c74a330 100644
--- a/arch/loongarch/kvm/vcpu.c
+++ b/arch/loongarch/kvm/vcpu.c
@@ -239,23 +239,14 @@ static void kvm_late_check_requests(struct kvm_vcpu *vcpu)
}
if (kvm_check_request(KVM_REQ_AUX_LOAD, vcpu)) {
- switch (vcpu->arch.aux_ldtype) {
- case KVM_LARCH_FPU:
- kvm_own_fpu(vcpu);
- break;
- case KVM_LARCH_LSX:
- kvm_own_lsx(vcpu);
- break;
- case KVM_LARCH_LASX:
+ if (vcpu->arch.aux_ldtype & KVM_LARCH_LASX)
kvm_own_lasx(vcpu);
- break;
- case KVM_LARCH_LBT:
+ else if (vcpu->arch.aux_ldtype & KVM_LARCH_LSX)
+ kvm_own_lsx(vcpu);
+ else if (vcpu->arch.aux_ldtype & KVM_LARCH_FPU)
+ kvm_own_fpu(vcpu);
+ else if (vcpu->arch.aux_ldtype == KVM_LARCH_LBT)
kvm_own_lbt(vcpu);
- break;
- default:
- break;
- }
-
vcpu->arch.aux_ldtype = 0;
}
}
@@ -956,6 +947,7 @@ static int kvm_set_one_reg(struct kvm_vcpu *vcpu,
break;
case KVM_REG_LOONGARCH_VCPU_RESET:
vcpu->arch.st.guest_addr = 0;
+ vcpu->arch.aux_used = 0;
memset(&vcpu->arch.irq_pending, 0, sizeof(vcpu->arch.irq_pending));
memset(&vcpu->arch.irq_clear, 0, sizeof(vcpu->arch.irq_clear));
@@ -1384,6 +1376,7 @@ void kvm_own_fpu(struct kvm_vcpu *vcpu)
kvm_restore_fpu(&vcpu->arch.fpu);
vcpu->arch.aux_inuse |= KVM_LARCH_FPU;
+ vcpu->arch.aux_used |= KVM_LARCH_FPU;
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_FPU);
}
@@ -1412,6 +1405,7 @@ int kvm_own_lsx(struct kvm_vcpu *vcpu)
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LSX);
vcpu->arch.aux_inuse |= KVM_LARCH_LSX | KVM_LARCH_FPU;
+ vcpu->arch.aux_used |= KVM_LARCH_LSX | KVM_LARCH_FPU;
return 0;
}
@@ -1442,6 +1436,7 @@ int kvm_own_lasx(struct kvm_vcpu *vcpu)
trace_kvm_aux(vcpu, KVM_TRACE_AUX_RESTORE, KVM_TRACE_AUX_LASX);
vcpu->arch.aux_inuse |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU;
+ vcpu->arch.aux_used |= KVM_LARCH_LASX | KVM_LARCH_LSX | KVM_LARCH_FPU;
return 0;
}

base-commit: c369299895a591d96745d6492d4888259b004a9e