diff options
| author | Rodrigo Vivi <[email protected]> | 2018-07-23 09:13:12 -0700 | 
|---|---|---|
| committer | Rodrigo Vivi <[email protected]> | 2018-07-23 09:13:12 -0700 | 
| commit | c74a7469f97c0f40b46e82ee979f9fb1bb6e847c (patch) | |
| tree | f2690a1a916b73ef94657fbf0e0141ae57701825 /arch/arm64/kvm/fpsimd.c | |
| parent | 6f15a7de86c8cf2dc09fc9e6d07047efa40ef809 (diff) | |
| parent | 500775074f88d9cf5416bed2ca19592812d62c41 (diff) | |
Merge drm/drm-next into drm-intel-next-queued
We need a backmerge to get DP_DPCD_REV_14 before we push other
i915 changes to dinq that could break compilation.
Signed-off-by: Rodrigo Vivi <[email protected]>
Diffstat (limited to 'arch/arm64/kvm/fpsimd.c')
| -rw-r--r-- | arch/arm64/kvm/fpsimd.c | 128 | 
1 files changed, 128 insertions, 0 deletions
| diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c new file mode 100644 index 000000000000..aac7808ce216 --- /dev/null +++ b/arch/arm64/kvm/fpsimd.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * arch/arm64/kvm/fpsimd.c: Guest/host FPSIMD context coordination helpers + * + * Copyright 2018 Arm Limited + * Author: Dave Martin <[email protected]> + */ +#include <linux/irqflags.h> +#include <linux/sched.h> +#include <linux/thread_info.h> +#include <linux/kvm_host.h> +#include <asm/kvm_asm.h> +#include <asm/kvm_host.h> +#include <asm/kvm_mmu.h> +#include <asm/sysreg.h> + +/* + * Called on entry to KVM_RUN unless this vcpu previously ran at least + * once and the most recent prior KVM_RUN for this vcpu was called from + * the same task as current (highly likely). + * + * This is guaranteed to execute before kvm_arch_vcpu_load_fp(vcpu), + * such that on entering hyp the relevant parts of current are already + * mapped. + */ +int kvm_arch_vcpu_run_map_fp(struct kvm_vcpu *vcpu) +{ +	int ret; + +	struct thread_info *ti = ¤t->thread_info; +	struct user_fpsimd_state *fpsimd = ¤t->thread.uw.fpsimd_state; + +	/* +	 * Make sure the host task thread flags and fpsimd state are +	 * visible to hyp: +	 */ +	ret = create_hyp_mappings(ti, ti + 1, PAGE_HYP); +	if (ret) +		goto error; + +	ret = create_hyp_mappings(fpsimd, fpsimd + 1, PAGE_HYP); +	if (ret) +		goto error; + +	vcpu->arch.host_thread_info = kern_hyp_va(ti); +	vcpu->arch.host_fpsimd_state = kern_hyp_va(fpsimd); +error: +	return ret; +} + +/* + * Prepare vcpu for saving the host's FPSIMD state and loading the guest's. + * The actual loading is done by the FPSIMD access trap taken to hyp. + * + * Here, we just set the correct metadata to indicate that the FPSIMD + * state in the cpu regs (if any) belongs to current on the host. + * + * TIF_SVE is backed up here, since it may get clobbered with guest state. + * This flag is restored by kvm_arch_vcpu_put_fp(vcpu). + */ +void kvm_arch_vcpu_load_fp(struct kvm_vcpu *vcpu) +{ +	BUG_ON(!current->mm); + +	vcpu->arch.flags &= ~(KVM_ARM64_FP_ENABLED | +			      KVM_ARM64_HOST_SVE_IN_USE | +			      KVM_ARM64_HOST_SVE_ENABLED); +	vcpu->arch.flags |= KVM_ARM64_FP_HOST; + +	if (test_thread_flag(TIF_SVE)) +		vcpu->arch.flags |= KVM_ARM64_HOST_SVE_IN_USE; + +	if (read_sysreg(cpacr_el1) & CPACR_EL1_ZEN_EL0EN) +		vcpu->arch.flags |= KVM_ARM64_HOST_SVE_ENABLED; +} + +/* + * If the guest FPSIMD state was loaded, update the host's context + * tracking data mark the CPU FPSIMD regs as dirty and belonging to vcpu + * so that they will be written back if the kernel clobbers them due to + * kernel-mode NEON before re-entry into the guest. + */ +void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu) +{ +	WARN_ON_ONCE(!irqs_disabled()); + +	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { +		fpsimd_bind_state_to_cpu(&vcpu->arch.ctxt.gp_regs.fp_regs); +		clear_thread_flag(TIF_FOREIGN_FPSTATE); +		clear_thread_flag(TIF_SVE); +	} +} + +/* + * Write back the vcpu FPSIMD regs if they are dirty, and invalidate the + * cpu FPSIMD regs so that they can't be spuriously reused if this vcpu + * disappears and another task or vcpu appears that recycles the same + * struct fpsimd_state. + */ +void kvm_arch_vcpu_put_fp(struct kvm_vcpu *vcpu) +{ +	unsigned long flags; + +	local_irq_save(flags); + +	if (vcpu->arch.flags & KVM_ARM64_FP_ENABLED) { +		/* Clean guest FP state to memory and invalidate cpu view */ +		fpsimd_save(); +		fpsimd_flush_cpu_state(); +	} else if (system_supports_sve()) { +		/* +		 * The FPSIMD/SVE state in the CPU has not been touched, and we +		 * have SVE (and VHE): CPACR_EL1 (alias CPTR_EL2) has been +		 * reset to CPACR_EL1_DEFAULT by the Hyp code, disabling SVE +		 * for EL0.  To avoid spurious traps, restore the trap state +		 * seen by kvm_arch_vcpu_load_fp(): +		 */ +		if (vcpu->arch.flags & KVM_ARM64_HOST_SVE_ENABLED) +			sysreg_clear_set(CPACR_EL1, 0, CPACR_EL1_ZEN_EL0EN); +		else +			sysreg_clear_set(CPACR_EL1, CPACR_EL1_ZEN_EL0EN, 0); +	} + +	update_thread_flag(TIF_SVE, +			   vcpu->arch.flags & KVM_ARM64_HOST_SVE_IN_USE); + +	local_irq_restore(flags); +} |