]> www.infradead.org Git - nvme.git/commitdiff
KVM: arm64: Add early_param to control WFx trapping
authorColton Lewis <coltonlewis@google.com>
Thu, 23 May 2024 17:40:55 +0000 (17:40 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Fri, 14 Jun 2024 20:11:15 +0000 (20:11 +0000)
Add an early_params to control WFI and WFE trapping. This is to
control the degree guests can wait for interrupts on their own without
being trapped by KVM. Options for each param are trap and notrap. trap
enables the trap. notrap disables the trap. Note that when enabled,
traps are allowed but not guaranteed by the CPU architecture. Absent
an explicitly set policy, default to current behavior: disabling the
trap if only a single task is running and enabling otherwise.

Signed-off-by: Colton Lewis <coltonlewis@google.com>
Reviewed-by: Jing Zhang <jingzhangos@google.com>
Link: https://lore.kernel.org/r/20240523174056.1565133-1-coltonlewis@google.com
[ oliver: rework kvm_vcpu_should_clear_tw*() for readability ]
Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
Documentation/admin-guide/kernel-parameters.txt
arch/arm64/kvm/arm.c

index b600df82669db000304571fd23c3af90df36190d..47249bd99987b96f048c436ab59aa15061923aa4 100644 (file)
                        [KVM,ARM,EARLY] Allow use of GICv4 for direct
                        injection of LPIs.
 
+       kvm-arm.wfe_trap_policy=
+                       [KVM,ARM] Control when to set WFE instruction trap for
+                       KVM VMs. Traps are allowed but not guaranteed by the
+                       CPU architecture.
+
+                       trap: set WFE instruction trap
+
+                       notrap: clear WFE instruction trap
+
+       kvm-arm.wfi_trap_policy=
+                       [KVM,ARM] Control when to set WFI instruction trap for
+                       KVM VMs. Traps are allowed but not guaranteed by the
+                       CPU architecture.
+
+                       trap: set WFI instruction trap
+
+                       notrap: clear WFI instruction trap
+
        kvm_cma_resv_ratio=n [PPC,EARLY]
                        Reserves given percentage from system memory area for
                        contiguous memory allocation for KVM hash pagetable
index 59716789fe0f38186cd1700f92757b005f48d1cb..53e23528d2cfd007e85cec884b71f0e68c3abfae 100644 (file)
 
 static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
 
+enum kvm_wfx_trap_policy {
+       KVM_WFX_NOTRAP_SINGLE_TASK, /* Default option */
+       KVM_WFX_NOTRAP,
+       KVM_WFX_TRAP,
+};
+
+static enum kvm_wfx_trap_policy kvm_wfi_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
+static enum kvm_wfx_trap_policy kvm_wfe_trap_policy __read_mostly = KVM_WFX_NOTRAP_SINGLE_TASK;
+
 DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
 
 DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
@@ -546,6 +555,24 @@ static void vcpu_set_pauth_traps(struct kvm_vcpu *vcpu)
        }
 }
 
+static bool kvm_vcpu_should_clear_twi(struct kvm_vcpu *vcpu)
+{
+       if (unlikely(kvm_wfi_trap_policy != KVM_WFX_NOTRAP_SINGLE_TASK))
+               return kvm_wfi_trap_policy == KVM_WFX_NOTRAP;
+
+       return single_task_running() &&
+              (atomic_read(&vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count) ||
+               vcpu->kvm->arch.vgic.nassgireq);
+}
+
+static bool kvm_vcpu_should_clear_twe(struct kvm_vcpu *vcpu)
+{
+       if (unlikely(kvm_wfe_trap_policy != KVM_WFX_NOTRAP_SINGLE_TASK))
+               return kvm_wfe_trap_policy == KVM_WFX_NOTRAP;
+
+       return single_task_running();
+}
+
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
        struct kvm_s2_mmu *mmu;
@@ -579,10 +606,15 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        if (kvm_arm_is_pvtime_enabled(&vcpu->arch))
                kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
 
-       if (single_task_running())
-               vcpu_clear_wfx_traps(vcpu);
+       if (kvm_vcpu_should_clear_twe(vcpu))
+               vcpu->arch.hcr_el2 &= ~HCR_TWE;
+       else
+               vcpu->arch.hcr_el2 |= HCR_TWE;
+
+       if (kvm_vcpu_should_clear_twi(vcpu))
+               vcpu->arch.hcr_el2 &= ~HCR_TWI;
        else
-               vcpu_set_wfx_traps(vcpu);
+               vcpu->arch.hcr_el2 |= HCR_TWI;
 
        vcpu_set_pauth_traps(vcpu);
 
@@ -2858,6 +2890,36 @@ static int __init early_kvm_mode_cfg(char *arg)
 }
 early_param("kvm-arm.mode", early_kvm_mode_cfg);
 
+static int __init early_kvm_wfx_trap_policy_cfg(char *arg, enum kvm_wfx_trap_policy *p)
+{
+       if (!arg)
+               return -EINVAL;
+
+       if (strcmp(arg, "trap") == 0) {
+               *p = KVM_WFX_TRAP;
+               return 0;
+       }
+
+       if (strcmp(arg, "notrap") == 0) {
+               *p = KVM_WFX_NOTRAP;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int __init early_kvm_wfi_trap_policy_cfg(char *arg)
+{
+       return early_kvm_wfx_trap_policy_cfg(arg, &kvm_wfi_trap_policy);
+}
+early_param("kvm-arm.wfi_trap_policy", early_kvm_wfi_trap_policy_cfg);
+
+static int __init early_kvm_wfe_trap_policy_cfg(char *arg)
+{
+       return early_kvm_wfx_trap_policy_cfg(arg, &kvm_wfe_trap_policy);
+}
+early_param("kvm-arm.wfe_trap_policy", early_kvm_wfe_trap_policy_cfg);
+
 enum kvm_mode kvm_get_mode(void)
 {
        return kvm_mode;