@@ -12,6 +12,11 @@
#include <asm/types.h>
/* Hyp Configuration Register (HCR) bits */
+#define HCR_TWEDEL_SHIFT 60
+#define HCR_TWEDEL_MAX (UL(0xf))
+#define HCR_TWEDEL_MASK (HCR_TWEDEL_MAX << HCR_TWEDEL_SHIFT)
+#define HCR_TWEDEL (UL(1) << HCR_TWEDEL_SHIFT)
+#define HCR_TWEDEN (UL(1) << 59)
#define HCR_FWB (UL(1) << 46)
#define HCR_API (UL(1) << 41)
#define HCR_APK (UL(1) << 40)
@@ -102,6 +102,38 @@ static inline void vcpu_set_wfx_traps(struct kvm_vcpu *vcpu)
vcpu->arch.hcr_el2 |= HCR_TWI;
}
+#ifdef CONFIG_ARM64_TWED
+static inline void vcpu_twed_enable(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.hcr_el2 |= HCR_TWEDEN;
+}
+
+static inline void vcpu_twed_disable(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.hcr_el2 &= ~HCR_TWEDEN;
+}
+
+static inline void vcpu_twed_init(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.twed = (u64)twed;
+}
+
+static inline void vcpu_set_twed(struct kvm_vcpu *vcpu)
+{
+ u64 delay = vcpu->arch.twed;
+ if (delay > HCR_TWEDEL_MAX)
+ delay = HCR_TWEDEL_MAX;
+
+ vcpu->arch.hcr_el2 &= ~HCR_TWEDEL_MASK;
+ vcpu->arch.hcr_el2 |= (delay << HCR_TWEDEL_SHIFT);
+}
+#else
+static inline void vcpu_twed_enable(struct kvm_vcpu *vcpu) {};
+static inline void vcpu_twed_disable(struct kvm_vcpu *vcpu) {};
+static inline void vcpu_twed_init(struct kvm_vcpu *vcpu) {};
+static inline void vcpu_set_twed(struct kvm_vcpu *vcpu) {};
+#endif
+
static inline void vcpu_ptrauth_enable(struct kvm_vcpu *vcpu)
{
vcpu->arch.hcr_el2 |= (HCR_API | HCR_APK);
@@ -371,6 +371,11 @@ struct kvm_vcpu_arch {
u64 last_steal;
gpa_t base;
} steal;
+
+#ifdef CONFIG_ARM64_TWED
+ /* WFE trap delay */
+ u64 twed;
+#endif
};
/* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
@@ -688,4 +693,12 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
#define kvm_arm_vcpu_sve_finalized(vcpu) \
((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
+#ifdef CONFIG_ARM64_TWED
+#define use_twed() (has_twed() && twed_enable)
+extern bool twed_enable;
+extern unsigned int twed;
+#else
+#define use_twed() false
+#endif
+
#endif /* __ARM64_KVM_HOST_H__ */
@@ -98,6 +98,14 @@ static __always_inline bool has_vhe(void)
return cpus_have_final_cap(ARM64_HAS_VIRT_HOST_EXTN);
}
+static __always_inline bool has_twed(void)
+{
+ if (cpus_have_const_cap(ARM64_HAS_TWED))
+ return true;
+
+ return false;
+}
+
#endif /* __ASSEMBLY__ */
#endif /* ! __ASM__VIRT_H */
@@ -59,6 +59,14 @@ static bool vgic_present;
static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+#ifdef CONFIG_ARM64_TWED
+bool twed_enable = false;
+module_param(twed_enable, bool, S_IRUGO | S_IWUSR);
+
+unsigned int twed = 0;
+module_param(twed, uint, S_IRUGO | S_IWUSR);
+#endif
+
int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
{
return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
@@ -270,6 +278,13 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
vcpu->arch.hw_mmu = &vcpu->kvm->arch.mmu;
+ if (use_twed()) {
+ vcpu_twed_enable(vcpu);
+ vcpu_twed_init(vcpu);
+ } else {
+ vcpu_twed_disable(vcpu);
+ }
+
err = kvm_vgic_vcpu_init(vcpu);
if (err)
return err;
@@ -736,6 +751,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
kvm_arm_setup_debug(vcpu);
+ if (use_twed()) {
+ vcpu_twed_enable(vcpu);
+ vcpu_set_twed(vcpu);
+ } else {
+ vcpu_twed_disable(vcpu);
+ }
+
/**************************************************************
* Enter the guest
*/