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

Merge branch kvm-arm64/wfxt into kvmarm-master/next

* kvm-arm64/wfxt:
: .
: Add support for the WFET/WFIT instructions that provide the same
: service as WFE/WFI, only with a timeout.
: .
KVM: arm64: Expose the WFXT feature to guests
KVM: arm64: Offer early resume for non-blocking WFxT instructions
KVM: arm64: Handle blocking WFIT instruction
KVM: arm64: Introduce kvm_counter_compute_delta() helper
KVM: arm64: Simplify kvm_cpu_has_pending_timer()
arm64: Use WFxT for __delay() when possible
arm64: Add wfet()/wfit() helpers
arm64: Add HWCAP advertising FEAT_WFXT
arm64: Add RV and RN fields for ESR_ELx_WFx_ISS
arm64: Expand ESR_ELx_WFx_ISS_TI to match its ARMv8.7 definition

Signed-off-by: Marc Zyngier <maz@kernel.org>

+110 -30
+2
Documentation/arm64/cpu-feature-registers.rst
··· 290 290 +------------------------------+---------+---------+ 291 291 | RPRES | [7-4] | y | 292 292 +------------------------------+---------+---------+ 293 + | WFXT | [3-0] | y | 294 + +------------------------------+---------+---------+ 293 295 294 296 295 297 Appendix I: Example
+4
Documentation/arm64/elf_hwcaps.rst
··· 297 297 298 298 Functionality implied by ID_AA64SMFR0_EL1.FA64 == 0b1. 299 299 300 + HWCAP2_WFXT 301 + 302 + Functionality implied by ID_AA64ISAR2_EL1.WFXT == 0b0010. 303 + 300 304 4. Unused AT_HWCAP bits 301 305 ----------------------- 302 306
+4
arch/arm64/include/asm/barrier.h
··· 16 16 17 17 #define sev() asm volatile("sev" : : : "memory") 18 18 #define wfe() asm volatile("wfe" : : : "memory") 19 + #define wfet(val) asm volatile("msr s0_3_c1_c0_0, %0" \ 20 + : : "r" (val) : "memory") 19 21 #define wfi() asm volatile("wfi" : : : "memory") 22 + #define wfit(val) asm volatile("msr s0_3_c1_c0_1, %0" \ 23 + : : "r" (val) : "memory") 20 24 21 25 #define isb() asm volatile("isb" : : : "memory") 22 26 #define dmb(opt) asm volatile("dmb " #opt : : : "memory")
+6 -2
arch/arm64/include/asm/esr.h
··· 135 135 #define ESR_ELx_CV (UL(1) << 24) 136 136 #define ESR_ELx_COND_SHIFT (20) 137 137 #define ESR_ELx_COND_MASK (UL(0xF) << ESR_ELx_COND_SHIFT) 138 - #define ESR_ELx_WFx_ISS_TI (UL(1) << 0) 138 + #define ESR_ELx_WFx_ISS_RN (UL(0x1F) << 5) 139 + #define ESR_ELx_WFx_ISS_RV (UL(1) << 2) 140 + #define ESR_ELx_WFx_ISS_TI (UL(3) << 0) 141 + #define ESR_ELx_WFx_ISS_WFxT (UL(2) << 0) 139 142 #define ESR_ELx_WFx_ISS_WFI (UL(0) << 0) 140 143 #define ESR_ELx_WFx_ISS_WFE (UL(1) << 0) 141 144 #define ESR_ELx_xVC_IMM_MASK ((1UL << 16) - 1) ··· 151 148 #define DISR_EL1_ESR_MASK (ESR_ELx_AET | ESR_ELx_EA | ESR_ELx_FSC) 152 149 153 150 /* ESR value templates for specific events */ 154 - #define ESR_ELx_WFx_MASK (ESR_ELx_EC_MASK | ESR_ELx_WFx_ISS_TI) 151 + #define ESR_ELx_WFx_MASK (ESR_ELx_EC_MASK | \ 152 + (ESR_ELx_WFx_ISS_TI & ~ESR_ELx_WFx_ISS_WFxT)) 155 153 #define ESR_ELx_WFx_WFI_VAL ((ESR_ELx_EC_WFx << ESR_ELx_EC_SHIFT) | \ 156 154 ESR_ELx_WFx_ISS_WFI) 157 155
+1
arch/arm64/include/asm/hwcap.h
··· 117 117 #define KERNEL_HWCAP_SME_B16F32 __khwcap2_feature(SME_B16F32) 118 118 #define KERNEL_HWCAP_SME_F32F32 __khwcap2_feature(SME_F32F32) 119 119 #define KERNEL_HWCAP_SME_FA64 __khwcap2_feature(SME_FA64) 120 + #define KERNEL_HWCAP_WFXT __khwcap2_feature(WFXT) 120 121 121 122 /* 122 123 * This yields a mask that user programs can use to figure out what
+1
arch/arm64/include/asm/kvm_host.h
··· 455 455 #define KVM_ARM64_FP_FOREIGN_FPSTATE (1 << 14) 456 456 #define KVM_ARM64_ON_UNSUPPORTED_CPU (1 << 15) /* Physical CPU not in supported_cpus */ 457 457 #define KVM_ARM64_HOST_SME_ENABLED (1 << 16) /* SME enabled for EL0 */ 458 + #define KVM_ARM64_WFIT (1 << 17) /* WFIT instruction trapped */ 458 459 459 460 #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ 460 461 KVM_GUESTDBG_USE_SW_BP | \
+1
arch/arm64/include/uapi/asm/hwcap.h
··· 87 87 #define HWCAP2_SME_B16F32 (1 << 28) 88 88 #define HWCAP2_SME_F32F32 (1 << 29) 89 89 #define HWCAP2_SME_FA64 (1 << 30) 90 + #define HWCAP2_WFXT (1UL << 31) 90 91 91 92 #endif /* _UAPI__ASM_HWCAP_H */
+13
arch/arm64/kernel/cpufeature.c
··· 237 237 ARM64_FTR_BITS(FTR_VISIBLE_IF_IS_ENABLED(CONFIG_ARM64_PTR_AUTH), 238 238 FTR_STRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_GPA3_SHIFT, 4, 0), 239 239 ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_RPRES_SHIFT, 4, 0), 240 + ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_WFXT_SHIFT, 4, 0), 240 241 ARM64_FTR_END, 241 242 }; 242 243 ··· 2519 2518 .cpu_enable = fa64_kernel_enable, 2520 2519 }, 2521 2520 #endif /* CONFIG_ARM64_SME */ 2521 + { 2522 + .desc = "WFx with timeout", 2523 + .capability = ARM64_HAS_WFXT, 2524 + .type = ARM64_CPUCAP_SYSTEM_FEATURE, 2525 + .sys_reg = SYS_ID_AA64ISAR2_EL1, 2526 + .sign = FTR_UNSIGNED, 2527 + .field_pos = ID_AA64ISAR2_WFXT_SHIFT, 2528 + .field_width = 4, 2529 + .matches = has_cpuid_feature, 2530 + .min_field_value = ID_AA64ISAR2_WFXT_SUPPORTED, 2531 + }, 2522 2532 {}, 2523 2533 }; 2524 2534 ··· 2663 2651 HWCAP_CAP(SYS_ID_AA64MMFR0_EL1, ID_AA64MMFR0_ECV_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ECV), 2664 2652 HWCAP_CAP(SYS_ID_AA64MMFR1_EL1, ID_AA64MMFR1_AFP_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_AFP), 2665 2653 HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_RPRES_SHIFT, 4, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_RPRES), 2654 + HWCAP_CAP(SYS_ID_AA64ISAR2_EL1, ID_AA64ISAR2_WFXT_SHIFT, 4, FTR_UNSIGNED, ID_AA64ISAR2_WFXT_SUPPORTED, CAP_HWCAP, KERNEL_HWCAP_WFXT), 2666 2655 #ifdef CONFIG_ARM64_SME 2667 2656 HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SME_SHIFT, 4, FTR_UNSIGNED, ID_AA64PFR1_SME, CAP_HWCAP, KERNEL_HWCAP_SME), 2668 2657 HWCAP_CAP(SYS_ID_AA64SMFR0_EL1, ID_AA64SMFR0_FA64_SHIFT, 1, FTR_UNSIGNED, ID_AA64SMFR0_FA64, CAP_HWCAP, KERNEL_HWCAP_SME_FA64),
+1
arch/arm64/kernel/cpuinfo.c
··· 106 106 [KERNEL_HWCAP_SME_B16F32] = "smeb16f32", 107 107 [KERNEL_HWCAP_SME_F32F32] = "smef32f32", 108 108 [KERNEL_HWCAP_SME_FA64] = "smefa64", 109 + [KERNEL_HWCAP_WFXT] = "wfxt", 109 110 }; 110 111 111 112 #ifdef CONFIG_COMPAT
+31 -16
arch/arm64/kvm/arch_timer.c
··· 208 208 return IRQ_HANDLED; 209 209 } 210 210 211 - static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx) 211 + static u64 kvm_counter_compute_delta(struct arch_timer_context *timer_ctx, 212 + u64 val) 212 213 { 213 - u64 cval, now; 214 + u64 now = kvm_phys_timer_read() - timer_get_offset(timer_ctx); 214 215 215 - cval = timer_get_cval(timer_ctx); 216 - now = kvm_phys_timer_read() - timer_get_offset(timer_ctx); 217 - 218 - if (now < cval) { 216 + if (now < val) { 219 217 u64 ns; 220 218 221 219 ns = cyclecounter_cyc2ns(timecounter->cc, 222 - cval - now, 220 + val - now, 223 221 timecounter->mask, 224 222 &timecounter->frac); 225 223 return ns; ··· 226 228 return 0; 227 229 } 228 230 231 + static u64 kvm_timer_compute_delta(struct arch_timer_context *timer_ctx) 232 + { 233 + return kvm_counter_compute_delta(timer_ctx, timer_get_cval(timer_ctx)); 234 + } 235 + 229 236 static bool kvm_timer_irq_can_fire(struct arch_timer_context *timer_ctx) 230 237 { 231 238 WARN_ON(timer_ctx && timer_ctx->loaded); 232 239 return timer_ctx && 233 240 ((timer_get_ctl(timer_ctx) & 234 241 (ARCH_TIMER_CTRL_IT_MASK | ARCH_TIMER_CTRL_ENABLE)) == ARCH_TIMER_CTRL_ENABLE); 242 + } 243 + 244 + static bool vcpu_has_wfit_active(struct kvm_vcpu *vcpu) 245 + { 246 + return (cpus_have_final_cap(ARM64_HAS_WFXT) && 247 + (vcpu->arch.flags & KVM_ARM64_WFIT)); 248 + } 249 + 250 + static u64 wfit_delay_ns(struct kvm_vcpu *vcpu) 251 + { 252 + struct arch_timer_context *ctx = vcpu_vtimer(vcpu); 253 + u64 val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu)); 254 + 255 + return kvm_counter_compute_delta(ctx, val); 235 256 } 236 257 237 258 /* ··· 269 252 if (kvm_timer_irq_can_fire(ctx)) 270 253 min_delta = min(min_delta, kvm_timer_compute_delta(ctx)); 271 254 } 255 + 256 + if (vcpu_has_wfit_active(vcpu)) 257 + min_delta = min(min_delta, wfit_delay_ns(vcpu)); 272 258 273 259 /* If none of timers can fire, then return 0 */ 274 260 if (min_delta == ULLONG_MAX) ··· 370 350 return cval <= now; 371 351 } 372 352 373 - bool kvm_timer_is_pending(struct kvm_vcpu *vcpu) 353 + int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 374 354 { 375 - struct timer_map map; 376 - 377 - get_timer_map(vcpu, &map); 378 - 379 - return kvm_timer_should_fire(map.direct_vtimer) || 380 - kvm_timer_should_fire(map.direct_ptimer) || 381 - kvm_timer_should_fire(map.emul_ptimer); 355 + return vcpu_has_wfit_active(vcpu) && wfit_delay_ns(vcpu) == 0; 382 356 } 383 357 384 358 /* ··· 498 484 */ 499 485 if (!kvm_timer_irq_can_fire(map.direct_vtimer) && 500 486 !kvm_timer_irq_can_fire(map.direct_ptimer) && 501 - !kvm_timer_irq_can_fire(map.emul_ptimer)) 487 + !kvm_timer_irq_can_fire(map.emul_ptimer) && 488 + !vcpu_has_wfit_active(vcpu)) 502 489 return; 503 490 504 491 /*
+1 -5
arch/arm64/kvm/arm.c
··· 356 356 kvm_arm_vcpu_destroy(vcpu); 357 357 } 358 358 359 - int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 360 - { 361 - return kvm_timer_is_pending(vcpu); 362 - } 363 - 364 359 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) 365 360 { 366 361 ··· 634 639 preempt_enable(); 635 640 636 641 kvm_vcpu_halt(vcpu); 642 + vcpu->arch.flags &= ~KVM_ARM64_WFIT; 637 643 kvm_clear_request(KVM_REQ_UNHALT, vcpu); 638 644 639 645 preempt_disable();
+31 -4
arch/arm64/kvm/handle_exit.c
··· 80 80 * 81 81 * @vcpu: the vcpu pointer 82 82 * 83 - * WFE: Yield the CPU and come back to this vcpu when the scheduler 83 + * WFE[T]: Yield the CPU and come back to this vcpu when the scheduler 84 84 * decides to. 85 85 * WFI: Simply call kvm_vcpu_halt(), which will halt execution of 86 86 * world-switches and schedule other host processes until there is an 87 87 * incoming IRQ or FIQ to the VM. 88 + * WFIT: Same as WFI, with a timed wakeup implemented as a background timer 89 + * 90 + * WF{I,E}T can immediately return if the deadline has already expired. 88 91 */ 89 92 static int kvm_handle_wfx(struct kvm_vcpu *vcpu) 90 93 { 91 - if (kvm_vcpu_get_esr(vcpu) & ESR_ELx_WFx_ISS_WFE) { 94 + u64 esr = kvm_vcpu_get_esr(vcpu); 95 + 96 + if (esr & ESR_ELx_WFx_ISS_WFE) { 92 97 trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true); 93 98 vcpu->stat.wfe_exit_stat++; 94 - kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu)); 95 99 } else { 96 100 trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false); 97 101 vcpu->stat.wfi_exit_stat++; 98 - kvm_vcpu_wfi(vcpu); 99 102 } 100 103 104 + if (esr & ESR_ELx_WFx_ISS_WFxT) { 105 + if (esr & ESR_ELx_WFx_ISS_RV) { 106 + u64 val, now; 107 + 108 + now = kvm_arm_timer_get_reg(vcpu, KVM_REG_ARM_TIMER_CNT); 109 + val = vcpu_get_reg(vcpu, kvm_vcpu_sys_get_rt(vcpu)); 110 + 111 + if (now >= val) 112 + goto out; 113 + } else { 114 + /* Treat WFxT as WFx if RN is invalid */ 115 + esr &= ~ESR_ELx_WFx_ISS_WFxT; 116 + } 117 + } 118 + 119 + if (esr & ESR_ELx_WFx_ISS_WFE) { 120 + kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu)); 121 + } else { 122 + if (esr & ESR_ELx_WFx_ISS_WFxT) 123 + vcpu->arch.flags |= KVM_ARM64_WFIT; 124 + 125 + kvm_vcpu_wfi(vcpu); 126 + } 127 + out: 101 128 kvm_incr_pc(vcpu); 102 129 103 130 return 1;
+2
arch/arm64/kvm/sys_regs.c
··· 1146 1146 if (!vcpu_has_ptrauth(vcpu)) 1147 1147 val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR2_APA3) | 1148 1148 ARM64_FEATURE_MASK(ID_AA64ISAR2_GPA3)); 1149 + if (!cpus_have_final_cap(ARM64_HAS_WFXT)) 1150 + val &= ~ARM64_FEATURE_MASK(ID_AA64ISAR2_WFXT); 1149 1151 break; 1150 1152 case SYS_ID_AA64DFR0_EL1: 1151 1153 /* Limit debug to ARMv8.0 */
+11 -1
arch/arm64/lib/delay.c
··· 27 27 { 28 28 cycles_t start = get_cycles(); 29 29 30 - if (arch_timer_evtstrm_available()) { 30 + if (cpus_have_const_cap(ARM64_HAS_WFXT)) { 31 + u64 end = start + cycles; 32 + 33 + /* 34 + * Start with WFIT. If an interrupt makes us resume 35 + * early, use a WFET loop to complete the delay. 36 + */ 37 + wfit(end); 38 + while ((get_cycles() - start) < cycles) 39 + wfet(end); 40 + } else if (arch_timer_evtstrm_available()) { 31 41 const cycles_t timer_evt_period = 32 42 USECS_TO_CYCLES(ARCH_TIMER_EVT_STREAM_PERIOD_US); 33 43
+1
arch/arm64/tools/cpucaps
··· 38 38 HAS_SYSREG_GIC_CPUIF 39 39 HAS_TLB_RANGE 40 40 HAS_VIRT_HOST_EXTN 41 + HAS_WFXT 41 42 HW_DBM 42 43 KVM_PROTECTED_MODE 43 44 MISMATCHED_CACHE_TYPE
-2
include/kvm/arm_arch_timer.h
··· 76 76 int kvm_arm_timer_get_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); 77 77 int kvm_arm_timer_has_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr); 78 78 79 - bool kvm_timer_is_pending(struct kvm_vcpu *vcpu); 80 - 81 79 u64 kvm_phys_timer_read(void); 82 80 83 81 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu);