162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_X86_FPU_SCHED_H
362306a36Sopenharmony_ci#define _ASM_X86_FPU_SCHED_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <linux/sched.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/cpufeature.h>
862306a36Sopenharmony_ci#include <asm/fpu/types.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <asm/trace/fpu.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciextern void save_fpregs_to_fpstate(struct fpu *fpu);
1362306a36Sopenharmony_ciextern void fpu__drop(struct fpu *fpu);
1462306a36Sopenharmony_ciextern int  fpu_clone(struct task_struct *dst, unsigned long clone_flags, bool minimal,
1562306a36Sopenharmony_ci		      unsigned long shstk_addr);
1662306a36Sopenharmony_ciextern void fpu_flush_thread(void);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/*
1962306a36Sopenharmony_ci * FPU state switching for scheduling.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * This is a two-stage process:
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci *  - switch_fpu_prepare() saves the old state.
2462306a36Sopenharmony_ci *    This is done within the context of the old process.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci *  - switch_fpu_finish() sets TIF_NEED_FPU_LOAD; the floating point state
2762306a36Sopenharmony_ci *    will get loaded on return to userspace, or when the kernel needs it.
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * If TIF_NEED_FPU_LOAD is cleared then the CPU's FPU registers
3062306a36Sopenharmony_ci * are saved in the current thread's FPU register state.
3162306a36Sopenharmony_ci *
3262306a36Sopenharmony_ci * If TIF_NEED_FPU_LOAD is set then CPU's FPU registers may not
3362306a36Sopenharmony_ci * hold current()'s FPU registers. It is required to load the
3462306a36Sopenharmony_ci * registers before returning to userland or using the content
3562306a36Sopenharmony_ci * otherwise.
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci * The FPU context is only stored/restored for a user task and
3862306a36Sopenharmony_ci * PF_KTHREAD is used to distinguish between kernel and user threads.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_cistatic inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	if (cpu_feature_enabled(X86_FEATURE_FPU) &&
4362306a36Sopenharmony_ci	    !(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
4462306a36Sopenharmony_ci		save_fpregs_to_fpstate(old_fpu);
4562306a36Sopenharmony_ci		/*
4662306a36Sopenharmony_ci		 * The save operation preserved register state, so the
4762306a36Sopenharmony_ci		 * fpu_fpregs_owner_ctx is still @old_fpu. Store the
4862306a36Sopenharmony_ci		 * current CPU number in @old_fpu, so the next return
4962306a36Sopenharmony_ci		 * to user space can avoid the FPU register restore
5062306a36Sopenharmony_ci		 * when is returns on the same CPU and still owns the
5162306a36Sopenharmony_ci		 * context.
5262306a36Sopenharmony_ci		 */
5362306a36Sopenharmony_ci		old_fpu->last_cpu = cpu;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci		trace_x86_fpu_regs_deactivated(old_fpu);
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * Delay loading of the complete FPU state until the return to userland.
6162306a36Sopenharmony_ci * PKRU is handled separately.
6262306a36Sopenharmony_ci */
6362306a36Sopenharmony_cistatic inline void switch_fpu_finish(void)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	if (cpu_feature_enabled(X86_FEATURE_FPU))
6662306a36Sopenharmony_ci		set_thread_flag(TIF_NEED_FPU_LOAD);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#endif /* _ASM_X86_FPU_SCHED_H */
70