Merge branch 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 FPU updates from Ingo Molnar: "The main changes in this cycle were: - do a large round of simplifications after all CPUs do 'eager' FPU context switching in v4.9: remove CR0 twiddling, remove leftover eager/lazy bts, etc (Andy Lutomirski) - more FPU code simplifications: remove struct fpu::counter, clarify nomenclature, remove unnecessary arguments/functions and better structure the code (Rik van Riel)" * 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/fpu: Remove clts() x86/fpu: Remove stts() x86/fpu: Handle #NM without FPU emulation as an error x86/fpu, lguest: Remove CR0.TS support x86/fpu, kvm: Remove host CR0.TS manipulation x86/fpu: Remove irq_ts_save() and irq_ts_restore() x86/fpu: Stop saving and restoring CR0.TS in fpu__init_check_bugs() x86/fpu: Get rid of two redundant clts() calls x86/fpu: Finish excising 'eagerfpu' x86/fpu: Split old_fpu & new_fpu handling into separate functions x86/fpu: Remove 'cpu' argument from __cpu_invalidate_fpregs_state() x86/fpu: Split old & new FPU code paths x86/fpu: Remove __fpregs_(de)activate() x86/fpu: Rename lazy restore functions to "register state valid" x86/fpu, kvm: Remove KVM vcpu->fpu_counter x86/fpu: Remove struct fpu::counter x86/fpu: Remove use_eager_fpu() x86/fpu: Remove the XFEATURE_MASK_EAGER/LAZY distinction x86/fpu: Hard-disable lazy FPU mode x86/crypto, x86/fpu: Remove X86_FEATURE_EAGER_FPU #ifdef from the crc32c code
This commit is contained in:
@@ -104,7 +104,6 @@
|
||||
#define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */
|
||||
#define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */
|
||||
#define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */
|
||||
#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */
|
||||
#define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */
|
||||
|
||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
||||
|
@@ -26,16 +26,6 @@ extern void kernel_fpu_begin(void);
|
||||
extern void kernel_fpu_end(void);
|
||||
extern bool irq_fpu_usable(void);
|
||||
|
||||
/*
|
||||
* Some instructions like VIA's padlock instructions generate a spurious
|
||||
* DNA fault but don't modify SSE registers. And these instructions
|
||||
* get used from interrupt context as well. To prevent these kernel instructions
|
||||
* in interrupt context interacting wrongly with other user/kernel fpu usage, we
|
||||
* should use them only in the context of irq_ts_save/restore()
|
||||
*/
|
||||
extern int irq_ts_save(void);
|
||||
extern void irq_ts_restore(int TS_state);
|
||||
|
||||
/*
|
||||
* Query the presence of one or more xfeatures. Works on any legacy CPU as well.
|
||||
*
|
||||
|
@@ -60,11 +60,6 @@ extern u64 fpu__get_supported_xfeatures_mask(void);
|
||||
/*
|
||||
* FPU related CPU feature flag helper routines:
|
||||
*/
|
||||
static __always_inline __pure bool use_eager_fpu(void)
|
||||
{
|
||||
return static_cpu_has(X86_FEATURE_EAGER_FPU);
|
||||
}
|
||||
|
||||
static __always_inline __pure bool use_xsaveopt(void)
|
||||
{
|
||||
return static_cpu_has(X86_FEATURE_XSAVEOPT);
|
||||
@@ -484,42 +479,42 @@ extern int copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size)
|
||||
DECLARE_PER_CPU(struct fpu *, fpu_fpregs_owner_ctx);
|
||||
|
||||
/*
|
||||
* Must be run with preemption disabled: this clears the fpu_fpregs_owner_ctx,
|
||||
* on this CPU.
|
||||
* The in-register FPU state for an FPU context on a CPU is assumed to be
|
||||
* valid if the fpu->last_cpu matches the CPU, and the fpu_fpregs_owner_ctx
|
||||
* matches the FPU.
|
||||
*
|
||||
* This will disable any lazy FPU state restore of the current FPU state,
|
||||
* but if the current thread owns the FPU, it will still be saved by.
|
||||
* If the FPU register state is valid, the kernel can skip restoring the
|
||||
* FPU state from memory.
|
||||
*
|
||||
* Any code that clobbers the FPU registers or updates the in-memory
|
||||
* FPU state for a task MUST let the rest of the kernel know that the
|
||||
* FPU registers are no longer valid for this task.
|
||||
*
|
||||
* Either one of these invalidation functions is enough. Invalidate
|
||||
* a resource you control: CPU if using the CPU for something else
|
||||
* (with preemption disabled), FPU for the current task, or a task that
|
||||
* is prevented from running by the current task.
|
||||
*/
|
||||
static inline void __cpu_disable_lazy_restore(unsigned int cpu)
|
||||
static inline void __cpu_invalidate_fpregs_state(void)
|
||||
{
|
||||
per_cpu(fpu_fpregs_owner_ctx, cpu) = NULL;
|
||||
__this_cpu_write(fpu_fpregs_owner_ctx, NULL);
|
||||
}
|
||||
|
||||
static inline int fpu_want_lazy_restore(struct fpu *fpu, unsigned int cpu)
|
||||
static inline void __fpu_invalidate_fpregs_state(struct fpu *fpu)
|
||||
{
|
||||
fpu->last_cpu = -1;
|
||||
}
|
||||
|
||||
static inline int fpregs_state_valid(struct fpu *fpu, unsigned int cpu)
|
||||
{
|
||||
return fpu == this_cpu_read_stable(fpu_fpregs_owner_ctx) && cpu == fpu->last_cpu;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wrap lazy FPU TS handling in a 'hw fpregs activation/deactivation'
|
||||
* idiom, which is then paired with the sw-flag (fpregs_active) later on:
|
||||
* These generally need preemption protection to work,
|
||||
* do try to avoid using these on their own:
|
||||
*/
|
||||
|
||||
static inline void __fpregs_activate_hw(void)
|
||||
{
|
||||
if (!use_eager_fpu())
|
||||
clts();
|
||||
}
|
||||
|
||||
static inline void __fpregs_deactivate_hw(void)
|
||||
{
|
||||
if (!use_eager_fpu())
|
||||
stts();
|
||||
}
|
||||
|
||||
/* Must be paired with an 'stts' (fpregs_deactivate_hw()) after! */
|
||||
static inline void __fpregs_deactivate(struct fpu *fpu)
|
||||
static inline void fpregs_deactivate(struct fpu *fpu)
|
||||
{
|
||||
WARN_ON_FPU(!fpu->fpregs_active);
|
||||
|
||||
@@ -528,8 +523,7 @@ static inline void __fpregs_deactivate(struct fpu *fpu)
|
||||
trace_x86_fpu_regs_deactivated(fpu);
|
||||
}
|
||||
|
||||
/* Must be paired with a 'clts' (fpregs_activate_hw()) before! */
|
||||
static inline void __fpregs_activate(struct fpu *fpu)
|
||||
static inline void fpregs_activate(struct fpu *fpu)
|
||||
{
|
||||
WARN_ON_FPU(fpu->fpregs_active);
|
||||
|
||||
@@ -553,52 +547,20 @@ static inline int fpregs_active(void)
|
||||
return current->thread.fpu.fpregs_active;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encapsulate the CR0.TS handling together with the
|
||||
* software flag.
|
||||
*
|
||||
* These generally need preemption protection to work,
|
||||
* do try to avoid using these on their own.
|
||||
*/
|
||||
static inline void fpregs_activate(struct fpu *fpu)
|
||||
{
|
||||
__fpregs_activate_hw();
|
||||
__fpregs_activate(fpu);
|
||||
}
|
||||
|
||||
static inline void fpregs_deactivate(struct fpu *fpu)
|
||||
{
|
||||
__fpregs_deactivate(fpu);
|
||||
__fpregs_deactivate_hw();
|
||||
}
|
||||
|
||||
/*
|
||||
* FPU state switching for scheduling.
|
||||
*
|
||||
* This is a two-stage process:
|
||||
*
|
||||
* - switch_fpu_prepare() saves the old state and
|
||||
* sets the new state of the CR0.TS bit. This is
|
||||
* done within the context of the old process.
|
||||
* - switch_fpu_prepare() saves the old state.
|
||||
* This is done within the context of the old process.
|
||||
*
|
||||
* - switch_fpu_finish() restores the new state as
|
||||
* necessary.
|
||||
*/
|
||||
typedef struct { int preload; } fpu_switch_t;
|
||||
|
||||
static inline fpu_switch_t
|
||||
switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu)
|
||||
static inline void
|
||||
switch_fpu_prepare(struct fpu *old_fpu, int cpu)
|
||||
{
|
||||
fpu_switch_t fpu;
|
||||
|
||||
/*
|
||||
* If the task has used the math, pre-load the FPU on xsave processors
|
||||
* or if the past 5 consecutive context-switches used math.
|
||||
*/
|
||||
fpu.preload = static_cpu_has(X86_FEATURE_FPU) &&
|
||||
new_fpu->fpstate_active &&
|
||||
(use_eager_fpu() || new_fpu->counter > 5);
|
||||
|
||||
if (old_fpu->fpregs_active) {
|
||||
if (!copy_fpregs_to_fpstate(old_fpu))
|
||||
old_fpu->last_cpu = -1;
|
||||
@@ -608,29 +570,8 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu)
|
||||
/* But leave fpu_fpregs_owner_ctx! */
|
||||
old_fpu->fpregs_active = 0;
|
||||
trace_x86_fpu_regs_deactivated(old_fpu);
|
||||
|
||||
/* Don't change CR0.TS if we just switch! */
|
||||
if (fpu.preload) {
|
||||
new_fpu->counter++;
|
||||
__fpregs_activate(new_fpu);
|
||||
trace_x86_fpu_regs_activated(new_fpu);
|
||||
prefetch(&new_fpu->state);
|
||||
} else {
|
||||
__fpregs_deactivate_hw();
|
||||
}
|
||||
} else {
|
||||
old_fpu->counter = 0;
|
||||
} else
|
||||
old_fpu->last_cpu = -1;
|
||||
if (fpu.preload) {
|
||||
new_fpu->counter++;
|
||||
if (fpu_want_lazy_restore(new_fpu, cpu))
|
||||
fpu.preload = 0;
|
||||
else
|
||||
prefetch(&new_fpu->state);
|
||||
fpregs_activate(new_fpu);
|
||||
}
|
||||
}
|
||||
return fpu;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -638,15 +579,19 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu)
|
||||
*/
|
||||
|
||||
/*
|
||||
* By the time this gets called, we've already cleared CR0.TS and
|
||||
* given the process the FPU if we are going to preload the FPU
|
||||
* state - all we need to do is to conditionally restore the register
|
||||
* state itself.
|
||||
* Set up the userspace FPU context for the new task, if the task
|
||||
* has used the FPU.
|
||||
*/
|
||||
static inline void switch_fpu_finish(struct fpu *new_fpu, fpu_switch_t fpu_switch)
|
||||
static inline void switch_fpu_finish(struct fpu *new_fpu, int cpu)
|
||||
{
|
||||
if (fpu_switch.preload)
|
||||
copy_kernel_to_fpregs(&new_fpu->state);
|
||||
bool preload = static_cpu_has(X86_FEATURE_FPU) &&
|
||||
new_fpu->fpstate_active;
|
||||
|
||||
if (preload) {
|
||||
if (!fpregs_state_valid(new_fpu, cpu))
|
||||
copy_kernel_to_fpregs(&new_fpu->state);
|
||||
fpregs_activate(new_fpu);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -321,17 +321,6 @@ struct fpu {
|
||||
*/
|
||||
unsigned char fpregs_active;
|
||||
|
||||
/*
|
||||
* @counter:
|
||||
*
|
||||
* This counter contains the number of consecutive context switches
|
||||
* during which the FPU stays used. If this is over a threshold, the
|
||||
* lazy FPU restore logic becomes eager, to save the trap overhead.
|
||||
* This is an unsigned char so that after 256 iterations the counter
|
||||
* wraps and the context switch behavior turns lazy again; this is to
|
||||
* deal with bursty apps that only use the FPU for a short time:
|
||||
*/
|
||||
unsigned char counter;
|
||||
/*
|
||||
* @state:
|
||||
*
|
||||
@@ -340,29 +329,6 @@ struct fpu {
|
||||
* the registers in the FPU are more recent than this state
|
||||
* copy. If the task context-switches away then they get
|
||||
* saved here and represent the FPU state.
|
||||
*
|
||||
* After context switches there may be a (short) time period
|
||||
* during which the in-FPU hardware registers are unchanged
|
||||
* and still perfectly match this state, if the tasks
|
||||
* scheduled afterwards are not using the FPU.
|
||||
*
|
||||
* This is the 'lazy restore' window of optimization, which
|
||||
* we track though 'fpu_fpregs_owner_ctx' and 'fpu->last_cpu'.
|
||||
*
|
||||
* We detect whether a subsequent task uses the FPU via setting
|
||||
* CR0::TS to 1, which causes any FPU use to raise a #NM fault.
|
||||
*
|
||||
* During this window, if the task gets scheduled again, we
|
||||
* might be able to skip having to do a restore from this
|
||||
* memory buffer to the hardware registers - at the cost of
|
||||
* incurring the overhead of #NM fault traps.
|
||||
*
|
||||
* Note that on modern CPUs that support the XSAVEOPT (or other
|
||||
* optimized XSAVE instructions), we don't use #NM traps anymore,
|
||||
* as the hardware can track whether FPU registers need saving
|
||||
* or not. On such CPUs we activate the non-lazy ('eagerfpu')
|
||||
* logic, which unconditionally saves/restores all FPU state
|
||||
* across context switches. (if FPU state exists.)
|
||||
*/
|
||||
union fpregs_state state;
|
||||
/*
|
||||
|
@@ -21,21 +21,16 @@
|
||||
/* Supervisor features */
|
||||
#define XFEATURE_MASK_SUPERVISOR (XFEATURE_MASK_PT)
|
||||
|
||||
/* Supported features which support lazy state saving */
|
||||
#define XFEATURE_MASK_LAZY (XFEATURE_MASK_FP | \
|
||||
/* All currently supported features */
|
||||
#define XCNTXT_MASK (XFEATURE_MASK_FP | \
|
||||
XFEATURE_MASK_SSE | \
|
||||
XFEATURE_MASK_YMM | \
|
||||
XFEATURE_MASK_OPMASK | \
|
||||
XFEATURE_MASK_ZMM_Hi256 | \
|
||||
XFEATURE_MASK_Hi16_ZMM)
|
||||
|
||||
/* Supported features which require eager state saving */
|
||||
#define XFEATURE_MASK_EAGER (XFEATURE_MASK_BNDREGS | \
|
||||
XFEATURE_MASK_BNDCSR | \
|
||||
XFEATURE_MASK_PKRU)
|
||||
|
||||
/* All currently supported features */
|
||||
#define XCNTXT_MASK (XFEATURE_MASK_LAZY | XFEATURE_MASK_EAGER)
|
||||
XFEATURE_MASK_Hi16_ZMM | \
|
||||
XFEATURE_MASK_PKRU | \
|
||||
XFEATURE_MASK_BNDREGS | \
|
||||
XFEATURE_MASK_BNDCSR)
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define REX_PREFIX "0x48, "
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#define LHCALL_FLUSH_TLB 5
|
||||
#define LHCALL_LOAD_IDT_ENTRY 6
|
||||
#define LHCALL_SET_STACK 7
|
||||
#define LHCALL_TS 8
|
||||
#define LHCALL_SET_CLOCKEVENT 9
|
||||
#define LHCALL_HALT 10
|
||||
#define LHCALL_SET_PMD 13
|
||||
|
@@ -41,11 +41,6 @@ static inline void set_debugreg(unsigned long val, int reg)
|
||||
PVOP_VCALL2(pv_cpu_ops.set_debugreg, reg, val);
|
||||
}
|
||||
|
||||
static inline void clts(void)
|
||||
{
|
||||
PVOP_VCALL0(pv_cpu_ops.clts);
|
||||
}
|
||||
|
||||
static inline unsigned long read_cr0(void)
|
||||
{
|
||||
return PVOP_CALL0(unsigned long, pv_cpu_ops.read_cr0);
|
||||
|
@@ -103,8 +103,6 @@ struct pv_cpu_ops {
|
||||
unsigned long (*get_debugreg)(int regno);
|
||||
void (*set_debugreg)(int regno, unsigned long value);
|
||||
|
||||
void (*clts)(void);
|
||||
|
||||
unsigned long (*read_cr0)(void);
|
||||
void (*write_cr0)(unsigned long);
|
||||
|
||||
|
@@ -6,11 +6,6 @@
|
||||
|
||||
#include <asm/nops.h>
|
||||
|
||||
static inline void native_clts(void)
|
||||
{
|
||||
asm volatile("clts");
|
||||
}
|
||||
|
||||
/*
|
||||
* Volatile isn't enough to prevent the compiler from reordering the
|
||||
* read/write functions for the control registers and messing everything up.
|
||||
@@ -208,16 +203,8 @@ static inline void load_gs_index(unsigned selector)
|
||||
|
||||
#endif
|
||||
|
||||
/* Clear the 'TS' bit */
|
||||
static inline void clts(void)
|
||||
{
|
||||
native_clts();
|
||||
}
|
||||
|
||||
#endif/* CONFIG_PARAVIRT */
|
||||
|
||||
#define stts() write_cr0(read_cr0() | X86_CR0_TS)
|
||||
|
||||
static inline void clflush(volatile void *__p)
|
||||
{
|
||||
asm volatile("clflush %0" : "+m" (*(volatile char __force *)__p));
|
||||
|
@@ -14,7 +14,6 @@ DECLARE_EVENT_CLASS(x86_fpu,
|
||||
__field(struct fpu *, fpu)
|
||||
__field(bool, fpregs_active)
|
||||
__field(bool, fpstate_active)
|
||||
__field(int, counter)
|
||||
__field(u64, xfeatures)
|
||||
__field(u64, xcomp_bv)
|
||||
),
|
||||
@@ -23,17 +22,15 @@ DECLARE_EVENT_CLASS(x86_fpu,
|
||||
__entry->fpu = fpu;
|
||||
__entry->fpregs_active = fpu->fpregs_active;
|
||||
__entry->fpstate_active = fpu->fpstate_active;
|
||||
__entry->counter = fpu->counter;
|
||||
if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
|
||||
__entry->xfeatures = fpu->state.xsave.header.xfeatures;
|
||||
__entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv;
|
||||
}
|
||||
),
|
||||
TP_printk("x86/fpu: %p fpregs_active: %d fpstate_active: %d counter: %d xfeatures: %llx xcomp_bv: %llx",
|
||||
TP_printk("x86/fpu: %p fpregs_active: %d fpstate_active: %d xfeatures: %llx xcomp_bv: %llx",
|
||||
__entry->fpu,
|
||||
__entry->fpregs_active,
|
||||
__entry->fpstate_active,
|
||||
__entry->counter,
|
||||
__entry->xfeatures,
|
||||
__entry->xcomp_bv
|
||||
)
|
||||
|
Reference in New Issue
Block a user