Merge branch 'x86/fpu' into x86/smap
Reason for merge: x86/fpu changed the structure of some of the code that x86/smap changes; mostly fpu-internal.h but also minor changes to the signal code. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> Resolved Conflicts: arch/x86/ia32/ia32_signal.c arch/x86/include/asm/fpu-internal.h arch/x86/kernel/signal.c
This commit is contained in:
commit
49b8c695e3
90 changed files with 1117 additions and 1156 deletions
|
@ -1837,6 +1837,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||||
and restore using xsave. The kernel will fallback to
|
and restore using xsave. The kernel will fallback to
|
||||||
enabling legacy floating-point and sse state.
|
enabling legacy floating-point and sse state.
|
||||||
|
|
||||||
|
eagerfpu= [X86]
|
||||||
|
on enable eager fpu restore
|
||||||
|
off disable eager fpu restore
|
||||||
|
auto selects the default scheme, which automatically
|
||||||
|
enables eagerfpu restore for xsaveopt.
|
||||||
|
|
||||||
nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
|
nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or
|
||||||
wfi(ARM) instruction doesn't work correctly and not to
|
wfi(ARM) instruction doesn't work correctly and not to
|
||||||
use it. This is also useful when using JTAG debugger.
|
use it. This is also useful when using JTAG debugger.
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include <asm/sigframe.h>
|
#include <asm/sigframe.h>
|
||||||
#include <asm/sighandling.h>
|
#include <asm/sighandling.h>
|
||||||
#include <asm/sys_ia32.h>
|
#include <asm/sys_ia32.h>
|
||||||
|
#include <asm/smap.h>
|
||||||
|
|
||||||
#define FIX_EFLAGS __FIX_EFLAGS
|
#define FIX_EFLAGS __FIX_EFLAGS
|
||||||
|
|
||||||
|
@ -162,7 +163,8 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
|
||||||
}
|
}
|
||||||
seg = get_fs();
|
seg = get_fs();
|
||||||
set_fs(KERNEL_DS);
|
set_fs(KERNEL_DS);
|
||||||
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
|
ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL),
|
||||||
|
(stack_t __force __user *) &uoss, regs->sp);
|
||||||
set_fs(seg);
|
set_fs(seg);
|
||||||
if (ret >= 0 && uoss_ptr) {
|
if (ret >= 0 && uoss_ptr) {
|
||||||
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
|
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
|
||||||
|
@ -254,7 +256,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
|
||||||
get_user_ex(*pax, &sc->ax);
|
get_user_ex(*pax, &sc->ax);
|
||||||
} get_user_catch(err);
|
} get_user_catch(err);
|
||||||
|
|
||||||
err |= restore_i387_xstate_ia32(buf);
|
err |= restore_xstate_sig(buf, 1);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -362,7 +364,7 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
|
||||||
*/
|
*/
|
||||||
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||||
size_t frame_size,
|
size_t frame_size,
|
||||||
void **fpstate)
|
void __user **fpstate)
|
||||||
{
|
{
|
||||||
unsigned long sp;
|
unsigned long sp;
|
||||||
|
|
||||||
|
@ -382,9 +384,12 @@ static void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
|
||||||
sp = (unsigned long) ka->sa.sa_restorer;
|
sp = (unsigned long) ka->sa.sa_restorer;
|
||||||
|
|
||||||
if (used_math()) {
|
if (used_math()) {
|
||||||
sp = sp - sig_xstate_ia32_size;
|
unsigned long fx_aligned, math_size;
|
||||||
*fpstate = (struct _fpstate_ia32 *) sp;
|
|
||||||
if (save_i387_xstate_ia32(*fpstate) < 0)
|
sp = alloc_mathframe(sp, 1, &fx_aligned, &math_size);
|
||||||
|
*fpstate = (struct _fpstate_ia32 __user *) sp;
|
||||||
|
if (save_xstate_sig(*fpstate, (void __user *)fx_aligned,
|
||||||
|
math_size) < 0)
|
||||||
return (void __user *) -1L;
|
return (void __user *) -1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,7 +454,7 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
||||||
* These are actually not used anymore, but left because some
|
* These are actually not used anymore, but left because some
|
||||||
* gdb versions depend on them as a marker.
|
* gdb versions depend on them as a marker.
|
||||||
*/
|
*/
|
||||||
put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
|
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
|
||||||
} put_user_catch(err);
|
} put_user_catch(err);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -526,7 +531,7 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
* Not actually used anymore, but left because some gdb
|
* Not actually used anymore, but left because some gdb
|
||||||
* versions need it.
|
* versions need it.
|
||||||
*/
|
*/
|
||||||
put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
|
put_user_ex(*((u64 *)&code), (u64 __user *)frame->retcode);
|
||||||
} put_user_catch(err);
|
} put_user_catch(err);
|
||||||
|
|
||||||
err |= copy_siginfo_to_user32(&frame->info, info);
|
err |= copy_siginfo_to_user32(&frame->info, info);
|
||||||
|
|
|
@ -287,7 +287,7 @@ asmlinkage long sys32_sigaction(int sig, struct old_sigaction32 __user *act,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int *stat_addr,
|
asmlinkage long sys32_waitpid(compat_pid_t pid, unsigned int __user *stat_addr,
|
||||||
int options)
|
int options)
|
||||||
{
|
{
|
||||||
return compat_sys_wait4(pid, stat_addr, options, NULL);
|
return compat_sys_wait4(pid, stat_addr, options, NULL);
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
#define X86_FEATURE_EXTD_APICID (3*32+26) /* has extended APICID (8 bits) */
|
#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_AMD_DCM (3*32+27) /* multi-node processor */
|
||||||
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
|
#define X86_FEATURE_APERFMPERF (3*32+28) /* APERFMPERF */
|
||||||
|
#define X86_FEATURE_EAGER_FPU (3*32+29) /* "eagerfpu" Non lazy FPU restore */
|
||||||
|
|
||||||
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
|
||||||
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
|
#define X86_FEATURE_XMM3 (4*32+ 0) /* "pni" SSE-3 */
|
||||||
|
@ -300,12 +301,14 @@ extern const char * const x86_power_flags[32];
|
||||||
#define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2)
|
#define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2)
|
||||||
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
|
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
|
||||||
#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)
|
#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)
|
||||||
|
#define cpu_has_xsaveopt boot_cpu_has(X86_FEATURE_XSAVEOPT)
|
||||||
#define cpu_has_osxsave boot_cpu_has(X86_FEATURE_OSXSAVE)
|
#define cpu_has_osxsave boot_cpu_has(X86_FEATURE_OSXSAVE)
|
||||||
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
|
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
|
||||||
#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
|
#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
|
||||||
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
|
#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
|
||||||
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
|
#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
|
||||||
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
|
#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
|
||||||
|
#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
|
||||||
|
|
||||||
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
#if defined(CONFIG_X86_INVLPG) || defined(CONFIG_X86_64)
|
||||||
# define cpu_has_invlpg 1
|
# define cpu_has_invlpg 1
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
||||||
#include <linux/regset.h>
|
#include <linux/regset.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <asm/asm.h>
|
#include <asm/asm.h>
|
||||||
#include <asm/cpufeature.h>
|
#include <asm/cpufeature.h>
|
||||||
|
@ -20,43 +21,76 @@
|
||||||
#include <asm/user.h>
|
#include <asm/user.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/xsave.h>
|
#include <asm/xsave.h>
|
||||||
|
#include <asm/smap.h>
|
||||||
|
|
||||||
extern unsigned int sig_xstate_size;
|
#ifdef CONFIG_X86_64
|
||||||
|
# include <asm/sigcontext32.h>
|
||||||
|
# include <asm/user32.h>
|
||||||
|
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
|
compat_sigset_t *set, struct pt_regs *regs);
|
||||||
|
int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
||||||
|
compat_sigset_t *set, struct pt_regs *regs);
|
||||||
|
#else
|
||||||
|
# define user_i387_ia32_struct user_i387_struct
|
||||||
|
# define user32_fxsr_struct user_fxsr_struct
|
||||||
|
# define ia32_setup_frame __setup_frame
|
||||||
|
# define ia32_setup_rt_frame __setup_rt_frame
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern unsigned int mxcsr_feature_mask;
|
||||||
extern void fpu_init(void);
|
extern void fpu_init(void);
|
||||||
|
extern void eager_fpu_init(void);
|
||||||
|
|
||||||
DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
|
DECLARE_PER_CPU(struct task_struct *, fpu_owner_task);
|
||||||
|
|
||||||
|
extern void convert_from_fxsr(struct user_i387_ia32_struct *env,
|
||||||
|
struct task_struct *tsk);
|
||||||
|
extern void convert_to_fxsr(struct task_struct *tsk,
|
||||||
|
const struct user_i387_ia32_struct *env);
|
||||||
|
|
||||||
extern user_regset_active_fn fpregs_active, xfpregs_active;
|
extern user_regset_active_fn fpregs_active, xfpregs_active;
|
||||||
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
|
extern user_regset_get_fn fpregs_get, xfpregs_get, fpregs_soft_get,
|
||||||
xstateregs_get;
|
xstateregs_get;
|
||||||
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
|
extern user_regset_set_fn fpregs_set, xfpregs_set, fpregs_soft_set,
|
||||||
xstateregs_set;
|
xstateregs_set;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xstateregs_active == fpregs_active. Please refer to the comment
|
* xstateregs_active == fpregs_active. Please refer to the comment
|
||||||
* at the definition of fpregs_active.
|
* at the definition of fpregs_active.
|
||||||
*/
|
*/
|
||||||
#define xstateregs_active fpregs_active
|
#define xstateregs_active fpregs_active
|
||||||
|
|
||||||
extern struct _fpx_sw_bytes fx_sw_reserved;
|
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
|
||||||
extern unsigned int sig_xstate_ia32_size;
|
|
||||||
extern struct _fpx_sw_bytes fx_sw_reserved_ia32;
|
|
||||||
struct _fpstate_ia32;
|
|
||||||
struct _xstate_ia32;
|
|
||||||
extern int save_i387_xstate_ia32(void __user *buf);
|
|
||||||
extern int restore_i387_xstate_ia32(void __user *buf);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CONFIG_MATH_EMULATION
|
#ifdef CONFIG_MATH_EMULATION
|
||||||
|
# define HAVE_HWFP (boot_cpu_data.hard_math)
|
||||||
extern void finit_soft_fpu(struct i387_soft_struct *soft);
|
extern void finit_soft_fpu(struct i387_soft_struct *soft);
|
||||||
#else
|
#else
|
||||||
|
# define HAVE_HWFP 1
|
||||||
static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
|
static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline int is_ia32_compat_frame(void)
|
||||||
|
{
|
||||||
|
return config_enabled(CONFIG_IA32_EMULATION) &&
|
||||||
|
test_thread_flag(TIF_IA32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_ia32_frame(void)
|
||||||
|
{
|
||||||
|
return config_enabled(CONFIG_X86_32) || is_ia32_compat_frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_x32_frame(void)
|
||||||
|
{
|
||||||
|
return config_enabled(CONFIG_X86_X32_ABI) && test_thread_flag(TIF_X32);
|
||||||
|
}
|
||||||
|
|
||||||
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
#define X87_FSW_ES (1 << 7) /* Exception Summary */
|
||||||
|
|
||||||
|
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)
|
static __always_inline __pure bool use_xsaveopt(void)
|
||||||
{
|
{
|
||||||
return static_cpu_has(X86_FEATURE_XSAVEOPT);
|
return static_cpu_has(X86_FEATURE_XSAVEOPT);
|
||||||
|
@ -72,6 +106,13 @@ static __always_inline __pure bool use_fxsr(void)
|
||||||
return static_cpu_has(X86_FEATURE_FXSR);
|
return static_cpu_has(X86_FEATURE_FXSR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void fx_finit(struct i387_fxsave_struct *fx)
|
||||||
|
{
|
||||||
|
memset(fx, 0, xstate_size);
|
||||||
|
fx->cwd = 0x37f;
|
||||||
|
fx->mxcsr = MXCSR_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
extern void __sanitize_i387_state(struct task_struct *);
|
extern void __sanitize_i387_state(struct task_struct *);
|
||||||
|
|
||||||
static inline void sanitize_i387_state(struct task_struct *tsk)
|
static inline void sanitize_i387_state(struct task_struct *tsk)
|
||||||
|
@ -81,133 +122,104 @@ static inline void sanitize_i387_state(struct task_struct *tsk)
|
||||||
__sanitize_i387_state(tsk);
|
__sanitize_i387_state(tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
#define user_insn(insn, output, input...) \
|
||||||
static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
|
({ \
|
||||||
{
|
int err; \
|
||||||
int err;
|
asm volatile(ASM_STAC "\n" \
|
||||||
|
"1:" #insn "\n\t" \
|
||||||
|
"2: " ASM_CLAC "\n" \
|
||||||
|
".section .fixup,\"ax\"\n" \
|
||||||
|
"3: movl $-1,%[err]\n" \
|
||||||
|
" jmp 2b\n" \
|
||||||
|
".previous\n" \
|
||||||
|
_ASM_EXTABLE(1b, 3b) \
|
||||||
|
: [err] "=r" (err), output \
|
||||||
|
: "0"(0), input); \
|
||||||
|
err; \
|
||||||
|
})
|
||||||
|
|
||||||
/* See comment in fxsave() below. */
|
#define check_insn(insn, output, input...) \
|
||||||
#ifdef CONFIG_AS_FXSAVEQ
|
({ \
|
||||||
asm volatile("1: fxrstorq %[fx]\n\t"
|
int err; \
|
||||||
"2:\n"
|
asm volatile("1:" #insn "\n\t" \
|
||||||
".section .fixup,\"ax\"\n"
|
"2:\n" \
|
||||||
"3: movl $-1,%[err]\n"
|
".section .fixup,\"ax\"\n" \
|
||||||
" jmp 2b\n"
|
"3: movl $-1,%[err]\n" \
|
||||||
".previous\n"
|
" jmp 2b\n" \
|
||||||
_ASM_EXTABLE(1b, 3b)
|
".previous\n" \
|
||||||
: [err] "=r" (err)
|
_ASM_EXTABLE(1b, 3b) \
|
||||||
: [fx] "m" (*fx), "0" (0));
|
: [err] "=r" (err), output \
|
||||||
#else
|
: "0"(0), input); \
|
||||||
asm volatile("1: rex64/fxrstor (%[fx])\n\t"
|
err; \
|
||||||
"2:\n"
|
})
|
||||||
".section .fixup,\"ax\"\n"
|
|
||||||
"3: movl $-1,%[err]\n"
|
static inline int fsave_user(struct i387_fsave_struct __user *fx)
|
||||||
" jmp 2b\n"
|
{
|
||||||
".previous\n"
|
return user_insn(fnsave %[fx]; fwait, [fx] "=m" (*fx), "m" (*fx));
|
||||||
_ASM_EXTABLE(1b, 3b)
|
|
||||||
: [err] "=r" (err)
|
|
||||||
: [fx] "R" (fx), "m" (*fx), "0" (0));
|
|
||||||
#endif
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
|
static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
|
||||||
{
|
{
|
||||||
int err;
|
if (config_enabled(CONFIG_X86_32))
|
||||||
|
return user_insn(fxsave %[fx], [fx] "=m" (*fx), "m" (*fx));
|
||||||
|
else if (config_enabled(CONFIG_AS_FXSAVEQ))
|
||||||
|
return user_insn(fxsaveq %[fx], [fx] "=m" (*fx), "m" (*fx));
|
||||||
|
|
||||||
/*
|
/* See comment in fpu_fxsave() below. */
|
||||||
* Clear the bytes not touched by the fxsave and reserved
|
return user_insn(rex64/fxsave (%[fx]), "=m" (*fx), [fx] "R" (fx));
|
||||||
* for the SW usage.
|
|
||||||
*/
|
|
||||||
err = __clear_user(&fx->sw_reserved,
|
|
||||||
sizeof(struct _fpx_sw_bytes));
|
|
||||||
if (unlikely(err))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/* See comment in fxsave() below. */
|
|
||||||
#ifdef CONFIG_AS_FXSAVEQ
|
|
||||||
asm volatile(ASM_STAC "\n"
|
|
||||||
"1: fxsaveq %[fx]\n\t"
|
|
||||||
"2: " ASM_CLAC "\n"
|
|
||||||
".section .fixup,\"ax\"\n"
|
|
||||||
"3: movl $-1,%[err]\n"
|
|
||||||
" jmp 2b\n"
|
|
||||||
".previous\n"
|
|
||||||
_ASM_EXTABLE(1b, 3b)
|
|
||||||
: [err] "=r" (err), [fx] "=m" (*fx)
|
|
||||||
: "0" (0));
|
|
||||||
#else
|
|
||||||
asm volatile(ASM_STAC "\n"
|
|
||||||
"1: rex64/fxsave (%[fx])\n\t"
|
|
||||||
"2: " ASM_CLAC "\n"
|
|
||||||
".section .fixup,\"ax\"\n"
|
|
||||||
"3: movl $-1,%[err]\n"
|
|
||||||
" jmp 2b\n"
|
|
||||||
".previous\n"
|
|
||||||
_ASM_EXTABLE(1b, 3b)
|
|
||||||
: [err] "=r" (err), "=m" (*fx)
|
|
||||||
: [fx] "R" (fx), "0" (0));
|
|
||||||
#endif
|
|
||||||
if (unlikely(err) &&
|
|
||||||
__clear_user(fx, sizeof(struct i387_fxsave_struct)))
|
|
||||||
err = -EFAULT;
|
|
||||||
/* No need to clear here because the caller clears USED_MATH */
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fpu_fxsave(struct fpu *fpu)
|
|
||||||
{
|
|
||||||
/* Using "rex64; fxsave %0" is broken because, if the memory operand
|
|
||||||
uses any extended registers for addressing, a second REX prefix
|
|
||||||
will be generated (to the assembler, rex64 followed by semicolon
|
|
||||||
is a separate instruction), and hence the 64-bitness is lost. */
|
|
||||||
|
|
||||||
#ifdef CONFIG_AS_FXSAVEQ
|
|
||||||
/* Using "fxsaveq %0" would be the ideal choice, but is only supported
|
|
||||||
starting with gas 2.16. */
|
|
||||||
__asm__ __volatile__("fxsaveq %0"
|
|
||||||
: "=m" (fpu->state->fxsave));
|
|
||||||
#else
|
|
||||||
/* Using, as a workaround, the properly prefixed form below isn't
|
|
||||||
accepted by any binutils version so far released, complaining that
|
|
||||||
the same type of prefix is used twice if an extended register is
|
|
||||||
needed for addressing (fix submitted to mainline 2005-11-21).
|
|
||||||
asm volatile("rex64/fxsave %0"
|
|
||||||
: "=m" (fpu->state->fxsave));
|
|
||||||
This, however, we can work around by forcing the compiler to select
|
|
||||||
an addressing mode that doesn't require extended registers. */
|
|
||||||
asm volatile("rex64/fxsave (%[fx])"
|
|
||||||
: "=m" (fpu->state->fxsave)
|
|
||||||
: [fx] "R" (&fpu->state->fxsave));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* CONFIG_X86_32 */
|
|
||||||
|
|
||||||
/* perform fxrstor iff the processor has extended states, otherwise frstor */
|
|
||||||
static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
|
static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
|
||||||
{
|
{
|
||||||
/*
|
if (config_enabled(CONFIG_X86_32))
|
||||||
* The "nop" is needed to make the instructions the same
|
return check_insn(fxrstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
||||||
* length.
|
else if (config_enabled(CONFIG_AS_FXSAVEQ))
|
||||||
*/
|
return check_insn(fxrstorq %[fx], "=m" (*fx), [fx] "m" (*fx));
|
||||||
alternative_input(
|
|
||||||
"nop ; frstor %1",
|
|
||||||
"fxrstor %1",
|
|
||||||
X86_FEATURE_FXSR,
|
|
||||||
"m" (*fx));
|
|
||||||
|
|
||||||
return 0;
|
/* See comment in fpu_fxsave() below. */
|
||||||
|
return check_insn(rex64/fxrstor (%[fx]), "=m" (*fx), [fx] "R" (fx),
|
||||||
|
"m" (*fx));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int frstor_checking(struct i387_fsave_struct *fx)
|
||||||
|
{
|
||||||
|
return check_insn(frstor %[fx], "=m" (*fx), [fx] "m" (*fx));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fpu_fxsave(struct fpu *fpu)
|
static inline void fpu_fxsave(struct fpu *fpu)
|
||||||
{
|
{
|
||||||
asm volatile("fxsave %[fx]"
|
if (config_enabled(CONFIG_X86_32))
|
||||||
: [fx] "=m" (fpu->state->fxsave));
|
asm volatile( "fxsave %[fx]" : [fx] "=m" (fpu->state->fxsave));
|
||||||
|
else if (config_enabled(CONFIG_AS_FXSAVEQ))
|
||||||
|
asm volatile("fxsaveq %0" : "=m" (fpu->state->fxsave));
|
||||||
|
else {
|
||||||
|
/* Using "rex64; fxsave %0" is broken because, if the memory
|
||||||
|
* operand uses any extended registers for addressing, a second
|
||||||
|
* REX prefix will be generated (to the assembler, rex64
|
||||||
|
* followed by semicolon is a separate instruction), and hence
|
||||||
|
* the 64-bitness is lost.
|
||||||
|
*
|
||||||
|
* Using "fxsaveq %0" would be the ideal choice, but is only
|
||||||
|
* supported starting with gas 2.16.
|
||||||
|
*
|
||||||
|
* Using, as a workaround, the properly prefixed form below
|
||||||
|
* isn't accepted by any binutils version so far released,
|
||||||
|
* complaining that the same type of prefix is used twice if
|
||||||
|
* an extended register is needed for addressing (fix submitted
|
||||||
|
* to mainline 2005-11-21).
|
||||||
|
*
|
||||||
|
* asm volatile("rex64/fxsave %0" : "=m" (fpu->state->fxsave));
|
||||||
|
*
|
||||||
|
* This, however, we can work around by forcing the compiler to
|
||||||
|
* select an addressing mode that doesn't require extended
|
||||||
|
* registers.
|
||||||
|
*/
|
||||||
|
asm volatile( "rex64/fxsave (%[fx])"
|
||||||
|
: "=m" (fpu->state->fxsave)
|
||||||
|
: [fx] "R" (&fpu->state->fxsave));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These must be called with preempt disabled. Returns
|
* These must be called with preempt disabled. Returns
|
||||||
* 'true' if the FPU state is still intact.
|
* 'true' if the FPU state is still intact.
|
||||||
|
@ -250,17 +262,14 @@ static inline int __save_init_fpu(struct task_struct *tsk)
|
||||||
return fpu_save_init(&tsk->thread.fpu);
|
return fpu_save_init(&tsk->thread.fpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int fpu_fxrstor_checking(struct fpu *fpu)
|
|
||||||
{
|
|
||||||
return fxrstor_checking(&fpu->state->fxsave);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int fpu_restore_checking(struct fpu *fpu)
|
static inline int fpu_restore_checking(struct fpu *fpu)
|
||||||
{
|
{
|
||||||
if (use_xsave())
|
if (use_xsave())
|
||||||
return fpu_xrstor_checking(fpu);
|
return fpu_xrstor_checking(&fpu->state->xsave);
|
||||||
|
else if (use_fxsr())
|
||||||
|
return fxrstor_checking(&fpu->state->fxsave);
|
||||||
else
|
else
|
||||||
return fpu_fxrstor_checking(fpu);
|
return frstor_checking(&fpu->state->fsave);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int restore_fpu_checking(struct task_struct *tsk)
|
static inline int restore_fpu_checking(struct task_struct *tsk)
|
||||||
|
@ -312,15 +321,52 @@ static inline void __thread_set_has_fpu(struct task_struct *tsk)
|
||||||
static inline void __thread_fpu_end(struct task_struct *tsk)
|
static inline void __thread_fpu_end(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
__thread_clear_has_fpu(tsk);
|
__thread_clear_has_fpu(tsk);
|
||||||
|
if (!use_eager_fpu())
|
||||||
stts();
|
stts();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void __thread_fpu_begin(struct task_struct *tsk)
|
static inline void __thread_fpu_begin(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
|
if (!use_eager_fpu())
|
||||||
clts();
|
clts();
|
||||||
__thread_set_has_fpu(tsk);
|
__thread_set_has_fpu(tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void __drop_fpu(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
if (__thread_has_fpu(tsk)) {
|
||||||
|
/* Ignore delayed exceptions from user space */
|
||||||
|
asm volatile("1: fwait\n"
|
||||||
|
"2:\n"
|
||||||
|
_ASM_EXTABLE(1b, 2b));
|
||||||
|
__thread_fpu_end(tsk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void drop_fpu(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Forget coprocessor state..
|
||||||
|
*/
|
||||||
|
preempt_disable();
|
||||||
|
tsk->fpu_counter = 0;
|
||||||
|
__drop_fpu(tsk);
|
||||||
|
clear_used_math();
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void drop_init_fpu(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
if (!use_eager_fpu())
|
||||||
|
drop_fpu(tsk);
|
||||||
|
else {
|
||||||
|
if (use_xsave())
|
||||||
|
xrstor_state(init_xstate_buf, -1);
|
||||||
|
else
|
||||||
|
fxrstor_checking(&init_xstate_buf->i387);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FPU state switching for scheduling.
|
* FPU state switching for scheduling.
|
||||||
*
|
*
|
||||||
|
@ -354,7 +400,12 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
|
||||||
{
|
{
|
||||||
fpu_switch_t fpu;
|
fpu_switch_t fpu;
|
||||||
|
|
||||||
fpu.preload = tsk_used_math(new) && new->fpu_counter > 5;
|
/*
|
||||||
|
* 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 = tsk_used_math(new) && (use_eager_fpu() ||
|
||||||
|
new->fpu_counter > 5);
|
||||||
if (__thread_has_fpu(old)) {
|
if (__thread_has_fpu(old)) {
|
||||||
if (!__save_init_fpu(old))
|
if (!__save_init_fpu(old))
|
||||||
cpu = ~0;
|
cpu = ~0;
|
||||||
|
@ -366,14 +417,14 @@ static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct ta
|
||||||
new->fpu_counter++;
|
new->fpu_counter++;
|
||||||
__thread_set_has_fpu(new);
|
__thread_set_has_fpu(new);
|
||||||
prefetch(new->thread.fpu.state);
|
prefetch(new->thread.fpu.state);
|
||||||
} else
|
} else if (!use_eager_fpu())
|
||||||
stts();
|
stts();
|
||||||
} else {
|
} else {
|
||||||
old->fpu_counter = 0;
|
old->fpu_counter = 0;
|
||||||
old->thread.fpu.last_cpu = ~0;
|
old->thread.fpu.last_cpu = ~0;
|
||||||
if (fpu.preload) {
|
if (fpu.preload) {
|
||||||
new->fpu_counter++;
|
new->fpu_counter++;
|
||||||
if (fpu_lazy_restore(new, cpu))
|
if (!use_eager_fpu() && fpu_lazy_restore(new, cpu))
|
||||||
fpu.preload = 0;
|
fpu.preload = 0;
|
||||||
else
|
else
|
||||||
prefetch(new->thread.fpu.state);
|
prefetch(new->thread.fpu.state);
|
||||||
|
@ -393,44 +444,40 @@ static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu)
|
||||||
{
|
{
|
||||||
if (fpu.preload) {
|
if (fpu.preload) {
|
||||||
if (unlikely(restore_fpu_checking(new)))
|
if (unlikely(restore_fpu_checking(new)))
|
||||||
__thread_fpu_end(new);
|
drop_init_fpu(new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signal frame handlers...
|
* Signal frame handlers...
|
||||||
*/
|
*/
|
||||||
extern int save_i387_xstate(void __user *buf);
|
extern int save_xstate_sig(void __user *buf, void __user *fx, int size);
|
||||||
extern int restore_i387_xstate(void __user *buf);
|
extern int __restore_xstate_sig(void __user *buf, void __user *fx, int size);
|
||||||
|
|
||||||
static inline void __clear_fpu(struct task_struct *tsk)
|
static inline int xstate_sigframe_size(void)
|
||||||
{
|
{
|
||||||
if (__thread_has_fpu(tsk)) {
|
return use_xsave() ? xstate_size + FP_XSTATE_MAGIC2_SIZE : xstate_size;
|
||||||
/* Ignore delayed exceptions from user space */
|
}
|
||||||
asm volatile("1: fwait\n"
|
|
||||||
"2:\n"
|
static inline int restore_xstate_sig(void __user *buf, int ia32_frame)
|
||||||
_ASM_EXTABLE(1b, 2b));
|
{
|
||||||
__thread_fpu_end(tsk);
|
void __user *buf_fx = buf;
|
||||||
|
int size = xstate_sigframe_size();
|
||||||
|
|
||||||
|
if (ia32_frame && use_fxsr()) {
|
||||||
|
buf_fx = buf + sizeof(struct i387_fsave_struct);
|
||||||
|
size += sizeof(struct i387_fsave_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return __restore_xstate_sig(buf, buf_fx, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The actual user_fpu_begin/end() functions
|
* Need to be preemption-safe.
|
||||||
* need to be preemption-safe.
|
|
||||||
*
|
*
|
||||||
* NOTE! user_fpu_end() must be used only after you
|
* NOTE! user_fpu_begin() must be used only immediately before restoring
|
||||||
* have saved the FP state, and user_fpu_begin() must
|
* it. This function does not do any save/restore on their own.
|
||||||
* be used only immediately before restoring it.
|
|
||||||
* These functions do not do any save/restore on
|
|
||||||
* their own.
|
|
||||||
*/
|
*/
|
||||||
static inline void user_fpu_end(void)
|
|
||||||
{
|
|
||||||
preempt_disable();
|
|
||||||
__thread_fpu_end(current);
|
|
||||||
preempt_enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void user_fpu_begin(void)
|
static inline void user_fpu_begin(void)
|
||||||
{
|
{
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
@ -439,25 +486,32 @@ static inline void user_fpu_begin(void)
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void __save_fpu(struct task_struct *tsk)
|
||||||
|
{
|
||||||
|
if (use_xsave())
|
||||||
|
xsave_state(&tsk->thread.fpu.state->xsave, -1);
|
||||||
|
else
|
||||||
|
fpu_fxsave(&tsk->thread.fpu);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These disable preemption on their own and are safe
|
* These disable preemption on their own and are safe
|
||||||
*/
|
*/
|
||||||
static inline void save_init_fpu(struct task_struct *tsk)
|
static inline void save_init_fpu(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
WARN_ON_ONCE(!__thread_has_fpu(tsk));
|
WARN_ON_ONCE(!__thread_has_fpu(tsk));
|
||||||
|
|
||||||
|
if (use_eager_fpu()) {
|
||||||
|
__save_fpu(tsk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
__save_init_fpu(tsk);
|
__save_init_fpu(tsk);
|
||||||
__thread_fpu_end(tsk);
|
__thread_fpu_end(tsk);
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void clear_fpu(struct task_struct *tsk)
|
|
||||||
{
|
|
||||||
preempt_disable();
|
|
||||||
__clear_fpu(tsk);
|
|
||||||
preempt_enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* i387 state interaction
|
* i387 state interaction
|
||||||
*/
|
*/
|
||||||
|
@ -512,11 +566,34 @@ static inline void fpu_free(struct fpu *fpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fpu_copy(struct fpu *dst, struct fpu *src)
|
static inline void fpu_copy(struct task_struct *dst, struct task_struct *src)
|
||||||
{
|
{
|
||||||
memcpy(dst->state, src->state, xstate_size);
|
if (use_eager_fpu()) {
|
||||||
|
memset(&dst->thread.fpu.state->xsave, 0, xstate_size);
|
||||||
|
__save_fpu(dst);
|
||||||
|
} else {
|
||||||
|
struct fpu *dfpu = &dst->thread.fpu;
|
||||||
|
struct fpu *sfpu = &src->thread.fpu;
|
||||||
|
|
||||||
|
unlazy_fpu(src);
|
||||||
|
memcpy(dfpu->state, sfpu->state, xstate_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void fpu_finit(struct fpu *fpu);
|
static inline unsigned long
|
||||||
|
alloc_mathframe(unsigned long sp, int ia32_frame, unsigned long *buf_fx,
|
||||||
|
unsigned long *size)
|
||||||
|
{
|
||||||
|
unsigned long frame_size = xstate_sigframe_size();
|
||||||
|
|
||||||
|
*buf_fx = sp = round_down(sp - frame_size, 64);
|
||||||
|
if (ia32_frame && use_fxsr()) {
|
||||||
|
frame_size += sizeof(struct i387_fsave_struct);
|
||||||
|
sp -= sizeof(struct i387_fsave_struct);
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = frame_size;
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,12 +19,37 @@ struct pt_regs;
|
||||||
struct user_i387_struct;
|
struct user_i387_struct;
|
||||||
|
|
||||||
extern int init_fpu(struct task_struct *child);
|
extern int init_fpu(struct task_struct *child);
|
||||||
|
extern void fpu_finit(struct fpu *fpu);
|
||||||
extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
|
extern int dump_fpu(struct pt_regs *, struct user_i387_struct *);
|
||||||
extern void math_state_restore(void);
|
extern void math_state_restore(void);
|
||||||
|
|
||||||
extern bool irq_fpu_usable(void);
|
extern bool irq_fpu_usable(void);
|
||||||
extern void kernel_fpu_begin(void);
|
|
||||||
extern void kernel_fpu_end(void);
|
/*
|
||||||
|
* Careful: __kernel_fpu_begin/end() must be called with preempt disabled
|
||||||
|
* and they don't touch the preempt state on their own.
|
||||||
|
* If you enable preemption after __kernel_fpu_begin(), preempt notifier
|
||||||
|
* should call the __kernel_fpu_end() to prevent the kernel/user FPU
|
||||||
|
* state from getting corrupted. KVM for example uses this model.
|
||||||
|
*
|
||||||
|
* All other cases use kernel_fpu_begin/end() which disable preemption
|
||||||
|
* during kernel FPU usage.
|
||||||
|
*/
|
||||||
|
extern void __kernel_fpu_begin(void);
|
||||||
|
extern void __kernel_fpu_end(void);
|
||||||
|
|
||||||
|
static inline void kernel_fpu_begin(void)
|
||||||
|
{
|
||||||
|
WARN_ON_ONCE(!irq_fpu_usable());
|
||||||
|
preempt_disable();
|
||||||
|
__kernel_fpu_begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void kernel_fpu_end(void)
|
||||||
|
{
|
||||||
|
__kernel_fpu_end();
|
||||||
|
preempt_enable();
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some instructions like VIA's padlock instructions generate a spurious
|
* Some instructions like VIA's padlock instructions generate a spurious
|
||||||
|
|
|
@ -48,7 +48,7 @@ struct iommu_table_entry {
|
||||||
|
|
||||||
|
|
||||||
#define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\
|
#define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\
|
||||||
static const struct iommu_table_entry const \
|
static const struct iommu_table_entry \
|
||||||
__iommu_entry_##_detect __used \
|
__iommu_entry_##_detect __used \
|
||||||
__attribute__ ((unused, __section__(".iommu_table"), \
|
__attribute__ ((unused, __section__(".iommu_table"), \
|
||||||
aligned((sizeof(void *))))) \
|
aligned((sizeof(void *))))) \
|
||||||
|
@ -63,10 +63,10 @@ struct iommu_table_entry {
|
||||||
* to stop detecting the other IOMMUs after yours has been detected.
|
* to stop detecting the other IOMMUs after yours has been detected.
|
||||||
*/
|
*/
|
||||||
#define IOMMU_INIT_POST(_detect) \
|
#define IOMMU_INIT_POST(_detect) \
|
||||||
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 0)
|
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, NULL, NULL, 0)
|
||||||
|
|
||||||
#define IOMMU_INIT_POST_FINISH(detect) \
|
#define IOMMU_INIT_POST_FINISH(detect) \
|
||||||
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, 0, 0, 1)
|
__IOMMU_INIT(_detect, pci_swiotlb_detect_4gb, NULL, NULL, 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A more sophisticated version of IOMMU_INIT. This variant requires:
|
* A more sophisticated version of IOMMU_INIT. This variant requires:
|
||||||
|
|
|
@ -31,6 +31,10 @@ typedef struct {
|
||||||
unsigned long sig[_NSIG_WORDS];
|
unsigned long sig[_NSIG_WORDS];
|
||||||
} sigset_t;
|
} sigset_t;
|
||||||
|
|
||||||
|
#ifndef CONFIG_COMPAT
|
||||||
|
typedef sigset_t compat_sigset_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
/* Here we must cater to libcs that poke about in kernel headers. */
|
/* Here we must cater to libcs that poke about in kernel headers. */
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ asmlinkage long sys32_sigaction(int, struct old_sigaction32 __user *,
|
||||||
struct old_sigaction32 __user *);
|
struct old_sigaction32 __user *);
|
||||||
asmlinkage long sys32_alarm(unsigned int);
|
asmlinkage long sys32_alarm(unsigned int);
|
||||||
|
|
||||||
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int *, int);
|
asmlinkage long sys32_waitpid(compat_pid_t, unsigned int __user *, int);
|
||||||
asmlinkage long sys32_sysfs(int, u32, u32);
|
asmlinkage long sys32_sysfs(int, u32, u32);
|
||||||
|
|
||||||
asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
|
asmlinkage long sys32_sched_rr_get_interval(compat_pid_t,
|
||||||
|
|
|
@ -11,7 +11,8 @@ extern const char VDSO32_PRELINK[];
|
||||||
#define VDSO32_SYMBOL(base, name) \
|
#define VDSO32_SYMBOL(base, name) \
|
||||||
({ \
|
({ \
|
||||||
extern const char VDSO32_##name[]; \
|
extern const char VDSO32_##name[]; \
|
||||||
(void *)(VDSO32_##name - VDSO32_PRELINK + (unsigned long)(base)); \
|
(void __user *)(VDSO32_##name - VDSO32_PRELINK + \
|
||||||
|
(unsigned long)(base)); \
|
||||||
})
|
})
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -534,38 +534,6 @@ static struct xor_block_template xor_block_p5_mmx = {
|
||||||
* Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
|
* Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define XMMS_SAVE \
|
|
||||||
do { \
|
|
||||||
preempt_disable(); \
|
|
||||||
cr0 = read_cr0(); \
|
|
||||||
clts(); \
|
|
||||||
asm volatile( \
|
|
||||||
"movups %%xmm0,(%0) ;\n\t" \
|
|
||||||
"movups %%xmm1,0x10(%0) ;\n\t" \
|
|
||||||
"movups %%xmm2,0x20(%0) ;\n\t" \
|
|
||||||
"movups %%xmm3,0x30(%0) ;\n\t" \
|
|
||||||
: \
|
|
||||||
: "r" (xmm_save) \
|
|
||||||
: "memory"); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XMMS_RESTORE \
|
|
||||||
do { \
|
|
||||||
asm volatile( \
|
|
||||||
"sfence ;\n\t" \
|
|
||||||
"movups (%0),%%xmm0 ;\n\t" \
|
|
||||||
"movups 0x10(%0),%%xmm1 ;\n\t" \
|
|
||||||
"movups 0x20(%0),%%xmm2 ;\n\t" \
|
|
||||||
"movups 0x30(%0),%%xmm3 ;\n\t" \
|
|
||||||
: \
|
|
||||||
: "r" (xmm_save) \
|
|
||||||
: "memory"); \
|
|
||||||
write_cr0(cr0); \
|
|
||||||
preempt_enable(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define ALIGN16 __attribute__((aligned(16)))
|
|
||||||
|
|
||||||
#define OFFS(x) "16*("#x")"
|
#define OFFS(x) "16*("#x")"
|
||||||
#define PF_OFFS(x) "256+16*("#x")"
|
#define PF_OFFS(x) "256+16*("#x")"
|
||||||
#define PF0(x) " prefetchnta "PF_OFFS(x)"(%1) ;\n"
|
#define PF0(x) " prefetchnta "PF_OFFS(x)"(%1) ;\n"
|
||||||
|
@ -587,10 +555,8 @@ static void
|
||||||
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||||
{
|
{
|
||||||
unsigned long lines = bytes >> 8;
|
unsigned long lines = bytes >> 8;
|
||||||
char xmm_save[16*4] ALIGN16;
|
|
||||||
int cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -633,7 +599,7 @@ xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||||
:
|
:
|
||||||
: "memory");
|
: "memory");
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -641,10 +607,8 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
unsigned long *p3)
|
unsigned long *p3)
|
||||||
{
|
{
|
||||||
unsigned long lines = bytes >> 8;
|
unsigned long lines = bytes >> 8;
|
||||||
char xmm_save[16*4] ALIGN16;
|
|
||||||
int cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -694,7 +658,7 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
:
|
:
|
||||||
: "memory" );
|
: "memory" );
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -702,10 +666,8 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
unsigned long *p3, unsigned long *p4)
|
unsigned long *p3, unsigned long *p4)
|
||||||
{
|
{
|
||||||
unsigned long lines = bytes >> 8;
|
unsigned long lines = bytes >> 8;
|
||||||
char xmm_save[16*4] ALIGN16;
|
|
||||||
int cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -762,7 +724,7 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
:
|
:
|
||||||
: "memory" );
|
: "memory" );
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -770,10 +732,8 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
unsigned long *p3, unsigned long *p4, unsigned long *p5)
|
unsigned long *p3, unsigned long *p4, unsigned long *p5)
|
||||||
{
|
{
|
||||||
unsigned long lines = bytes >> 8;
|
unsigned long lines = bytes >> 8;
|
||||||
char xmm_save[16*4] ALIGN16;
|
|
||||||
int cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
/* Make sure GCC forgets anything it knows about p4 or p5,
|
/* Make sure GCC forgets anything it knows about p4 or p5,
|
||||||
such that it won't pass to the asm volatile below a
|
such that it won't pass to the asm volatile below a
|
||||||
|
@ -850,7 +810,7 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
like assuming they have some legal value. */
|
like assuming they have some legal value. */
|
||||||
asm("" : "=r" (p4), "=r" (p5));
|
asm("" : "=r" (p4), "=r" (p5));
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xor_block_template xor_block_pIII_sse = {
|
static struct xor_block_template xor_block_pIII_sse = {
|
||||||
|
|
|
@ -34,41 +34,7 @@
|
||||||
* no advantages to be gotten from x86-64 here anyways.
|
* no advantages to be gotten from x86-64 here anyways.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct {
|
#include <asm/i387.h>
|
||||||
unsigned long a, b;
|
|
||||||
} __attribute__((aligned(16))) xmm_store_t;
|
|
||||||
|
|
||||||
/* Doesn't use gcc to save the XMM registers, because there is no easy way to
|
|
||||||
tell it to do a clts before the register saving. */
|
|
||||||
#define XMMS_SAVE \
|
|
||||||
do { \
|
|
||||||
preempt_disable(); \
|
|
||||||
asm volatile( \
|
|
||||||
"movq %%cr0,%0 ;\n\t" \
|
|
||||||
"clts ;\n\t" \
|
|
||||||
"movups %%xmm0,(%1) ;\n\t" \
|
|
||||||
"movups %%xmm1,0x10(%1) ;\n\t" \
|
|
||||||
"movups %%xmm2,0x20(%1) ;\n\t" \
|
|
||||||
"movups %%xmm3,0x30(%1) ;\n\t" \
|
|
||||||
: "=&r" (cr0) \
|
|
||||||
: "r" (xmm_save) \
|
|
||||||
: "memory"); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define XMMS_RESTORE \
|
|
||||||
do { \
|
|
||||||
asm volatile( \
|
|
||||||
"sfence ;\n\t" \
|
|
||||||
"movups (%1),%%xmm0 ;\n\t" \
|
|
||||||
"movups 0x10(%1),%%xmm1 ;\n\t" \
|
|
||||||
"movups 0x20(%1),%%xmm2 ;\n\t" \
|
|
||||||
"movups 0x30(%1),%%xmm3 ;\n\t" \
|
|
||||||
"movq %0,%%cr0 ;\n\t" \
|
|
||||||
: \
|
|
||||||
: "r" (cr0), "r" (xmm_save) \
|
|
||||||
: "memory"); \
|
|
||||||
preempt_enable(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define OFFS(x) "16*("#x")"
|
#define OFFS(x) "16*("#x")"
|
||||||
#define PF_OFFS(x) "256+16*("#x")"
|
#define PF_OFFS(x) "256+16*("#x")"
|
||||||
|
@ -91,10 +57,8 @@ static void
|
||||||
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||||
{
|
{
|
||||||
unsigned int lines = bytes >> 8;
|
unsigned int lines = bytes >> 8;
|
||||||
unsigned long cr0;
|
|
||||||
xmm_store_t xmm_save[4];
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -135,7 +99,7 @@ xor_sse_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
|
||||||
: [inc] "r" (256UL)
|
: [inc] "r" (256UL)
|
||||||
: "memory");
|
: "memory");
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -143,11 +107,8 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
unsigned long *p3)
|
unsigned long *p3)
|
||||||
{
|
{
|
||||||
unsigned int lines = bytes >> 8;
|
unsigned int lines = bytes >> 8;
|
||||||
xmm_store_t xmm_save[4];
|
|
||||||
unsigned long cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
|
||||||
|
|
||||||
|
kernel_fpu_begin();
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
#define BLOCK(i) \
|
#define BLOCK(i) \
|
||||||
|
@ -194,7 +155,7 @@ xor_sse_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
[p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
|
[p1] "+r" (p1), [p2] "+r" (p2), [p3] "+r" (p3)
|
||||||
: [inc] "r" (256UL)
|
: [inc] "r" (256UL)
|
||||||
: "memory");
|
: "memory");
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -202,10 +163,8 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
unsigned long *p3, unsigned long *p4)
|
unsigned long *p3, unsigned long *p4)
|
||||||
{
|
{
|
||||||
unsigned int lines = bytes >> 8;
|
unsigned int lines = bytes >> 8;
|
||||||
xmm_store_t xmm_save[4];
|
|
||||||
unsigned long cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -261,7 +220,7 @@ xor_sse_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
: [inc] "r" (256UL)
|
: [inc] "r" (256UL)
|
||||||
: "memory" );
|
: "memory" );
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -269,10 +228,8 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
unsigned long *p3, unsigned long *p4, unsigned long *p5)
|
unsigned long *p3, unsigned long *p4, unsigned long *p5)
|
||||||
{
|
{
|
||||||
unsigned int lines = bytes >> 8;
|
unsigned int lines = bytes >> 8;
|
||||||
xmm_store_t xmm_save[4];
|
|
||||||
unsigned long cr0;
|
|
||||||
|
|
||||||
XMMS_SAVE;
|
kernel_fpu_begin();
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -336,7 +293,7 @@ xor_sse_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
|
||||||
: [inc] "r" (256UL)
|
: [inc] "r" (256UL)
|
||||||
: "memory");
|
: "memory");
|
||||||
|
|
||||||
XMMS_RESTORE;
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xor_block_template xor_block_sse = {
|
static struct xor_block_template xor_block_sse = {
|
||||||
|
|
|
@ -20,32 +20,6 @@
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <asm/i387.h>
|
#include <asm/i387.h>
|
||||||
|
|
||||||
#define ALIGN32 __aligned(32)
|
|
||||||
|
|
||||||
#define YMM_SAVED_REGS 4
|
|
||||||
|
|
||||||
#define YMMS_SAVE \
|
|
||||||
do { \
|
|
||||||
preempt_disable(); \
|
|
||||||
cr0 = read_cr0(); \
|
|
||||||
clts(); \
|
|
||||||
asm volatile("vmovaps %%ymm0, %0" : "=m" (ymm_save[0]) : : "memory"); \
|
|
||||||
asm volatile("vmovaps %%ymm1, %0" : "=m" (ymm_save[32]) : : "memory"); \
|
|
||||||
asm volatile("vmovaps %%ymm2, %0" : "=m" (ymm_save[64]) : : "memory"); \
|
|
||||||
asm volatile("vmovaps %%ymm3, %0" : "=m" (ymm_save[96]) : : "memory"); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define YMMS_RESTORE \
|
|
||||||
do { \
|
|
||||||
asm volatile("sfence" : : : "memory"); \
|
|
||||||
asm volatile("vmovaps %0, %%ymm3" : : "m" (ymm_save[96])); \
|
|
||||||
asm volatile("vmovaps %0, %%ymm2" : : "m" (ymm_save[64])); \
|
|
||||||
asm volatile("vmovaps %0, %%ymm1" : : "m" (ymm_save[32])); \
|
|
||||||
asm volatile("vmovaps %0, %%ymm0" : : "m" (ymm_save[0])); \
|
|
||||||
write_cr0(cr0); \
|
|
||||||
preempt_enable(); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define BLOCK4(i) \
|
#define BLOCK4(i) \
|
||||||
BLOCK(32 * i, 0) \
|
BLOCK(32 * i, 0) \
|
||||||
BLOCK(32 * (i + 1), 1) \
|
BLOCK(32 * (i + 1), 1) \
|
||||||
|
@ -60,10 +34,9 @@ do { \
|
||||||
|
|
||||||
static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
|
static void xor_avx_2(unsigned long bytes, unsigned long *p0, unsigned long *p1)
|
||||||
{
|
{
|
||||||
unsigned long cr0, lines = bytes >> 9;
|
unsigned long lines = bytes >> 9;
|
||||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
|
||||||
|
|
||||||
YMMS_SAVE
|
kernel_fpu_begin();
|
||||||
|
|
||||||
while (lines--) {
|
while (lines--) {
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -82,16 +55,15 @@ do { \
|
||||||
p1 = (unsigned long *)((uintptr_t)p1 + 512);
|
p1 = (unsigned long *)((uintptr_t)p1 + 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
YMMS_RESTORE
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
static void xor_avx_3(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
||||||
unsigned long *p2)
|
unsigned long *p2)
|
||||||
{
|
{
|
||||||
unsigned long cr0, lines = bytes >> 9;
|
unsigned long lines = bytes >> 9;
|
||||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
|
||||||
|
|
||||||
YMMS_SAVE
|
kernel_fpu_begin();
|
||||||
|
|
||||||
while (lines--) {
|
while (lines--) {
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -113,16 +85,15 @@ do { \
|
||||||
p2 = (unsigned long *)((uintptr_t)p2 + 512);
|
p2 = (unsigned long *)((uintptr_t)p2 + 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
YMMS_RESTORE
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
static void xor_avx_4(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
||||||
unsigned long *p2, unsigned long *p3)
|
unsigned long *p2, unsigned long *p3)
|
||||||
{
|
{
|
||||||
unsigned long cr0, lines = bytes >> 9;
|
unsigned long lines = bytes >> 9;
|
||||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
|
||||||
|
|
||||||
YMMS_SAVE
|
kernel_fpu_begin();
|
||||||
|
|
||||||
while (lines--) {
|
while (lines--) {
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -147,16 +118,15 @@ do { \
|
||||||
p3 = (unsigned long *)((uintptr_t)p3 + 512);
|
p3 = (unsigned long *)((uintptr_t)p3 + 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
YMMS_RESTORE
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
static void xor_avx_5(unsigned long bytes, unsigned long *p0, unsigned long *p1,
|
||||||
unsigned long *p2, unsigned long *p3, unsigned long *p4)
|
unsigned long *p2, unsigned long *p3, unsigned long *p4)
|
||||||
{
|
{
|
||||||
unsigned long cr0, lines = bytes >> 9;
|
unsigned long lines = bytes >> 9;
|
||||||
char ymm_save[32 * YMM_SAVED_REGS] ALIGN32;
|
|
||||||
|
|
||||||
YMMS_SAVE
|
kernel_fpu_begin();
|
||||||
|
|
||||||
while (lines--) {
|
while (lines--) {
|
||||||
#undef BLOCK
|
#undef BLOCK
|
||||||
|
@ -184,7 +154,7 @@ do { \
|
||||||
p4 = (unsigned long *)((uintptr_t)p4 + 512);
|
p4 = (unsigned long *)((uintptr_t)p4 + 512);
|
||||||
}
|
}
|
||||||
|
|
||||||
YMMS_RESTORE
|
kernel_fpu_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xor_block_template xor_block_avx = {
|
static struct xor_block_template xor_block_avx = {
|
||||||
|
|
|
@ -34,17 +34,14 @@
|
||||||
extern unsigned int xstate_size;
|
extern unsigned int xstate_size;
|
||||||
extern u64 pcntxt_mask;
|
extern u64 pcntxt_mask;
|
||||||
extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
|
extern u64 xstate_fx_sw_bytes[USER_XSTATE_FX_SW_WORDS];
|
||||||
|
extern struct xsave_struct *init_xstate_buf;
|
||||||
|
|
||||||
extern void xsave_init(void);
|
extern void xsave_init(void);
|
||||||
extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
|
extern void update_regset_xstate_info(unsigned int size, u64 xstate_mask);
|
||||||
extern int init_fpu(struct task_struct *child);
|
extern int init_fpu(struct task_struct *child);
|
||||||
extern int check_for_xstate(struct i387_fxsave_struct __user *buf,
|
|
||||||
void __user *fpstate,
|
|
||||||
struct _fpx_sw_bytes *sw);
|
|
||||||
|
|
||||||
static inline int fpu_xrstor_checking(struct fpu *fpu)
|
static inline int fpu_xrstor_checking(struct xsave_struct *fx)
|
||||||
{
|
{
|
||||||
struct xsave_struct *fx = &fpu->state->xsave;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
|
asm volatile("1: .byte " REX_PREFIX "0x0f,0xae,0x2f\n\t"
|
||||||
|
@ -69,8 +66,7 @@ static inline int xsave_user(struct xsave_struct __user *buf)
|
||||||
* Clear the xsave header first, so that reserved fields are
|
* Clear the xsave header first, so that reserved fields are
|
||||||
* initialized to zero.
|
* initialized to zero.
|
||||||
*/
|
*/
|
||||||
err = __clear_user(&buf->xsave_hdr,
|
err = __clear_user(&buf->xsave_hdr, sizeof(buf->xsave_hdr));
|
||||||
sizeof(struct xsave_hdr_struct));
|
|
||||||
if (unlikely(err))
|
if (unlikely(err))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
|
@ -85,9 +81,6 @@ static inline int xsave_user(struct xsave_struct __user *buf)
|
||||||
: [err] "=r" (err)
|
: [err] "=r" (err)
|
||||||
: "D" (buf), "a" (-1), "d" (-1), "0" (0)
|
: "D" (buf), "a" (-1), "d" (-1), "0" (0)
|
||||||
: "memory");
|
: "memory");
|
||||||
if (unlikely(err) && __clear_user(buf, xstate_size))
|
|
||||||
err = -EFAULT;
|
|
||||||
/* No need to clear here because the caller clears USED_MATH */
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -165,10 +165,15 @@ void __init check_bugs(void)
|
||||||
print_cpu_info(&boot_cpu_data);
|
print_cpu_info(&boot_cpu_data);
|
||||||
#endif
|
#endif
|
||||||
check_config();
|
check_config();
|
||||||
check_fpu();
|
|
||||||
check_hlt();
|
check_hlt();
|
||||||
check_popad();
|
check_popad();
|
||||||
init_utsname()->machine[1] =
|
init_utsname()->machine[1] =
|
||||||
'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
|
'0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
|
||||||
alternative_instructions();
|
alternative_instructions();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kernel_fpu_begin/end() in check_fpu() relies on the patched
|
||||||
|
* alternative instructions.
|
||||||
|
*/
|
||||||
|
check_fpu();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1324,7 +1324,6 @@ void __cpuinit cpu_init(void)
|
||||||
dbg_restore_debug_regs();
|
dbg_restore_debug_regs();
|
||||||
|
|
||||||
fpu_init();
|
fpu_init();
|
||||||
xsave_init();
|
|
||||||
|
|
||||||
raw_local_save_flags(kernel_eflags);
|
raw_local_save_flags(kernel_eflags);
|
||||||
|
|
||||||
|
@ -1379,6 +1378,5 @@ void __cpuinit cpu_init(void)
|
||||||
dbg_restore_debug_regs();
|
dbg_restore_debug_regs();
|
||||||
|
|
||||||
fpu_init();
|
fpu_init();
|
||||||
xsave_init();
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,24 +19,17 @@
|
||||||
#include <asm/fpu-internal.h>
|
#include <asm/fpu-internal.h>
|
||||||
#include <asm/user.h>
|
#include <asm/user.h>
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
# include <asm/sigcontext32.h>
|
|
||||||
# include <asm/user32.h>
|
|
||||||
#else
|
|
||||||
# define save_i387_xstate_ia32 save_i387_xstate
|
|
||||||
# define restore_i387_xstate_ia32 restore_i387_xstate
|
|
||||||
# define _fpstate_ia32 _fpstate
|
|
||||||
# define _xstate_ia32 _xstate
|
|
||||||
# define sig_xstate_ia32_size sig_xstate_size
|
|
||||||
# define fx_sw_reserved_ia32 fx_sw_reserved
|
|
||||||
# define user_i387_ia32_struct user_i387_struct
|
|
||||||
# define user32_fxsr_struct user_fxsr_struct
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Were we in an interrupt that interrupted kernel mode?
|
* Were we in an interrupt that interrupted kernel mode?
|
||||||
*
|
*
|
||||||
* We can do a kernel_fpu_begin/end() pair *ONLY* if that
|
* For now, with eagerfpu we will return interrupted kernel FPU
|
||||||
|
* state as not-idle. TBD: Ideally we can change the return value
|
||||||
|
* to something like __thread_has_fpu(current). But we need to
|
||||||
|
* be careful of doing __thread_clear_has_fpu() before saving
|
||||||
|
* the FPU etc for supporting nested uses etc. For now, take
|
||||||
|
* the simple route!
|
||||||
|
*
|
||||||
|
* On others, we can do a kernel_fpu_begin/end() pair *ONLY* if that
|
||||||
* pair does nothing at all: the thread must not have fpu (so
|
* pair does nothing at all: the thread must not have fpu (so
|
||||||
* that we don't try to save the FPU state), and TS must
|
* that we don't try to save the FPU state), and TS must
|
||||||
* be set (so that the clts/stts pair does nothing that is
|
* be set (so that the clts/stts pair does nothing that is
|
||||||
|
@ -44,6 +37,9 @@
|
||||||
*/
|
*/
|
||||||
static inline bool interrupted_kernel_fpu_idle(void)
|
static inline bool interrupted_kernel_fpu_idle(void)
|
||||||
{
|
{
|
||||||
|
if (use_eager_fpu())
|
||||||
|
return 0;
|
||||||
|
|
||||||
return !__thread_has_fpu(current) &&
|
return !__thread_has_fpu(current) &&
|
||||||
(read_cr0() & X86_CR0_TS);
|
(read_cr0() & X86_CR0_TS);
|
||||||
}
|
}
|
||||||
|
@ -77,29 +73,29 @@ bool irq_fpu_usable(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(irq_fpu_usable);
|
EXPORT_SYMBOL(irq_fpu_usable);
|
||||||
|
|
||||||
void kernel_fpu_begin(void)
|
void __kernel_fpu_begin(void)
|
||||||
{
|
{
|
||||||
struct task_struct *me = current;
|
struct task_struct *me = current;
|
||||||
|
|
||||||
WARN_ON_ONCE(!irq_fpu_usable());
|
|
||||||
preempt_disable();
|
|
||||||
if (__thread_has_fpu(me)) {
|
if (__thread_has_fpu(me)) {
|
||||||
__save_init_fpu(me);
|
__save_init_fpu(me);
|
||||||
__thread_clear_has_fpu(me);
|
__thread_clear_has_fpu(me);
|
||||||
/* We do 'stts()' in kernel_fpu_end() */
|
/* We do 'stts()' in __kernel_fpu_end() */
|
||||||
} else {
|
} else if (!use_eager_fpu()) {
|
||||||
this_cpu_write(fpu_owner_task, NULL);
|
this_cpu_write(fpu_owner_task, NULL);
|
||||||
clts();
|
clts();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kernel_fpu_begin);
|
EXPORT_SYMBOL(__kernel_fpu_begin);
|
||||||
|
|
||||||
void kernel_fpu_end(void)
|
void __kernel_fpu_end(void)
|
||||||
{
|
{
|
||||||
|
if (use_eager_fpu())
|
||||||
|
math_state_restore();
|
||||||
|
else
|
||||||
stts();
|
stts();
|
||||||
preempt_enable();
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kernel_fpu_end);
|
EXPORT_SYMBOL(__kernel_fpu_end);
|
||||||
|
|
||||||
void unlazy_fpu(struct task_struct *tsk)
|
void unlazy_fpu(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
|
@ -113,23 +109,15 @@ void unlazy_fpu(struct task_struct *tsk)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(unlazy_fpu);
|
EXPORT_SYMBOL(unlazy_fpu);
|
||||||
|
|
||||||
#ifdef CONFIG_MATH_EMULATION
|
unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
|
||||||
# define HAVE_HWFP (boot_cpu_data.hard_math)
|
|
||||||
#else
|
|
||||||
# define HAVE_HWFP 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static unsigned int mxcsr_feature_mask __read_mostly = 0xffffffffu;
|
|
||||||
unsigned int xstate_size;
|
unsigned int xstate_size;
|
||||||
EXPORT_SYMBOL_GPL(xstate_size);
|
EXPORT_SYMBOL_GPL(xstate_size);
|
||||||
unsigned int sig_xstate_ia32_size = sizeof(struct _fpstate_ia32);
|
|
||||||
static struct i387_fxsave_struct fx_scratch __cpuinitdata;
|
static struct i387_fxsave_struct fx_scratch __cpuinitdata;
|
||||||
|
|
||||||
static void __cpuinit mxcsr_feature_mask_init(void)
|
static void __cpuinit mxcsr_feature_mask_init(void)
|
||||||
{
|
{
|
||||||
unsigned long mask = 0;
|
unsigned long mask = 0;
|
||||||
|
|
||||||
clts();
|
|
||||||
if (cpu_has_fxsr) {
|
if (cpu_has_fxsr) {
|
||||||
memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
|
memset(&fx_scratch, 0, sizeof(struct i387_fxsave_struct));
|
||||||
asm volatile("fxsave %0" : : "m" (fx_scratch));
|
asm volatile("fxsave %0" : : "m" (fx_scratch));
|
||||||
|
@ -138,7 +126,6 @@ static void __cpuinit mxcsr_feature_mask_init(void)
|
||||||
mask = 0x0000ffbf;
|
mask = 0x0000ffbf;
|
||||||
}
|
}
|
||||||
mxcsr_feature_mask &= mask;
|
mxcsr_feature_mask &= mask;
|
||||||
stts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit init_thread_xstate(void)
|
static void __cpuinit init_thread_xstate(void)
|
||||||
|
@ -192,9 +179,8 @@ void __cpuinit fpu_init(void)
|
||||||
init_thread_xstate();
|
init_thread_xstate();
|
||||||
|
|
||||||
mxcsr_feature_mask_init();
|
mxcsr_feature_mask_init();
|
||||||
/* clean state in init */
|
xsave_init();
|
||||||
current_thread_info()->status = 0;
|
eager_fpu_init();
|
||||||
clear_used_math();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fpu_finit(struct fpu *fpu)
|
void fpu_finit(struct fpu *fpu)
|
||||||
|
@ -205,12 +191,7 @@ void fpu_finit(struct fpu *fpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_has_fxsr) {
|
if (cpu_has_fxsr) {
|
||||||
struct i387_fxsave_struct *fx = &fpu->state->fxsave;
|
fx_finit(&fpu->state->fxsave);
|
||||||
|
|
||||||
memset(fx, 0, xstate_size);
|
|
||||||
fx->cwd = 0x37f;
|
|
||||||
if (cpu_has_xmm)
|
|
||||||
fx->mxcsr = MXCSR_DEFAULT;
|
|
||||||
} else {
|
} else {
|
||||||
struct i387_fsave_struct *fp = &fpu->state->fsave;
|
struct i387_fsave_struct *fp = &fpu->state->fsave;
|
||||||
memset(fp, 0, xstate_size);
|
memset(fp, 0, xstate_size);
|
||||||
|
@ -454,7 +435,7 @@ static inline u32 twd_fxsr_to_i387(struct i387_fxsave_struct *fxsave)
|
||||||
* FXSR floating point environment conversions.
|
* FXSR floating point environment conversions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
void
|
||||||
convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
|
convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
|
struct i387_fxsave_struct *fxsave = &tsk->thread.fpu.state->fxsave;
|
||||||
|
@ -491,7 +472,7 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
|
||||||
memcpy(&to[i], &from[i], sizeof(to[0]));
|
memcpy(&to[i], &from[i], sizeof(to[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void convert_to_fxsr(struct task_struct *tsk,
|
void convert_to_fxsr(struct task_struct *tsk,
|
||||||
const struct user_i387_ia32_struct *env)
|
const struct user_i387_ia32_struct *env)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -588,223 +569,6 @@ int fpregs_set(struct task_struct *target, const struct user_regset *regset,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Signal frame handlers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline int save_i387_fsave(struct _fpstate_ia32 __user *buf)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
struct i387_fsave_struct *fp = &tsk->thread.fpu.state->fsave;
|
|
||||||
|
|
||||||
fp->status = fp->swd;
|
|
||||||
if (__copy_to_user(buf, fp, sizeof(struct i387_fsave_struct)))
|
|
||||||
return -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int save_i387_fxsave(struct _fpstate_ia32 __user *buf)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
|
|
||||||
struct user_i387_ia32_struct env;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
convert_from_fxsr(&env, tsk);
|
|
||||||
if (__copy_to_user(buf, &env, sizeof(env)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err |= __put_user(fx->swd, &buf->status);
|
|
||||||
err |= __put_user(X86_FXSR_MAGIC, &buf->magic);
|
|
||||||
if (err)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (__copy_to_user(&buf->_fxsr_env[0], fx, xstate_size))
|
|
||||||
return -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int save_i387_xsave(void __user *buf)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
struct _fpstate_ia32 __user *fx = buf;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
|
|
||||||
sanitize_i387_state(tsk);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For legacy compatible, we always set FP/SSE bits in the bit
|
|
||||||
* vector while saving the state to the user context.
|
|
||||||
* This will enable us capturing any changes(during sigreturn) to
|
|
||||||
* the FP/SSE bits by the legacy applications which don't touch
|
|
||||||
* xstate_bv in the xsave header.
|
|
||||||
*
|
|
||||||
* xsave aware applications can change the xstate_bv in the xsave
|
|
||||||
* header as well as change any contents in the memory layout.
|
|
||||||
* xrestore as part of sigreturn will capture all the changes.
|
|
||||||
*/
|
|
||||||
tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv |= XSTATE_FPSSE;
|
|
||||||
|
|
||||||
if (save_i387_fxsave(fx) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved_ia32,
|
|
||||||
sizeof(struct _fpx_sw_bytes));
|
|
||||||
err |= __put_user(FP_XSTATE_MAGIC2,
|
|
||||||
(__u32 __user *) (buf + sig_xstate_ia32_size
|
|
||||||
- FP_XSTATE_MAGIC2_SIZE));
|
|
||||||
if (err)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int save_i387_xstate_ia32(void __user *buf)
|
|
||||||
{
|
|
||||||
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
|
|
||||||
if (!used_math())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_ia32_size))
|
|
||||||
return -EACCES;
|
|
||||||
/*
|
|
||||||
* This will cause a "finit" to be triggered by the next
|
|
||||||
* attempted FPU operation by the 'current' process.
|
|
||||||
*/
|
|
||||||
clear_used_math();
|
|
||||||
|
|
||||||
if (!HAVE_HWFP) {
|
|
||||||
return fpregs_soft_get(current, NULL,
|
|
||||||
0, sizeof(struct user_i387_ia32_struct),
|
|
||||||
NULL, fp) ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlazy_fpu(tsk);
|
|
||||||
|
|
||||||
if (cpu_has_xsave)
|
|
||||||
return save_i387_xsave(fp);
|
|
||||||
if (cpu_has_fxsr)
|
|
||||||
return save_i387_fxsave(fp);
|
|
||||||
else
|
|
||||||
return save_i387_fsave(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int restore_i387_fsave(struct _fpstate_ia32 __user *buf)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
|
|
||||||
return __copy_from_user(&tsk->thread.fpu.state->fsave, buf,
|
|
||||||
sizeof(struct i387_fsave_struct));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int restore_i387_fxsave(struct _fpstate_ia32 __user *buf,
|
|
||||||
unsigned int size)
|
|
||||||
{
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
struct user_i387_ia32_struct env;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = __copy_from_user(&tsk->thread.fpu.state->fxsave, &buf->_fxsr_env[0],
|
|
||||||
size);
|
|
||||||
/* mxcsr reserved bits must be masked to zero for security reasons */
|
|
||||||
tsk->thread.fpu.state->fxsave.mxcsr &= mxcsr_feature_mask;
|
|
||||||
if (err || __copy_from_user(&env, buf, sizeof(env)))
|
|
||||||
return 1;
|
|
||||||
convert_to_fxsr(tsk, &env);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int restore_i387_xsave(void __user *buf)
|
|
||||||
{
|
|
||||||
struct _fpx_sw_bytes fx_sw_user;
|
|
||||||
struct _fpstate_ia32 __user *fx_user =
|
|
||||||
((struct _fpstate_ia32 __user *) buf);
|
|
||||||
struct i387_fxsave_struct __user *fx =
|
|
||||||
(struct i387_fxsave_struct __user *) &fx_user->_fxsr_env[0];
|
|
||||||
struct xsave_hdr_struct *xsave_hdr =
|
|
||||||
¤t->thread.fpu.state->xsave.xsave_hdr;
|
|
||||||
u64 mask;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (check_for_xstate(fx, buf, &fx_sw_user))
|
|
||||||
goto fx_only;
|
|
||||||
|
|
||||||
mask = fx_sw_user.xstate_bv;
|
|
||||||
|
|
||||||
err = restore_i387_fxsave(buf, fx_sw_user.xstate_size);
|
|
||||||
|
|
||||||
xsave_hdr->xstate_bv &= pcntxt_mask;
|
|
||||||
/*
|
|
||||||
* These bits must be zero.
|
|
||||||
*/
|
|
||||||
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Init the state that is not present in the memory layout
|
|
||||||
* and enabled by the OS.
|
|
||||||
*/
|
|
||||||
mask = ~(pcntxt_mask & ~mask);
|
|
||||||
xsave_hdr->xstate_bv &= mask;
|
|
||||||
|
|
||||||
return err;
|
|
||||||
fx_only:
|
|
||||||
/*
|
|
||||||
* Couldn't find the extended state information in the memory
|
|
||||||
* layout. Restore the FP/SSE and init the other extended state
|
|
||||||
* enabled by the OS.
|
|
||||||
*/
|
|
||||||
xsave_hdr->xstate_bv = XSTATE_FPSSE;
|
|
||||||
return restore_i387_fxsave(buf, sizeof(struct i387_fxsave_struct));
|
|
||||||
}
|
|
||||||
|
|
||||||
int restore_i387_xstate_ia32(void __user *buf)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct task_struct *tsk = current;
|
|
||||||
struct _fpstate_ia32 __user *fp = (struct _fpstate_ia32 __user *) buf;
|
|
||||||
|
|
||||||
if (HAVE_HWFP)
|
|
||||||
clear_fpu(tsk);
|
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
if (used_math()) {
|
|
||||||
clear_fpu(tsk);
|
|
||||||
clear_used_math();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
} else
|
|
||||||
if (!access_ok(VERIFY_READ, buf, sig_xstate_ia32_size))
|
|
||||||
return -EACCES;
|
|
||||||
|
|
||||||
if (!used_math()) {
|
|
||||||
err = init_fpu(tsk);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HAVE_HWFP) {
|
|
||||||
if (cpu_has_xsave)
|
|
||||||
err = restore_i387_xsave(buf);
|
|
||||||
else if (cpu_has_fxsr)
|
|
||||||
err = restore_i387_fxsave(fp, sizeof(struct
|
|
||||||
i387_fxsave_struct));
|
|
||||||
else
|
|
||||||
err = restore_i387_fsave(fp);
|
|
||||||
} else {
|
|
||||||
err = fpregs_soft_set(current, NULL,
|
|
||||||
0, sizeof(struct user_i387_ia32_struct),
|
|
||||||
NULL, fp) != 0;
|
|
||||||
}
|
|
||||||
set_used_math();
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FPU state for core dumps.
|
* FPU state for core dumps.
|
||||||
* This is only used for a.out dumps now.
|
* This is only used for a.out dumps now.
|
||||||
|
|
|
@ -150,7 +150,7 @@ static struct resource *find_oprom(struct pci_dev *pdev)
|
||||||
return oprom;
|
return oprom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *pci_map_biosrom(struct pci_dev *pdev)
|
void __iomem *pci_map_biosrom(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct resource *oprom = find_oprom(pdev);
|
struct resource *oprom = find_oprom(pdev);
|
||||||
|
|
||||||
|
|
|
@ -66,15 +66,13 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
unlazy_fpu(src);
|
|
||||||
|
|
||||||
*dst = *src;
|
*dst = *src;
|
||||||
if (fpu_allocated(&src->thread.fpu)) {
|
if (fpu_allocated(&src->thread.fpu)) {
|
||||||
memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
|
memset(&dst->thread.fpu, 0, sizeof(dst->thread.fpu));
|
||||||
ret = fpu_alloc(&dst->thread.fpu);
|
ret = fpu_alloc(&dst->thread.fpu);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
fpu_copy(&dst->thread.fpu, &src->thread.fpu);
|
fpu_copy(dst, src);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -97,16 +95,6 @@ void arch_task_cache_init(void)
|
||||||
SLAB_PANIC | SLAB_NOTRACK, NULL);
|
SLAB_PANIC | SLAB_NOTRACK, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void drop_fpu(struct task_struct *tsk)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Forget coprocessor state..
|
|
||||||
*/
|
|
||||||
tsk->fpu_counter = 0;
|
|
||||||
clear_fpu(tsk);
|
|
||||||
clear_used_math();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free current thread data structures etc..
|
* Free current thread data structures etc..
|
||||||
*/
|
*/
|
||||||
|
@ -163,7 +151,13 @@ void flush_thread(void)
|
||||||
|
|
||||||
flush_ptrace_hw_breakpoint(tsk);
|
flush_ptrace_hw_breakpoint(tsk);
|
||||||
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
|
memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
|
||||||
drop_fpu(tsk);
|
drop_init_fpu(tsk);
|
||||||
|
/*
|
||||||
|
* Free the FPU state for non xsave platforms. They get reallocated
|
||||||
|
* lazily at the first use.
|
||||||
|
*/
|
||||||
|
if (!use_eager_fpu())
|
||||||
|
free_thread_xstate(tsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hard_disable_TSC(void)
|
static void hard_disable_TSC(void)
|
||||||
|
|
|
@ -190,10 +190,6 @@ start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
|
||||||
regs->cs = __USER_CS;
|
regs->cs = __USER_CS;
|
||||||
regs->ip = new_ip;
|
regs->ip = new_ip;
|
||||||
regs->sp = new_sp;
|
regs->sp = new_sp;
|
||||||
/*
|
|
||||||
* Free the old FP and other extended state
|
|
||||||
*/
|
|
||||||
free_thread_xstate(current);
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(start_thread);
|
EXPORT_SYMBOL_GPL(start_thread);
|
||||||
|
|
||||||
|
|
|
@ -232,10 +232,6 @@ start_thread_common(struct pt_regs *regs, unsigned long new_ip,
|
||||||
regs->cs = _cs;
|
regs->cs = _cs;
|
||||||
regs->ss = _ss;
|
regs->ss = _ss;
|
||||||
regs->flags = X86_EFLAGS_IF;
|
regs->flags = X86_EFLAGS_IF;
|
||||||
/*
|
|
||||||
* Free the old FP and other extended state
|
|
||||||
*/
|
|
||||||
free_thread_xstate(current);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -1332,9 +1332,6 @@ static const struct user_regset_view user_x86_64_view = {
|
||||||
#define genregs32_get genregs_get
|
#define genregs32_get genregs_get
|
||||||
#define genregs32_set genregs_set
|
#define genregs32_set genregs_set
|
||||||
|
|
||||||
#define user_i387_ia32_struct user_i387_struct
|
|
||||||
#define user32_fxsr_struct user_fxsr_struct
|
|
||||||
|
|
||||||
#endif /* CONFIG_X86_64 */
|
#endif /* CONFIG_X86_64 */
|
||||||
|
|
||||||
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
|
#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION
|
||||||
|
|
|
@ -118,7 +118,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
|
||||||
get_user_ex(*pax, &sc->ax);
|
get_user_ex(*pax, &sc->ax);
|
||||||
} get_user_catch(err);
|
} get_user_catch(err);
|
||||||
|
|
||||||
err |= restore_i387_xstate(buf);
|
err |= restore_xstate_sig(buf, config_enabled(CONFIG_X86_32));
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -207,35 +207,32 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
|
||||||
void __user **fpstate)
|
void __user **fpstate)
|
||||||
{
|
{
|
||||||
/* Default to using normal stack */
|
/* Default to using normal stack */
|
||||||
|
unsigned long math_size = 0;
|
||||||
unsigned long sp = regs->sp;
|
unsigned long sp = regs->sp;
|
||||||
|
unsigned long buf_fx = 0;
|
||||||
int onsigstack = on_sig_stack(sp);
|
int onsigstack = on_sig_stack(sp);
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
/* redzone */
|
/* redzone */
|
||||||
|
if (config_enabled(CONFIG_X86_64))
|
||||||
sp -= 128;
|
sp -= 128;
|
||||||
#endif /* CONFIG_X86_64 */
|
|
||||||
|
|
||||||
if (!onsigstack) {
|
if (!onsigstack) {
|
||||||
/* This is the X/Open sanctioned signal stack switching. */
|
/* This is the X/Open sanctioned signal stack switching. */
|
||||||
if (ka->sa.sa_flags & SA_ONSTACK) {
|
if (ka->sa.sa_flags & SA_ONSTACK) {
|
||||||
if (current->sas_ss_size)
|
if (current->sas_ss_size)
|
||||||
sp = current->sas_ss_sp + current->sas_ss_size;
|
sp = current->sas_ss_sp + current->sas_ss_size;
|
||||||
} else {
|
} else if (config_enabled(CONFIG_X86_32) &&
|
||||||
#ifdef CONFIG_X86_32
|
(regs->ss & 0xffff) != __USER_DS &&
|
||||||
/* This is the legacy signal stack switching. */
|
|
||||||
if ((regs->ss & 0xffff) != __USER_DS &&
|
|
||||||
!(ka->sa.sa_flags & SA_RESTORER) &&
|
!(ka->sa.sa_flags & SA_RESTORER) &&
|
||||||
ka->sa.sa_restorer)
|
ka->sa.sa_restorer) {
|
||||||
|
/* This is the legacy signal stack switching. */
|
||||||
sp = (unsigned long) ka->sa.sa_restorer;
|
sp = (unsigned long) ka->sa.sa_restorer;
|
||||||
#endif /* CONFIG_X86_32 */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (used_math()) {
|
if (used_math()) {
|
||||||
sp -= sig_xstate_size;
|
sp = alloc_mathframe(sp, config_enabled(CONFIG_X86_32),
|
||||||
#ifdef CONFIG_X86_64
|
&buf_fx, &math_size);
|
||||||
sp = round_down(sp, 64);
|
|
||||||
#endif /* CONFIG_X86_64 */
|
|
||||||
*fpstate = (void __user *)sp;
|
*fpstate = (void __user *)sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,8 +245,9 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size,
|
||||||
if (onsigstack && !likely(on_sig_stack(sp)))
|
if (onsigstack && !likely(on_sig_stack(sp)))
|
||||||
return (void __user *)-1L;
|
return (void __user *)-1L;
|
||||||
|
|
||||||
/* save i387 state */
|
/* save i387 and extended state */
|
||||||
if (used_math() && save_i387_xstate(*fpstate) < 0)
|
if (used_math() &&
|
||||||
|
save_xstate_sig(*fpstate, (void __user *)buf_fx, math_size) < 0)
|
||||||
return (void __user *)-1L;
|
return (void __user *)-1L;
|
||||||
|
|
||||||
return (void __user *)sp;
|
return (void __user *)sp;
|
||||||
|
@ -477,6 +475,75 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_X86_32 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
|
static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
||||||
|
siginfo_t *info, compat_sigset_t *set,
|
||||||
|
struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_X86_X32_ABI
|
||||||
|
struct rt_sigframe_x32 __user *frame;
|
||||||
|
void __user *restorer;
|
||||||
|
int err = 0;
|
||||||
|
void __user *fpstate = NULL;
|
||||||
|
|
||||||
|
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (ka->sa.sa_flags & SA_SIGINFO) {
|
||||||
|
if (copy_siginfo_to_user32(&frame->info, info))
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
put_user_try {
|
||||||
|
/* Create the ucontext. */
|
||||||
|
if (cpu_has_xsave)
|
||||||
|
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
||||||
|
else
|
||||||
|
put_user_ex(0, &frame->uc.uc_flags);
|
||||||
|
put_user_ex(0, &frame->uc.uc_link);
|
||||||
|
put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
||||||
|
put_user_ex(sas_ss_flags(regs->sp),
|
||||||
|
&frame->uc.uc_stack.ss_flags);
|
||||||
|
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
||||||
|
put_user_ex(0, &frame->uc.uc__pad0);
|
||||||
|
|
||||||
|
if (ka->sa.sa_flags & SA_RESTORER) {
|
||||||
|
restorer = ka->sa.sa_restorer;
|
||||||
|
} else {
|
||||||
|
/* could use a vstub here */
|
||||||
|
restorer = NULL;
|
||||||
|
err |= -EFAULT;
|
||||||
|
}
|
||||||
|
put_user_ex(restorer, &frame->pretcode);
|
||||||
|
} put_user_catch(err);
|
||||||
|
|
||||||
|
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
||||||
|
regs, set->sig[0]);
|
||||||
|
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* Set up registers for signal handler */
|
||||||
|
regs->sp = (unsigned long) frame;
|
||||||
|
regs->ip = (unsigned long) ka->sa.sa_handler;
|
||||||
|
|
||||||
|
/* We use the x32 calling convention here... */
|
||||||
|
regs->di = sig;
|
||||||
|
regs->si = (unsigned long) &frame->info;
|
||||||
|
regs->dx = (unsigned long) &frame->uc;
|
||||||
|
|
||||||
|
loadsegment(ds, __USER_DS);
|
||||||
|
loadsegment(es, __USER_DS);
|
||||||
|
|
||||||
|
regs->cs = __USER_CS;
|
||||||
|
regs->ss = __USER_DS;
|
||||||
|
#endif /* CONFIG_X86_X32_ABI */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
/*
|
/*
|
||||||
* Atomically swap in the new signal mask, and wait for a signal.
|
* Atomically swap in the new signal mask, and wait for a signal.
|
||||||
|
@ -615,55 +682,22 @@ static int signr_convert(int sig)
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
|
||||||
|
|
||||||
#define is_ia32 1
|
|
||||||
#define ia32_setup_frame __setup_frame
|
|
||||||
#define ia32_setup_rt_frame __setup_rt_frame
|
|
||||||
|
|
||||||
#else /* !CONFIG_X86_32 */
|
|
||||||
|
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
|
||||||
#define is_ia32 test_thread_flag(TIF_IA32)
|
|
||||||
#else /* !CONFIG_IA32_EMULATION */
|
|
||||||
#define is_ia32 0
|
|
||||||
#endif /* CONFIG_IA32_EMULATION */
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_X32_ABI
|
|
||||||
#define is_x32 test_thread_flag(TIF_X32)
|
|
||||||
|
|
||||||
static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
|
||||||
siginfo_t *info, compat_sigset_t *set,
|
|
||||||
struct pt_regs *regs);
|
|
||||||
#else /* !CONFIG_X86_X32_ABI */
|
|
||||||
#define is_x32 0
|
|
||||||
#endif /* CONFIG_X86_X32_ABI */
|
|
||||||
|
|
||||||
int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
||||||
sigset_t *set, struct pt_regs *regs);
|
|
||||||
int ia32_setup_frame(int sig, struct k_sigaction *ka,
|
|
||||||
sigset_t *set, struct pt_regs *regs);
|
|
||||||
|
|
||||||
#endif /* CONFIG_X86_32 */
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
||||||
struct pt_regs *regs)
|
struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
int usig = signr_convert(sig);
|
int usig = signr_convert(sig);
|
||||||
sigset_t *set = sigmask_to_save();
|
sigset_t *set = sigmask_to_save();
|
||||||
|
compat_sigset_t *cset = (compat_sigset_t *) set;
|
||||||
|
|
||||||
/* Set up the stack frame */
|
/* Set up the stack frame */
|
||||||
if (is_ia32) {
|
if (is_ia32_frame()) {
|
||||||
if (ka->sa.sa_flags & SA_SIGINFO)
|
if (ka->sa.sa_flags & SA_SIGINFO)
|
||||||
return ia32_setup_rt_frame(usig, ka, info, set, regs);
|
return ia32_setup_rt_frame(usig, ka, info, cset, regs);
|
||||||
else
|
else
|
||||||
return ia32_setup_frame(usig, ka, set, regs);
|
return ia32_setup_frame(usig, ka, cset, regs);
|
||||||
#ifdef CONFIG_X86_X32_ABI
|
} else if (is_x32_frame()) {
|
||||||
} else if (is_x32) {
|
return x32_setup_rt_frame(usig, ka, info, cset, regs);
|
||||||
return x32_setup_rt_frame(usig, ka, info,
|
|
||||||
(compat_sigset_t *)set, regs);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
return __setup_rt_frame(sig, ka, info, set, regs);
|
return __setup_rt_frame(sig, ka, info, set, regs);
|
||||||
}
|
}
|
||||||
|
@ -827,73 +861,6 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_X32_ABI
|
#ifdef CONFIG_X86_X32_ABI
|
||||||
static int x32_setup_rt_frame(int sig, struct k_sigaction *ka,
|
|
||||||
siginfo_t *info, compat_sigset_t *set,
|
|
||||||
struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
struct rt_sigframe_x32 __user *frame;
|
|
||||||
void __user *restorer;
|
|
||||||
int err = 0;
|
|
||||||
void __user *fpstate = NULL;
|
|
||||||
|
|
||||||
frame = get_sigframe(ka, regs, sizeof(*frame), &fpstate);
|
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
if (ka->sa.sa_flags & SA_SIGINFO) {
|
|
||||||
if (copy_siginfo_to_user32(&frame->info, info))
|
|
||||||
return -EFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
put_user_try {
|
|
||||||
/* Create the ucontext. */
|
|
||||||
if (cpu_has_xsave)
|
|
||||||
put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
|
|
||||||
else
|
|
||||||
put_user_ex(0, &frame->uc.uc_flags);
|
|
||||||
put_user_ex(0, &frame->uc.uc_link);
|
|
||||||
put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
|
|
||||||
put_user_ex(sas_ss_flags(regs->sp),
|
|
||||||
&frame->uc.uc_stack.ss_flags);
|
|
||||||
put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
|
|
||||||
put_user_ex(0, &frame->uc.uc__pad0);
|
|
||||||
|
|
||||||
if (ka->sa.sa_flags & SA_RESTORER) {
|
|
||||||
restorer = ka->sa.sa_restorer;
|
|
||||||
} else {
|
|
||||||
/* could use a vstub here */
|
|
||||||
restorer = NULL;
|
|
||||||
err |= -EFAULT;
|
|
||||||
}
|
|
||||||
put_user_ex(restorer, &frame->pretcode);
|
|
||||||
} put_user_catch(err);
|
|
||||||
|
|
||||||
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
|
|
||||||
regs, set->sig[0]);
|
|
||||||
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/* Set up registers for signal handler */
|
|
||||||
regs->sp = (unsigned long) frame;
|
|
||||||
regs->ip = (unsigned long) ka->sa.sa_handler;
|
|
||||||
|
|
||||||
/* We use the x32 calling convention here... */
|
|
||||||
regs->di = sig;
|
|
||||||
regs->si = (unsigned long) &frame->info;
|
|
||||||
regs->dx = (unsigned long) &frame->uc;
|
|
||||||
|
|
||||||
loadsegment(ds, __USER_DS);
|
|
||||||
loadsegment(es, __USER_DS);
|
|
||||||
|
|
||||||
regs->cs = __USER_CS;
|
|
||||||
regs->ss = __USER_DS;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
|
asmlinkage long sys32_x32_rt_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct rt_sigframe_x32 __user *frame;
|
struct rt_sigframe_x32 __user *frame;
|
||||||
|
|
|
@ -613,11 +613,12 @@ void math_state_restore(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
__thread_fpu_begin(tsk);
|
__thread_fpu_begin(tsk);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Paranoid restore. send a SIGSEGV if we fail to restore the state.
|
* Paranoid restore. send a SIGSEGV if we fail to restore the state.
|
||||||
*/
|
*/
|
||||||
if (unlikely(restore_fpu_checking(tsk))) {
|
if (unlikely(restore_fpu_checking(tsk))) {
|
||||||
__thread_fpu_end(tsk);
|
drop_init_fpu(tsk);
|
||||||
force_sig(SIGSEGV, tsk);
|
force_sig(SIGSEGV, tsk);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -629,6 +630,8 @@ EXPORT_SYMBOL_GPL(math_state_restore);
|
||||||
dotraplinkage void __kprobes
|
dotraplinkage void __kprobes
|
||||||
do_device_not_available(struct pt_regs *regs, long error_code)
|
do_device_not_available(struct pt_regs *regs, long error_code)
|
||||||
{
|
{
|
||||||
|
BUG_ON(use_eager_fpu());
|
||||||
|
|
||||||
#ifdef CONFIG_MATH_EMULATION
|
#ifdef CONFIG_MATH_EMULATION
|
||||||
if (read_cr0() & X86_CR0_EM) {
|
if (read_cr0() & X86_CR0_EM) {
|
||||||
struct math_emu_info info = { };
|
struct math_emu_info info = { };
|
||||||
|
|
|
@ -10,9 +10,7 @@
|
||||||
#include <linux/compat.h>
|
#include <linux/compat.h>
|
||||||
#include <asm/i387.h>
|
#include <asm/i387.h>
|
||||||
#include <asm/fpu-internal.h>
|
#include <asm/fpu-internal.h>
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
#include <asm/sigframe.h>
|
||||||
#include <asm/sigcontext32.h>
|
|
||||||
#endif
|
|
||||||
#include <asm/xcr.h>
|
#include <asm/xcr.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -23,13 +21,9 @@ u64 pcntxt_mask;
|
||||||
/*
|
/*
|
||||||
* Represents init state for the supported extended state.
|
* Represents init state for the supported extended state.
|
||||||
*/
|
*/
|
||||||
static struct xsave_struct *init_xstate_buf;
|
struct xsave_struct *init_xstate_buf;
|
||||||
|
|
||||||
struct _fpx_sw_bytes fx_sw_reserved;
|
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
|
||||||
struct _fpx_sw_bytes fx_sw_reserved_ia32;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32;
|
||||||
static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
|
static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -44,9 +38,9 @@ static unsigned int *xstate_offsets, *xstate_sizes, xstate_features;
|
||||||
*/
|
*/
|
||||||
void __sanitize_i387_state(struct task_struct *tsk)
|
void __sanitize_i387_state(struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
u64 xstate_bv;
|
|
||||||
int feature_bit = 0x2;
|
|
||||||
struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
|
struct i387_fxsave_struct *fx = &tsk->thread.fpu.state->fxsave;
|
||||||
|
int feature_bit = 0x2;
|
||||||
|
u64 xstate_bv;
|
||||||
|
|
||||||
if (!fx)
|
if (!fx)
|
||||||
return;
|
return;
|
||||||
|
@ -104,108 +98,84 @@ void __sanitize_i387_state(struct task_struct *tsk)
|
||||||
* Check for the presence of extended state information in the
|
* Check for the presence of extended state information in the
|
||||||
* user fpstate pointer in the sigcontext.
|
* user fpstate pointer in the sigcontext.
|
||||||
*/
|
*/
|
||||||
int check_for_xstate(struct i387_fxsave_struct __user *buf,
|
static inline int check_for_xstate(struct i387_fxsave_struct __user *buf,
|
||||||
void __user *fpstate,
|
void __user *fpstate,
|
||||||
struct _fpx_sw_bytes *fx_sw_user)
|
struct _fpx_sw_bytes *fx_sw)
|
||||||
{
|
{
|
||||||
int min_xstate_size = sizeof(struct i387_fxsave_struct) +
|
int min_xstate_size = sizeof(struct i387_fxsave_struct) +
|
||||||
sizeof(struct xsave_hdr_struct);
|
sizeof(struct xsave_hdr_struct);
|
||||||
unsigned int magic2;
|
unsigned int magic2;
|
||||||
int err;
|
|
||||||
|
|
||||||
err = __copy_from_user(fx_sw_user, &buf->sw_reserved[0],
|
if (__copy_from_user(fx_sw, &buf->sw_reserved[0], sizeof(*fx_sw)))
|
||||||
sizeof(struct _fpx_sw_bytes));
|
return -1;
|
||||||
if (err)
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/*
|
/* Check for the first magic field and other error scenarios. */
|
||||||
* First Magic check failed.
|
if (fx_sw->magic1 != FP_XSTATE_MAGIC1 ||
|
||||||
*/
|
fx_sw->xstate_size < min_xstate_size ||
|
||||||
if (fx_sw_user->magic1 != FP_XSTATE_MAGIC1)
|
fx_sw->xstate_size > xstate_size ||
|
||||||
return -EINVAL;
|
fx_sw->xstate_size > fx_sw->extended_size)
|
||||||
|
return -1;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for error scenarios.
|
|
||||||
*/
|
|
||||||
if (fx_sw_user->xstate_size < min_xstate_size ||
|
|
||||||
fx_sw_user->xstate_size > xstate_size ||
|
|
||||||
fx_sw_user->xstate_size > fx_sw_user->extended_size)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
err = __get_user(magic2, (__u32 *) (((void *)fpstate) +
|
|
||||||
fx_sw_user->extended_size -
|
|
||||||
FP_XSTATE_MAGIC2_SIZE));
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
/*
|
/*
|
||||||
* Check for the presence of second magic word at the end of memory
|
* Check for the presence of second magic word at the end of memory
|
||||||
* layout. This detects the case where the user just copied the legacy
|
* layout. This detects the case where the user just copied the legacy
|
||||||
* fpstate layout with out copying the extended state information
|
* fpstate layout with out copying the extended state information
|
||||||
* in the memory layout.
|
* in the memory layout.
|
||||||
*/
|
*/
|
||||||
if (magic2 != FP_XSTATE_MAGIC2)
|
if (__get_user(magic2, (__u32 __user *)(fpstate + fx_sw->xstate_size))
|
||||||
return -EFAULT;
|
|| magic2 != FP_XSTATE_MAGIC2)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
/*
|
/*
|
||||||
* Signal frame handlers.
|
* Signal frame handlers.
|
||||||
*/
|
*/
|
||||||
|
static inline int save_fsave_header(struct task_struct *tsk, void __user *buf)
|
||||||
int save_i387_xstate(void __user *buf)
|
|
||||||
{
|
{
|
||||||
struct task_struct *tsk = current;
|
if (use_fxsr()) {
|
||||||
int err = 0;
|
struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
|
||||||
|
struct user_i387_ia32_struct env;
|
||||||
|
struct _fpstate_ia32 __user *fp = buf;
|
||||||
|
|
||||||
if (!access_ok(VERIFY_WRITE, buf, sig_xstate_size))
|
convert_from_fxsr(&env, tsk);
|
||||||
return -EACCES;
|
|
||||||
|
|
||||||
BUG_ON(sig_xstate_size < xstate_size);
|
if (__copy_to_user(buf, &env, sizeof(env)) ||
|
||||||
|
__put_user(xsave->i387.swd, &fp->status) ||
|
||||||
if ((unsigned long)buf % 64)
|
__put_user(X86_FXSR_MAGIC, &fp->magic))
|
||||||
pr_err("%s: bad fpstate %p\n", __func__, buf);
|
return -1;
|
||||||
|
|
||||||
if (!used_math())
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (user_has_fpu()) {
|
|
||||||
if (use_xsave())
|
|
||||||
err = xsave_user(buf);
|
|
||||||
else
|
|
||||||
err = fxsave_user(buf);
|
|
||||||
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
user_fpu_end();
|
|
||||||
} else {
|
} else {
|
||||||
sanitize_i387_state(tsk);
|
struct i387_fsave_struct __user *fp = buf;
|
||||||
if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave,
|
u32 swd;
|
||||||
xstate_size))
|
if (__get_user(swd, &fp->swd) || __put_user(swd, &fp->status))
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_used_math(); /* trigger finit */
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (use_xsave()) {
|
static inline int save_xstate_epilog(void __user *buf, int ia32_frame)
|
||||||
struct _fpstate __user *fx = buf;
|
{
|
||||||
struct _xstate __user *x = buf;
|
struct xsave_struct __user *x = buf;
|
||||||
u64 xstate_bv;
|
struct _fpx_sw_bytes *sw_bytes;
|
||||||
|
u32 xstate_bv;
|
||||||
|
int err;
|
||||||
|
|
||||||
err = __copy_to_user(&fx->sw_reserved, &fx_sw_reserved,
|
/* Setup the bytes not touched by the [f]xsave and reserved for SW. */
|
||||||
sizeof(struct _fpx_sw_bytes));
|
sw_bytes = ia32_frame ? &fx_sw_reserved_ia32 : &fx_sw_reserved;
|
||||||
|
err = __copy_to_user(&x->i387.sw_reserved, sw_bytes, sizeof(*sw_bytes));
|
||||||
|
|
||||||
err |= __put_user(FP_XSTATE_MAGIC2,
|
if (!use_xsave())
|
||||||
(__u32 __user *) (buf + sig_xstate_size
|
return err;
|
||||||
- FP_XSTATE_MAGIC2_SIZE));
|
|
||||||
|
err |= __put_user(FP_XSTATE_MAGIC2, (__u32 *)(buf + xstate_size));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the xstate_bv which we copied (directly from the cpu or
|
* Read the xstate_bv which we copied (directly from the cpu or
|
||||||
* from the state in task struct) to the user buffers and
|
* from the state in task struct) to the user buffers.
|
||||||
* set the FP/SSE bits.
|
|
||||||
*/
|
*/
|
||||||
err |= __get_user(xstate_bv, &x->xstate_hdr.xstate_bv);
|
err |= __get_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For legacy compatible, we always set FP/SSE bits in the bit
|
* For legacy compatible, we always set FP/SSE bits in the bit
|
||||||
|
@ -220,97 +190,234 @@ int save_i387_xstate(void __user *buf)
|
||||||
*/
|
*/
|
||||||
xstate_bv |= XSTATE_FPSSE;
|
xstate_bv |= XSTATE_FPSSE;
|
||||||
|
|
||||||
err |= __put_user(xstate_bv, &x->xstate_hdr.xstate_bv);
|
err |= __put_user(xstate_bv, (__u32 *)&x->xsave_hdr.xstate_bv);
|
||||||
|
|
||||||
if (err)
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
static inline int save_user_xstate(struct xsave_struct __user *buf)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (use_xsave())
|
||||||
|
err = xsave_user(buf);
|
||||||
|
else if (use_fxsr())
|
||||||
|
err = fxsave_user((struct i387_fxsave_struct __user *) buf);
|
||||||
|
else
|
||||||
|
err = fsave_user((struct i387_fsave_struct __user *) buf);
|
||||||
|
|
||||||
|
if (unlikely(err) && __clear_user(buf, xstate_size))
|
||||||
|
err = -EFAULT;
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore the extended state if present. Otherwise, restore the FP/SSE
|
* Save the fpu, extended register state to the user signal frame.
|
||||||
* state.
|
*
|
||||||
|
* 'buf_fx' is the 64-byte aligned pointer at which the [f|fx|x]save
|
||||||
|
* state is copied.
|
||||||
|
* 'buf' points to the 'buf_fx' or to the fsave header followed by 'buf_fx'.
|
||||||
|
*
|
||||||
|
* buf == buf_fx for 64-bit frames and 32-bit fsave frame.
|
||||||
|
* buf != buf_fx for 32-bit frames with fxstate.
|
||||||
|
*
|
||||||
|
* If the fpu, extended register state is live, save the state directly
|
||||||
|
* to the user frame pointed by the aligned pointer 'buf_fx'. Otherwise,
|
||||||
|
* copy the thread's fpu state to the user frame starting at 'buf_fx'.
|
||||||
|
*
|
||||||
|
* If this is a 32-bit frame with fxstate, put a fsave header before
|
||||||
|
* the aligned state at 'buf_fx'.
|
||||||
|
*
|
||||||
|
* For [f]xsave state, update the SW reserved fields in the [f]xsave frame
|
||||||
|
* indicating the absence/presence of the extended state to the user.
|
||||||
*/
|
*/
|
||||||
static int restore_user_xstate(void __user *buf)
|
int save_xstate_sig(void __user *buf, void __user *buf_fx, int size)
|
||||||
{
|
{
|
||||||
struct _fpx_sw_bytes fx_sw_user;
|
struct xsave_struct *xsave = ¤t->thread.fpu.state->xsave;
|
||||||
u64 mask;
|
struct task_struct *tsk = current;
|
||||||
int err;
|
int ia32_fxstate = (buf != buf_fx);
|
||||||
|
|
||||||
if (((unsigned long)buf % 64) ||
|
ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
|
||||||
check_for_xstate(buf, buf, &fx_sw_user))
|
config_enabled(CONFIG_IA32_EMULATION));
|
||||||
goto fx_only;
|
|
||||||
|
|
||||||
mask = fx_sw_user.xstate_bv;
|
if (!access_ok(VERIFY_WRITE, buf, size))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
/*
|
if (!HAVE_HWFP)
|
||||||
* restore the state passed by the user.
|
return fpregs_soft_get(current, NULL, 0,
|
||||||
*/
|
sizeof(struct user_i387_ia32_struct), NULL,
|
||||||
err = xrestore_user(buf, mask);
|
(struct _fpstate_ia32 __user *) buf) ? -1 : 1;
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
/*
|
if (user_has_fpu()) {
|
||||||
* init the state skipped by the user.
|
/* Save the live register state to the user directly. */
|
||||||
*/
|
if (save_user_xstate(buf_fx))
|
||||||
mask = pcntxt_mask & ~mask;
|
return -1;
|
||||||
if (unlikely(mask))
|
/* Update the thread's fxstate to save the fsave header. */
|
||||||
xrstor_state(init_xstate_buf, mask);
|
if (ia32_fxstate)
|
||||||
|
fpu_fxsave(&tsk->thread.fpu);
|
||||||
|
} else {
|
||||||
|
sanitize_i387_state(tsk);
|
||||||
|
if (__copy_to_user(buf_fx, xsave, xstate_size))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the fsave header for the 32-bit frames. */
|
||||||
|
if ((ia32_fxstate || !use_fxsr()) && save_fsave_header(tsk, buf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (use_fxsr() && save_xstate_epilog(buf_fx, ia32_fxstate))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
drop_init_fpu(tsk); /* trigger finit */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
sanitize_restored_xstate(struct task_struct *tsk,
|
||||||
|
struct user_i387_ia32_struct *ia32_env,
|
||||||
|
u64 xstate_bv, int fx_only)
|
||||||
|
{
|
||||||
|
struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
|
||||||
|
struct xsave_hdr_struct *xsave_hdr = &xsave->xsave_hdr;
|
||||||
|
|
||||||
|
if (use_xsave()) {
|
||||||
|
/* These bits must be zero. */
|
||||||
|
xsave_hdr->reserved1[0] = xsave_hdr->reserved1[1] = 0;
|
||||||
|
|
||||||
fx_only:
|
|
||||||
/*
|
/*
|
||||||
* couldn't find the extended state information in the
|
* Init the state that is not present in the memory
|
||||||
|
* layout and not enabled by the OS.
|
||||||
|
*/
|
||||||
|
if (fx_only)
|
||||||
|
xsave_hdr->xstate_bv = XSTATE_FPSSE;
|
||||||
|
else
|
||||||
|
xsave_hdr->xstate_bv &= (pcntxt_mask & xstate_bv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_fxsr()) {
|
||||||
|
/*
|
||||||
|
* mscsr reserved bits must be masked to zero for security
|
||||||
|
* reasons.
|
||||||
|
*/
|
||||||
|
xsave->i387.mxcsr &= mxcsr_feature_mask;
|
||||||
|
|
||||||
|
convert_to_fxsr(tsk, ia32_env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restore the extended state if present. Otherwise, restore the FP/SSE state.
|
||||||
|
*/
|
||||||
|
static inline int restore_user_xstate(void __user *buf, u64 xbv, int fx_only)
|
||||||
|
{
|
||||||
|
if (use_xsave()) {
|
||||||
|
if ((unsigned long)buf % 64 || fx_only) {
|
||||||
|
u64 init_bv = pcntxt_mask & ~XSTATE_FPSSE;
|
||||||
|
xrstor_state(init_xstate_buf, init_bv);
|
||||||
|
return fxrstor_checking((__force void *) buf);
|
||||||
|
} else {
|
||||||
|
u64 init_bv = pcntxt_mask & ~xbv;
|
||||||
|
if (unlikely(init_bv))
|
||||||
|
xrstor_state(init_xstate_buf, init_bv);
|
||||||
|
return xrestore_user(buf, xbv);
|
||||||
|
}
|
||||||
|
} else if (use_fxsr()) {
|
||||||
|
return fxrstor_checking((__force void *) buf);
|
||||||
|
} else
|
||||||
|
return frstor_checking((__force void *) buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
int __restore_xstate_sig(void __user *buf, void __user *buf_fx, int size)
|
||||||
|
{
|
||||||
|
int ia32_fxstate = (buf != buf_fx);
|
||||||
|
struct task_struct *tsk = current;
|
||||||
|
int state_size = xstate_size;
|
||||||
|
u64 xstate_bv = 0;
|
||||||
|
int fx_only = 0;
|
||||||
|
|
||||||
|
ia32_fxstate &= (config_enabled(CONFIG_X86_32) ||
|
||||||
|
config_enabled(CONFIG_IA32_EMULATION));
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
drop_init_fpu(tsk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!access_ok(VERIFY_READ, buf, size))
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
if (!used_math() && init_fpu(tsk))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!HAVE_HWFP) {
|
||||||
|
return fpregs_soft_set(current, NULL,
|
||||||
|
0, sizeof(struct user_i387_ia32_struct),
|
||||||
|
NULL, buf) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_xsave()) {
|
||||||
|
struct _fpx_sw_bytes fx_sw_user;
|
||||||
|
if (unlikely(check_for_xstate(buf_fx, buf_fx, &fx_sw_user))) {
|
||||||
|
/*
|
||||||
|
* Couldn't find the extended state information in the
|
||||||
* memory layout. Restore just the FP/SSE and init all
|
* memory layout. Restore just the FP/SSE and init all
|
||||||
* the other extended state.
|
* the other extended state.
|
||||||
*/
|
*/
|
||||||
xrstor_state(init_xstate_buf, pcntxt_mask & ~XSTATE_FPSSE);
|
state_size = sizeof(struct i387_fxsave_struct);
|
||||||
return fxrstor_checking((__force struct i387_fxsave_struct *)buf);
|
fx_only = 1;
|
||||||
}
|
} else {
|
||||||
|
state_size = fx_sw_user.xstate_size;
|
||||||
|
xstate_bv = fx_sw_user.xstate_bv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
if (ia32_fxstate) {
|
||||||
* This restores directly out of user space. Exceptions are handled.
|
/*
|
||||||
|
* For 32-bit frames with fxstate, copy the user state to the
|
||||||
|
* thread's fpu state, reconstruct fxstate from the fsave
|
||||||
|
* header. Sanitize the copied state etc.
|
||||||
*/
|
*/
|
||||||
int restore_i387_xstate(void __user *buf)
|
struct xsave_struct *xsave = &tsk->thread.fpu.state->xsave;
|
||||||
{
|
struct user_i387_ia32_struct env;
|
||||||
struct task_struct *tsk = current;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (!buf) {
|
|
||||||
if (used_math())
|
|
||||||
goto clear;
|
|
||||||
return 0;
|
|
||||||
} else
|
|
||||||
if (!access_ok(VERIFY_READ, buf, sig_xstate_size))
|
|
||||||
return -EACCES;
|
|
||||||
|
|
||||||
if (!used_math()) {
|
|
||||||
err = init_fpu(tsk);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
user_fpu_begin();
|
|
||||||
if (use_xsave())
|
|
||||||
err = restore_user_xstate(buf);
|
|
||||||
else
|
|
||||||
err = fxrstor_checking((__force struct i387_fxsave_struct *)
|
|
||||||
buf);
|
|
||||||
if (unlikely(err)) {
|
|
||||||
/*
|
/*
|
||||||
* Encountered an error while doing the restore from the
|
* Drop the current fpu which clears used_math(). This ensures
|
||||||
* user buffer, clear the fpu state.
|
* that any context-switch during the copy of the new state,
|
||||||
|
* avoids the intermediate state from getting restored/saved.
|
||||||
|
* Thus avoiding the new restored state from getting corrupted.
|
||||||
|
* We will be ready to restore/save the state only after
|
||||||
|
* set_used_math() is again set.
|
||||||
*/
|
*/
|
||||||
clear:
|
drop_fpu(tsk);
|
||||||
clear_fpu(tsk);
|
|
||||||
clear_used_math();
|
if (__copy_from_user(xsave, buf_fx, state_size) ||
|
||||||
|
__copy_from_user(&env, buf, sizeof(env))) {
|
||||||
|
err = -1;
|
||||||
|
} else {
|
||||||
|
sanitize_restored_xstate(tsk, &env, xstate_bv, fx_only);
|
||||||
|
set_used_math();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (use_eager_fpu())
|
||||||
|
math_state_restore();
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* For 64-bit frames and 32-bit fsave frames, restore the user
|
||||||
|
* state to the registers directly (with exceptions handled).
|
||||||
|
*/
|
||||||
|
user_fpu_begin();
|
||||||
|
if (restore_user_xstate(buf_fx, xstate_bv, fx_only)) {
|
||||||
|
drop_init_fpu(tsk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare the SW reserved portion of the fxsave memory layout, indicating
|
* Prepare the SW reserved portion of the fxsave memory layout, indicating
|
||||||
|
@ -321,31 +428,22 @@ clear:
|
||||||
*/
|
*/
|
||||||
static void prepare_fx_sw_frame(void)
|
static void prepare_fx_sw_frame(void)
|
||||||
{
|
{
|
||||||
int size_extended = (xstate_size - sizeof(struct i387_fxsave_struct)) +
|
int fsave_header_size = sizeof(struct i387_fsave_struct);
|
||||||
FP_XSTATE_MAGIC2_SIZE;
|
int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
|
||||||
|
|
||||||
sig_xstate_size = sizeof(struct _fpstate) + size_extended;
|
if (config_enabled(CONFIG_X86_32))
|
||||||
|
size += fsave_header_size;
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
|
||||||
sig_xstate_ia32_size = sizeof(struct _fpstate_ia32) + size_extended;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset(&fx_sw_reserved, 0, sizeof(fx_sw_reserved));
|
|
||||||
|
|
||||||
fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
|
fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
|
||||||
fx_sw_reserved.extended_size = sig_xstate_size;
|
fx_sw_reserved.extended_size = size;
|
||||||
fx_sw_reserved.xstate_bv = pcntxt_mask;
|
fx_sw_reserved.xstate_bv = pcntxt_mask;
|
||||||
fx_sw_reserved.xstate_size = xstate_size;
|
fx_sw_reserved.xstate_size = xstate_size;
|
||||||
#ifdef CONFIG_IA32_EMULATION
|
|
||||||
memcpy(&fx_sw_reserved_ia32, &fx_sw_reserved,
|
|
||||||
sizeof(struct _fpx_sw_bytes));
|
|
||||||
fx_sw_reserved_ia32.extended_size = sig_xstate_ia32_size;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
if (config_enabled(CONFIG_IA32_EMULATION)) {
|
||||||
unsigned int sig_xstate_size = sizeof(struct _fpstate);
|
fx_sw_reserved_ia32 = fx_sw_reserved;
|
||||||
#endif
|
fx_sw_reserved_ia32.extended_size += fsave_header_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable the extended processor state save/restore feature
|
* Enable the extended processor state save/restore feature
|
||||||
|
@ -384,19 +482,21 @@ static void __init setup_xstate_features(void)
|
||||||
/*
|
/*
|
||||||
* setup the xstate image representing the init state
|
* setup the xstate image representing the init state
|
||||||
*/
|
*/
|
||||||
static void __init setup_xstate_init(void)
|
static void __init setup_init_fpu_buf(void)
|
||||||
{
|
{
|
||||||
setup_xstate_features();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup init_xstate_buf to represent the init state of
|
* Setup init_xstate_buf to represent the init state of
|
||||||
* all the features managed by the xsave
|
* all the features managed by the xsave
|
||||||
*/
|
*/
|
||||||
init_xstate_buf = alloc_bootmem_align(xstate_size,
|
init_xstate_buf = alloc_bootmem_align(xstate_size,
|
||||||
__alignof__(struct xsave_struct));
|
__alignof__(struct xsave_struct));
|
||||||
init_xstate_buf->i387.mxcsr = MXCSR_DEFAULT;
|
fx_finit(&init_xstate_buf->i387);
|
||||||
|
|
||||||
|
if (!cpu_has_xsave)
|
||||||
|
return;
|
||||||
|
|
||||||
|
setup_xstate_features();
|
||||||
|
|
||||||
clts();
|
|
||||||
/*
|
/*
|
||||||
* Init all the features state with header_bv being 0x0
|
* Init all the features state with header_bv being 0x0
|
||||||
*/
|
*/
|
||||||
|
@ -406,9 +506,21 @@ static void __init setup_xstate_init(void)
|
||||||
* of any feature which is not represented by all zero's.
|
* of any feature which is not represented by all zero's.
|
||||||
*/
|
*/
|
||||||
xsave_state(init_xstate_buf, -1);
|
xsave_state(init_xstate_buf, -1);
|
||||||
stts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum { AUTO, ENABLE, DISABLE } eagerfpu = AUTO;
|
||||||
|
static int __init eager_fpu_setup(char *s)
|
||||||
|
{
|
||||||
|
if (!strcmp(s, "on"))
|
||||||
|
eagerfpu = ENABLE;
|
||||||
|
else if (!strcmp(s, "off"))
|
||||||
|
eagerfpu = DISABLE;
|
||||||
|
else if (!strcmp(s, "auto"))
|
||||||
|
eagerfpu = AUTO;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
__setup("eagerfpu=", eager_fpu_setup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable and initialize the xsave feature.
|
* Enable and initialize the xsave feature.
|
||||||
*/
|
*/
|
||||||
|
@ -445,8 +557,11 @@ static void __init xstate_enable_boot_cpu(void)
|
||||||
|
|
||||||
update_regset_xstate_info(xstate_size, pcntxt_mask);
|
update_regset_xstate_info(xstate_size, pcntxt_mask);
|
||||||
prepare_fx_sw_frame();
|
prepare_fx_sw_frame();
|
||||||
|
setup_init_fpu_buf();
|
||||||
|
|
||||||
setup_xstate_init();
|
/* Auto enable eagerfpu for xsaveopt */
|
||||||
|
if (cpu_has_xsaveopt && eagerfpu != DISABLE)
|
||||||
|
eagerfpu = ENABLE;
|
||||||
|
|
||||||
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
pr_info("enabled xstate_bv 0x%llx, cntxt size 0x%x\n",
|
||||||
pcntxt_mask, xstate_size);
|
pcntxt_mask, xstate_size);
|
||||||
|
@ -471,3 +586,43 @@ void __cpuinit xsave_init(void)
|
||||||
next_func = xstate_enable;
|
next_func = xstate_enable;
|
||||||
this_func();
|
this_func();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void __init eager_fpu_init_bp(void)
|
||||||
|
{
|
||||||
|
current->thread.fpu.state =
|
||||||
|
alloc_bootmem_align(xstate_size, __alignof__(struct xsave_struct));
|
||||||
|
if (!init_xstate_buf)
|
||||||
|
setup_init_fpu_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __cpuinit eager_fpu_init(void)
|
||||||
|
{
|
||||||
|
static __refdata void (*boot_func)(void) = eager_fpu_init_bp;
|
||||||
|
|
||||||
|
clear_used_math();
|
||||||
|
current_thread_info()->status = 0;
|
||||||
|
|
||||||
|
if (eagerfpu == ENABLE)
|
||||||
|
setup_force_cpu_cap(X86_FEATURE_EAGER_FPU);
|
||||||
|
|
||||||
|
if (!cpu_has_eager_fpu) {
|
||||||
|
stts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boot_func) {
|
||||||
|
boot_func();
|
||||||
|
boot_func = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is same as math_state_restore(). But use_xsave() is
|
||||||
|
* not yet patched to use math_state_restore().
|
||||||
|
*/
|
||||||
|
init_fpu(current);
|
||||||
|
__thread_fpu_begin(current);
|
||||||
|
if (cpu_has_xsave)
|
||||||
|
xrstor_state(init_xstate_buf, -1);
|
||||||
|
else
|
||||||
|
fxrstor_checking(&init_xstate_buf->i387);
|
||||||
|
}
|
||||||
|
|
|
@ -1493,8 +1493,12 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
|
||||||
#ifdef CONFIG_X86_64
|
#ifdef CONFIG_X86_64
|
||||||
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
|
wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
|
||||||
#endif
|
#endif
|
||||||
if (user_has_fpu())
|
/*
|
||||||
clts();
|
* If the FPU is not active (through the host task or
|
||||||
|
* the guest vcpu), then restore the cr0.TS bit.
|
||||||
|
*/
|
||||||
|
if (!user_has_fpu() && !vmx->vcpu.guest_fpu_loaded)
|
||||||
|
stts();
|
||||||
load_gdt(&__get_cpu_var(host_gdt));
|
load_gdt(&__get_cpu_var(host_gdt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3730,7 +3734,7 @@ static void vmx_set_constant_host_state(void)
|
||||||
unsigned long tmpl;
|
unsigned long tmpl;
|
||||||
struct desc_ptr dt;
|
struct desc_ptr dt;
|
||||||
|
|
||||||
vmcs_writel(HOST_CR0, read_cr0() | X86_CR0_TS); /* 22.2.3 */
|
vmcs_writel(HOST_CR0, read_cr0() & ~X86_CR0_TS); /* 22.2.3 */
|
||||||
vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */
|
vmcs_writel(HOST_CR4, read_cr4()); /* 22.2.3, 22.2.5 */
|
||||||
vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */
|
vmcs_writel(HOST_CR3, read_cr3()); /* 22.2.3 FIXME: shadow tables */
|
||||||
|
|
||||||
|
|
|
@ -5972,7 +5972,7 @@ void kvm_load_guest_fpu(struct kvm_vcpu *vcpu)
|
||||||
*/
|
*/
|
||||||
kvm_put_guest_xcr0(vcpu);
|
kvm_put_guest_xcr0(vcpu);
|
||||||
vcpu->guest_fpu_loaded = 1;
|
vcpu->guest_fpu_loaded = 1;
|
||||||
unlazy_fpu(current);
|
__kernel_fpu_begin();
|
||||||
fpu_restore_checking(&vcpu->arch.guest_fpu);
|
fpu_restore_checking(&vcpu->arch.guest_fpu);
|
||||||
trace_kvm_fpu(1);
|
trace_kvm_fpu(1);
|
||||||
}
|
}
|
||||||
|
@ -5986,6 +5986,7 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
vcpu->guest_fpu_loaded = 0;
|
vcpu->guest_fpu_loaded = 0;
|
||||||
fpu_save_init(&vcpu->arch.guest_fpu);
|
fpu_save_init(&vcpu->arch.guest_fpu);
|
||||||
|
__kernel_fpu_end();
|
||||||
++vcpu->stat.fpu_reload;
|
++vcpu->stat.fpu_reload;
|
||||||
kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
|
kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu);
|
||||||
trace_kvm_fpu(0);
|
trace_kvm_fpu(0);
|
||||||
|
|
|
@ -203,8 +203,8 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||||
* we set it now, so we can trap and pass that trap to the Guest if it
|
* we set it now, so we can trap and pass that trap to the Guest if it
|
||||||
* uses the FPU.
|
* uses the FPU.
|
||||||
*/
|
*/
|
||||||
if (cpu->ts)
|
if (cpu->ts && user_has_fpu())
|
||||||
unlazy_fpu(current);
|
stts();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SYSENTER is an optimized way of doing system calls. We can't allow
|
* SYSENTER is an optimized way of doing system calls. We can't allow
|
||||||
|
@ -234,6 +234,10 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||||
if (boot_cpu_has(X86_FEATURE_SEP))
|
if (boot_cpu_has(X86_FEATURE_SEP))
|
||||||
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
|
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
|
||||||
|
|
||||||
|
/* Clear the host TS bit if it was set above. */
|
||||||
|
if (cpu->ts && user_has_fpu())
|
||||||
|
clts();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the Guest page faulted, then the cr2 register will tell us the
|
* If the Guest page faulted, then the cr2 register will tell us the
|
||||||
* bad virtual address. We have to grab this now, because once we
|
* bad virtual address. We have to grab this now, because once we
|
||||||
|
@ -249,7 +253,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
||||||
* a different CPU. So all the critical stuff should be done
|
* a different CPU. So all the critical stuff should be done
|
||||||
* before this.
|
* before this.
|
||||||
*/
|
*/
|
||||||
else if (cpu->regs->trapnum == 7)
|
else if (cpu->regs->trapnum == 7 && !user_has_fpu())
|
||||||
math_state_restore();
|
math_state_restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,9 @@ static int sp_probe(struct platform_device *pdev)
|
||||||
priv = netdev_priv(dev);
|
priv = netdev_priv(dev);
|
||||||
|
|
||||||
dev->irq = res_irq->start;
|
dev->irq = res_irq->start;
|
||||||
priv->irq_flags = res_irq->flags & (IRQF_TRIGGER_MASK | IRQF_SHARED);
|
priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK;
|
||||||
|
if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE)
|
||||||
|
priv->irq_flags |= IRQF_SHARED;
|
||||||
priv->reg_base = addr;
|
priv->reg_base = addr;
|
||||||
/* The CAN clock frequency is half the oscillator clock frequency */
|
/* The CAN clock frequency is half the oscillator clock frequency */
|
||||||
priv->can.clock.freq = pdata->osc_freq / 2;
|
priv->can.clock.freq = pdata->osc_freq / 2;
|
||||||
|
|
|
@ -150,7 +150,7 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||||
const uint8_t *mem, *end, *dat;
|
const uint8_t *mem, *end, *dat;
|
||||||
uint16_t type, len;
|
uint16_t type, len;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
uint8_t *buf = NULL;
|
uint8_t *buf = NULL, *new_buf;
|
||||||
int buflen = 0;
|
int buflen = 0;
|
||||||
int8_t type_end = 0;
|
int8_t type_end = 0;
|
||||||
|
|
||||||
|
@ -199,11 +199,12 @@ int softing_load_fw(const char *file, struct softing *card,
|
||||||
if (len > buflen) {
|
if (len > buflen) {
|
||||||
/* align buflen */
|
/* align buflen */
|
||||||
buflen = (len + (1024-1)) & ~(1024-1);
|
buflen = (len + (1024-1)) & ~(1024-1);
|
||||||
buf = krealloc(buf, buflen, GFP_KERNEL);
|
new_buf = krealloc(buf, buflen, GFP_KERNEL);
|
||||||
if (!buf) {
|
if (!new_buf) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
buf = new_buf;
|
||||||
}
|
}
|
||||||
/* verify record data */
|
/* verify record data */
|
||||||
memcpy_fromio(buf, &dpram[addr + offset], len);
|
memcpy_fromio(buf, &dpram[addr + offset], len);
|
||||||
|
|
|
@ -1708,9 +1708,6 @@ struct bnx2x_func_init_params {
|
||||||
continue; \
|
continue; \
|
||||||
else
|
else
|
||||||
|
|
||||||
#define for_each_napi_rx_queue(bp, var) \
|
|
||||||
for ((var) = 0; (var) < bp->num_napi_queues; (var)++)
|
|
||||||
|
|
||||||
/* Skip OOO FP */
|
/* Skip OOO FP */
|
||||||
#define for_each_tx_queue(bp, var) \
|
#define for_each_tx_queue(bp, var) \
|
||||||
for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \
|
for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \
|
||||||
|
|
|
@ -2046,6 +2046,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
|
||||||
*/
|
*/
|
||||||
bnx2x_setup_tc(bp->dev, bp->max_cos);
|
bnx2x_setup_tc(bp->dev, bp->max_cos);
|
||||||
|
|
||||||
|
/* Add all NAPI objects */
|
||||||
|
bnx2x_add_all_napi(bp);
|
||||||
bnx2x_napi_enable(bp);
|
bnx2x_napi_enable(bp);
|
||||||
|
|
||||||
/* set pf load just before approaching the MCP */
|
/* set pf load just before approaching the MCP */
|
||||||
|
@ -2408,6 +2410,8 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
|
||||||
|
|
||||||
/* Disable HW interrupts, NAPI */
|
/* Disable HW interrupts, NAPI */
|
||||||
bnx2x_netif_stop(bp, 1);
|
bnx2x_netif_stop(bp, 1);
|
||||||
|
/* Delete all NAPI objects */
|
||||||
|
bnx2x_del_all_napi(bp);
|
||||||
|
|
||||||
/* Release IRQs */
|
/* Release IRQs */
|
||||||
bnx2x_free_irq(bp);
|
bnx2x_free_irq(bp);
|
||||||
|
|
|
@ -792,7 +792,7 @@ static inline void bnx2x_add_all_napi(struct bnx2x *bp)
|
||||||
bp->num_napi_queues = bp->num_queues;
|
bp->num_napi_queues = bp->num_queues;
|
||||||
|
|
||||||
/* Add NAPI objects */
|
/* Add NAPI objects */
|
||||||
for_each_napi_rx_queue(bp, i)
|
for_each_rx_queue(bp, i)
|
||||||
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
|
netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi),
|
||||||
bnx2x_poll, BNX2X_NAPI_WEIGHT);
|
bnx2x_poll, BNX2X_NAPI_WEIGHT);
|
||||||
}
|
}
|
||||||
|
@ -801,7 +801,7 @@ static inline void bnx2x_del_all_napi(struct bnx2x *bp)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for_each_napi_rx_queue(bp, i)
|
for_each_rx_queue(bp, i)
|
||||||
netif_napi_del(&bnx2x_fp(bp, i, napi));
|
netif_napi_del(&bnx2x_fp(bp, i, napi));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2888,11 +2888,9 @@ static void bnx2x_get_channels(struct net_device *dev,
|
||||||
*/
|
*/
|
||||||
static void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss)
|
static void bnx2x_change_num_queues(struct bnx2x *bp, int num_rss)
|
||||||
{
|
{
|
||||||
bnx2x_del_all_napi(bp);
|
|
||||||
bnx2x_disable_msi(bp);
|
bnx2x_disable_msi(bp);
|
||||||
BNX2X_NUM_QUEUES(bp) = num_rss + NON_ETH_CONTEXT_USE;
|
BNX2X_NUM_QUEUES(bp) = num_rss + NON_ETH_CONTEXT_USE;
|
||||||
bnx2x_set_int_mode(bp);
|
bnx2x_set_int_mode(bp);
|
||||||
bnx2x_add_all_napi(bp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8427,6 +8427,8 @@ unload_error:
|
||||||
|
|
||||||
/* Disable HW interrupts, NAPI */
|
/* Disable HW interrupts, NAPI */
|
||||||
bnx2x_netif_stop(bp, 1);
|
bnx2x_netif_stop(bp, 1);
|
||||||
|
/* Delete all NAPI objects */
|
||||||
|
bnx2x_del_all_napi(bp);
|
||||||
|
|
||||||
/* Release IRQs */
|
/* Release IRQs */
|
||||||
bnx2x_free_irq(bp);
|
bnx2x_free_irq(bp);
|
||||||
|
@ -11229,10 +11231,12 @@ static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||||
static void poll_bnx2x(struct net_device *dev)
|
static void poll_bnx2x(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct bnx2x *bp = netdev_priv(dev);
|
struct bnx2x *bp = netdev_priv(dev);
|
||||||
|
int i;
|
||||||
|
|
||||||
disable_irq(bp->pdev->irq);
|
for_each_eth_queue(bp, i) {
|
||||||
bnx2x_interrupt(bp->pdev->irq, dev);
|
struct bnx2x_fastpath *fp = &bp->fp[i];
|
||||||
enable_irq(bp->pdev->irq);
|
napi_schedule(&bnx2x_fp(bp, fp->index, napi));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -11899,9 +11903,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
|
||||||
*/
|
*/
|
||||||
bnx2x_set_int_mode(bp);
|
bnx2x_set_int_mode(bp);
|
||||||
|
|
||||||
/* Add all NAPI objects */
|
|
||||||
bnx2x_add_all_napi(bp);
|
|
||||||
|
|
||||||
rc = register_netdev(dev);
|
rc = register_netdev(dev);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
dev_err(&pdev->dev, "Cannot register net device\n");
|
dev_err(&pdev->dev, "Cannot register net device\n");
|
||||||
|
@ -11976,9 +11977,6 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev)
|
||||||
|
|
||||||
unregister_netdev(dev);
|
unregister_netdev(dev);
|
||||||
|
|
||||||
/* Delete all NAPI objects */
|
|
||||||
bnx2x_del_all_napi(bp);
|
|
||||||
|
|
||||||
/* Power on: we can't let PCI layer write to us while we are in D3 */
|
/* Power on: we can't let PCI layer write to us while we are in D3 */
|
||||||
bnx2x_set_power_state(bp, PCI_D0);
|
bnx2x_set_power_state(bp, PCI_D0);
|
||||||
|
|
||||||
|
@ -12025,6 +12023,8 @@ static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
|
||||||
bnx2x_tx_disable(bp);
|
bnx2x_tx_disable(bp);
|
||||||
|
|
||||||
bnx2x_netif_stop(bp, 0);
|
bnx2x_netif_stop(bp, 0);
|
||||||
|
/* Delete all NAPI objects */
|
||||||
|
bnx2x_del_all_napi(bp);
|
||||||
|
|
||||||
del_timer_sync(&bp->timer);
|
del_timer_sync(&bp->timer);
|
||||||
|
|
||||||
|
|
|
@ -1243,6 +1243,7 @@ static void set_multicast_list(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct net_local *lp = netdev_priv(dev);
|
struct net_local *lp = netdev_priv(dev);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
u16 cfg;
|
||||||
|
|
||||||
spin_lock_irqsave(&lp->lock, flags);
|
spin_lock_irqsave(&lp->lock, flags);
|
||||||
if (dev->flags & IFF_PROMISC)
|
if (dev->flags & IFF_PROMISC)
|
||||||
|
@ -1260,11 +1261,10 @@ static void set_multicast_list(struct net_device *dev)
|
||||||
/* in promiscuous mode, we accept errored packets,
|
/* in promiscuous mode, we accept errored packets,
|
||||||
* so we have to enable interrupts on them also
|
* so we have to enable interrupts on them also
|
||||||
*/
|
*/
|
||||||
writereg(dev, PP_RxCFG,
|
cfg = lp->curr_rx_cfg;
|
||||||
(lp->curr_rx_cfg |
|
if (lp->rx_mode == RX_ALL_ACCEPT)
|
||||||
(lp->rx_mode == RX_ALL_ACCEPT)
|
cfg |= RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL;
|
||||||
? (RX_CRC_ERROR_ENBL | RX_RUNT_ENBL | RX_EXTRA_DATA_ENBL)
|
writereg(dev, PP_RxCFG, cfg);
|
||||||
: 0));
|
|
||||||
spin_unlock_irqrestore(&lp->lock, flags);
|
spin_unlock_irqrestore(&lp->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,7 +259,7 @@ int be_process_mcc(struct be_adapter *adapter)
|
||||||
int num = 0, status = 0;
|
int num = 0, status = 0;
|
||||||
struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
|
struct be_mcc_obj *mcc_obj = &adapter->mcc_obj;
|
||||||
|
|
||||||
spin_lock_bh(&adapter->mcc_cq_lock);
|
spin_lock(&adapter->mcc_cq_lock);
|
||||||
while ((compl = be_mcc_compl_get(adapter))) {
|
while ((compl = be_mcc_compl_get(adapter))) {
|
||||||
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
|
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
|
||||||
/* Interpret flags as an async trailer */
|
/* Interpret flags as an async trailer */
|
||||||
|
@ -280,7 +280,7 @@ int be_process_mcc(struct be_adapter *adapter)
|
||||||
if (num)
|
if (num)
|
||||||
be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
|
be_cq_notify(adapter, mcc_obj->cq.id, mcc_obj->rearm_cq, num);
|
||||||
|
|
||||||
spin_unlock_bh(&adapter->mcc_cq_lock);
|
spin_unlock(&adapter->mcc_cq_lock);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +295,9 @@ static int be_mcc_wait_compl(struct be_adapter *adapter)
|
||||||
if (be_error(adapter))
|
if (be_error(adapter))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
local_bh_disable();
|
||||||
status = be_process_mcc(adapter);
|
status = be_process_mcc(adapter);
|
||||||
|
local_bh_enable();
|
||||||
|
|
||||||
if (atomic_read(&mcc_obj->q.used) == 0)
|
if (atomic_read(&mcc_obj->q.used) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -3763,7 +3763,9 @@ static void be_worker(struct work_struct *work)
|
||||||
/* when interrupts are not yet enabled, just reap any pending
|
/* when interrupts are not yet enabled, just reap any pending
|
||||||
* mcc completions */
|
* mcc completions */
|
||||||
if (!netif_running(adapter->netdev)) {
|
if (!netif_running(adapter->netdev)) {
|
||||||
|
local_bh_disable();
|
||||||
be_process_mcc(adapter);
|
be_process_mcc(adapter);
|
||||||
|
local_bh_enable();
|
||||||
goto reschedule;
|
goto reschedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1041,7 +1041,7 @@ static int gfar_probe(struct platform_device *ofdev)
|
||||||
|
|
||||||
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
|
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
|
||||||
dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
||||||
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
|
dev->features |= NETIF_F_HW_VLAN_RX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
|
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
|
||||||
|
|
|
@ -310,6 +310,7 @@ struct e1000_adapter {
|
||||||
*/
|
*/
|
||||||
struct e1000_ring *tx_ring /* One per active queue */
|
struct e1000_ring *tx_ring /* One per active queue */
|
||||||
____cacheline_aligned_in_smp;
|
____cacheline_aligned_in_smp;
|
||||||
|
u32 tx_fifo_limit;
|
||||||
|
|
||||||
struct napi_struct napi;
|
struct napi_struct napi;
|
||||||
|
|
||||||
|
|
|
@ -3516,6 +3516,15 @@ void e1000e_reset(struct e1000_adapter *adapter)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alignment of Tx data is on an arbitrary byte boundary with the
|
||||||
|
* maximum size per Tx descriptor limited only to the transmit
|
||||||
|
* allocation of the packet buffer minus 96 bytes with an upper
|
||||||
|
* limit of 24KB due to receive synchronization limitations.
|
||||||
|
*/
|
||||||
|
adapter->tx_fifo_limit = min_t(u32, ((er32(PBA) >> 16) << 10) - 96,
|
||||||
|
24 << 10);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disable Adaptive Interrupt Moderation if 2 full packets cannot
|
* Disable Adaptive Interrupt Moderation if 2 full packets cannot
|
||||||
* fit in receive buffer.
|
* fit in receive buffer.
|
||||||
|
@ -4785,12 +4794,9 @@ static bool e1000_tx_csum(struct e1000_ring *tx_ring, struct sk_buff *skb)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define E1000_MAX_PER_TXD 8192
|
|
||||||
#define E1000_MAX_TXD_PWR 12
|
|
||||||
|
|
||||||
static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
|
static int e1000_tx_map(struct e1000_ring *tx_ring, struct sk_buff *skb,
|
||||||
unsigned int first, unsigned int max_per_txd,
|
unsigned int first, unsigned int max_per_txd,
|
||||||
unsigned int nr_frags, unsigned int mss)
|
unsigned int nr_frags)
|
||||||
{
|
{
|
||||||
struct e1000_adapter *adapter = tx_ring->adapter;
|
struct e1000_adapter *adapter = tx_ring->adapter;
|
||||||
struct pci_dev *pdev = adapter->pdev;
|
struct pci_dev *pdev = adapter->pdev;
|
||||||
|
@ -5023,20 +5029,19 @@ static int __e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
||||||
|
|
||||||
static int e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
static int e1000_maybe_stop_tx(struct e1000_ring *tx_ring, int size)
|
||||||
{
|
{
|
||||||
|
BUG_ON(size > tx_ring->count);
|
||||||
|
|
||||||
if (e1000_desc_unused(tx_ring) >= size)
|
if (e1000_desc_unused(tx_ring) >= size)
|
||||||
return 0;
|
return 0;
|
||||||
return __e1000_maybe_stop_tx(tx_ring, size);
|
return __e1000_maybe_stop_tx(tx_ring, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1)
|
|
||||||
static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||||
struct net_device *netdev)
|
struct net_device *netdev)
|
||||||
{
|
{
|
||||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||||
struct e1000_ring *tx_ring = adapter->tx_ring;
|
struct e1000_ring *tx_ring = adapter->tx_ring;
|
||||||
unsigned int first;
|
unsigned int first;
|
||||||
unsigned int max_per_txd = E1000_MAX_PER_TXD;
|
|
||||||
unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
|
|
||||||
unsigned int tx_flags = 0;
|
unsigned int tx_flags = 0;
|
||||||
unsigned int len = skb_headlen(skb);
|
unsigned int len = skb_headlen(skb);
|
||||||
unsigned int nr_frags;
|
unsigned int nr_frags;
|
||||||
|
@ -5056,18 +5061,8 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
|
|
||||||
mss = skb_shinfo(skb)->gso_size;
|
mss = skb_shinfo(skb)->gso_size;
|
||||||
/*
|
|
||||||
* The controller does a simple calculation to
|
|
||||||
* make sure there is enough room in the FIFO before
|
|
||||||
* initiating the DMA for each buffer. The calc is:
|
|
||||||
* 4 = ceil(buffer len/mss). To make sure we don't
|
|
||||||
* overrun the FIFO, adjust the max buffer len if mss
|
|
||||||
* drops.
|
|
||||||
*/
|
|
||||||
if (mss) {
|
if (mss) {
|
||||||
u8 hdr_len;
|
u8 hdr_len;
|
||||||
max_per_txd = min(mss << 2, max_per_txd);
|
|
||||||
max_txd_pwr = fls(max_per_txd) - 1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TSO Workaround for 82571/2/3 Controllers -- if skb->data
|
* TSO Workaround for 82571/2/3 Controllers -- if skb->data
|
||||||
|
@ -5097,12 +5092,12 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||||
count++;
|
count++;
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
count += TXD_USE_COUNT(len, max_txd_pwr);
|
count += DIV_ROUND_UP(len, adapter->tx_fifo_limit);
|
||||||
|
|
||||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
nr_frags = skb_shinfo(skb)->nr_frags;
|
||||||
for (f = 0; f < nr_frags; f++)
|
for (f = 0; f < nr_frags; f++)
|
||||||
count += TXD_USE_COUNT(skb_frag_size(&skb_shinfo(skb)->frags[f]),
|
count += DIV_ROUND_UP(skb_frag_size(&skb_shinfo(skb)->frags[f]),
|
||||||
max_txd_pwr);
|
adapter->tx_fifo_limit);
|
||||||
|
|
||||||
if (adapter->hw.mac.tx_pkt_filtering)
|
if (adapter->hw.mac.tx_pkt_filtering)
|
||||||
e1000_transfer_dhcp_info(adapter, skb);
|
e1000_transfer_dhcp_info(adapter, skb);
|
||||||
|
@ -5144,15 +5139,18 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
|
||||||
tx_flags |= E1000_TX_FLAGS_NO_FCS;
|
tx_flags |= E1000_TX_FLAGS_NO_FCS;
|
||||||
|
|
||||||
/* if count is 0 then mapping error has occurred */
|
/* if count is 0 then mapping error has occurred */
|
||||||
count = e1000_tx_map(tx_ring, skb, first, max_per_txd, nr_frags, mss);
|
count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
|
||||||
|
nr_frags);
|
||||||
if (count) {
|
if (count) {
|
||||||
skb_tx_timestamp(skb);
|
skb_tx_timestamp(skb);
|
||||||
|
|
||||||
netdev_sent_queue(netdev, skb->len);
|
netdev_sent_queue(netdev, skb->len);
|
||||||
e1000_tx_queue(tx_ring, tx_flags, count);
|
e1000_tx_queue(tx_ring, tx_flags, count);
|
||||||
/* Make sure there is space in the ring for the next send. */
|
/* Make sure there is space in the ring for the next send. */
|
||||||
e1000_maybe_stop_tx(tx_ring, MAX_SKB_FRAGS + 2);
|
e1000_maybe_stop_tx(tx_ring,
|
||||||
|
(MAX_SKB_FRAGS *
|
||||||
|
DIV_ROUND_UP(PAGE_SIZE,
|
||||||
|
adapter->tx_fifo_limit) + 2));
|
||||||
} else {
|
} else {
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
tx_ring->buffer_info[first].time_stamp = 0;
|
tx_ring->buffer_info[first].time_stamp = 0;
|
||||||
|
@ -6327,8 +6325,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
||||||
adapter->hw.phy.autoneg_advertised = 0x2f;
|
adapter->hw.phy.autoneg_advertised = 0x2f;
|
||||||
|
|
||||||
/* ring size defaults */
|
/* ring size defaults */
|
||||||
adapter->rx_ring->count = 256;
|
adapter->rx_ring->count = E1000_DEFAULT_RXD;
|
||||||
adapter->tx_ring->count = 256;
|
adapter->tx_ring->count = E1000_DEFAULT_TXD;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initial Wake on LAN setting - If APM wake is enabled in
|
* Initial Wake on LAN setting - If APM wake is enabled in
|
||||||
|
|
|
@ -863,8 +863,8 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
|
||||||
&ip_entry->ip4dst, &ip_entry->pdst);
|
&ip_entry->ip4dst, &ip_entry->pdst);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
rc = efx_filter_get_ipv4_full(
|
rc = efx_filter_get_ipv4_full(
|
||||||
&spec, &proto, &ip_entry->ip4src, &ip_entry->psrc,
|
&spec, &proto, &ip_entry->ip4dst, &ip_entry->pdst,
|
||||||
&ip_entry->ip4dst, &ip_entry->pdst);
|
&ip_entry->ip4src, &ip_entry->psrc);
|
||||||
EFX_WARN_ON_PARANOID(rc);
|
EFX_WARN_ON_PARANOID(rc);
|
||||||
ip_mask->ip4src = ~0;
|
ip_mask->ip4src = ~0;
|
||||||
ip_mask->psrc = ~0;
|
ip_mask->psrc = ~0;
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __COMMON_H__
|
||||||
|
#define __COMMON_H__
|
||||||
|
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
|
@ -366,3 +369,5 @@ extern void stmmac_set_mac(void __iomem *ioaddr, bool enable);
|
||||||
|
|
||||||
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
extern void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr);
|
||||||
extern const struct stmmac_ring_mode_ops ring_mode_ops;
|
extern const struct stmmac_ring_mode_ops ring_mode_ops;
|
||||||
|
|
||||||
|
#endif /* __COMMON_H__ */
|
||||||
|
|
|
@ -20,6 +20,10 @@
|
||||||
|
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __DESCS_H__
|
||||||
|
#define __DESCS_H__
|
||||||
|
|
||||||
struct dma_desc {
|
struct dma_desc {
|
||||||
/* Receive descriptor */
|
/* Receive descriptor */
|
||||||
union {
|
union {
|
||||||
|
@ -166,3 +170,5 @@ enum tdes_csum_insertion {
|
||||||
* is not calculated */
|
* is not calculated */
|
||||||
cic_full = 3, /* IP header and pseudoheader */
|
cic_full = 3, /* IP header and pseudoheader */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif /* __DESCS_H__ */
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __DESC_COM_H__
|
||||||
|
#define __DESC_COM_H__
|
||||||
|
|
||||||
#if defined(CONFIG_STMMAC_RING)
|
#if defined(CONFIG_STMMAC_RING)
|
||||||
static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
|
static inline void ehn_desc_rx_set_on_ring_chain(struct dma_desc *p, int end)
|
||||||
{
|
{
|
||||||
|
@ -124,3 +127,5 @@ static inline void norm_set_tx_desc_len(struct dma_desc *p, int len)
|
||||||
p->des01.tx.buffer1_size = len;
|
p->des01.tx.buffer1_size = len;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* __DESC_COM_H__ */
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __DWMAC100_H__
|
||||||
|
#define __DWMAC100_H__
|
||||||
|
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
@ -119,3 +122,5 @@ enum ttc_control {
|
||||||
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
|
||||||
|
|
||||||
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
extern const struct stmmac_dma_ops dwmac100_dma_ops;
|
||||||
|
|
||||||
|
#endif /* __DWMAC100_H__ */
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
#ifndef __DWMAC1000_H__
|
||||||
|
#define __DWMAC1000_H__
|
||||||
|
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
@ -229,6 +231,7 @@ enum rtc_control {
|
||||||
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
|
||||||
|
|
||||||
/* Synopsys Core versions */
|
/* Synopsys Core versions */
|
||||||
#define DWMAC_CORE_3_40 34
|
#define DWMAC_CORE_3_40 0x34
|
||||||
|
|
||||||
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
extern const struct stmmac_dma_ops dwmac1000_dma_ops;
|
||||||
|
#endif /* __DWMAC1000_H__ */
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __DWMAC_DMA_H__
|
||||||
|
#define __DWMAC_DMA_H__
|
||||||
|
|
||||||
/* DMA CRS Control and Status Register Mapping */
|
/* DMA CRS Control and Status Register Mapping */
|
||||||
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
|
||||||
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
|
||||||
|
@ -109,3 +112,5 @@ extern void dwmac_dma_start_rx(void __iomem *ioaddr);
|
||||||
extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
|
extern void dwmac_dma_stop_rx(void __iomem *ioaddr);
|
||||||
extern int dwmac_dma_interrupt(void __iomem *ioaddr,
|
extern int dwmac_dma_interrupt(void __iomem *ioaddr,
|
||||||
struct stmmac_extra_stats *x);
|
struct stmmac_extra_stats *x);
|
||||||
|
|
||||||
|
#endif /* __DWMAC_DMA_H__ */
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __MMC_H__
|
||||||
|
#define __MMC_H__
|
||||||
|
|
||||||
/* MMC control register */
|
/* MMC control register */
|
||||||
/* When set, all counter are reset */
|
/* When set, all counter are reset */
|
||||||
#define MMC_CNTRL_COUNTER_RESET 0x1
|
#define MMC_CNTRL_COUNTER_RESET 0x1
|
||||||
|
@ -129,3 +132,5 @@ struct stmmac_counters {
|
||||||
extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
|
extern void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode);
|
||||||
extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
|
extern void dwmac_mmc_intr_all_mask(void __iomem *ioaddr);
|
||||||
extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
extern void dwmac_mmc_read(void __iomem *ioaddr, struct stmmac_counters *mmc);
|
||||||
|
|
||||||
|
#endif /* __MMC_H__ */
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */
|
#define MMC_TX_INTR 0x00000108 /* MMC TX Interrupt */
|
||||||
#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */
|
#define MMC_RX_INTR_MASK 0x0000010c /* MMC Interrupt Mask */
|
||||||
#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */
|
#define MMC_TX_INTR_MASK 0x00000110 /* MMC Interrupt Mask */
|
||||||
#define MMC_DEFAUL_MASK 0xffffffff
|
#define MMC_DEFAULT_MASK 0xffffffff
|
||||||
|
|
||||||
/* MMC TX counter registers */
|
/* MMC TX counter registers */
|
||||||
|
|
||||||
|
@ -147,8 +147,8 @@ void dwmac_mmc_ctrl(void __iomem *ioaddr, unsigned int mode)
|
||||||
/* To mask all all interrupts.*/
|
/* To mask all all interrupts.*/
|
||||||
void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
|
void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
|
||||||
{
|
{
|
||||||
writel(MMC_DEFAUL_MASK, ioaddr + MMC_RX_INTR_MASK);
|
writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
|
||||||
writel(MMC_DEFAUL_MASK, ioaddr + MMC_TX_INTR_MASK);
|
writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This reads the MAC core counters (if actaully supported).
|
/* This reads the MAC core counters (if actaully supported).
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef __STMMAC_H__
|
||||||
|
#define __STMMAC_H__
|
||||||
|
|
||||||
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
#define STMMAC_RESOURCE_NAME "stmmaceth"
|
||||||
#define DRV_MODULE_VERSION "March_2012"
|
#define DRV_MODULE_VERSION "March_2012"
|
||||||
|
|
||||||
|
@ -166,3 +169,5 @@ static inline void stmmac_unregister_pci(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_STMMAC_PCI */
|
#endif /* CONFIG_STMMAC_PCI */
|
||||||
|
|
||||||
|
#endif /* __STMMAC_H__ */
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
|
|
||||||
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
#ifndef __STMMAC_TIMER_H__
|
||||||
|
#define __STMMAC_TIMER_H__
|
||||||
|
|
||||||
struct stmmac_timer {
|
struct stmmac_timer {
|
||||||
void (*timer_start) (unsigned int new_freq);
|
void (*timer_start) (unsigned int new_freq);
|
||||||
|
@ -40,3 +42,5 @@ void stmmac_schedule(struct net_device *dev);
|
||||||
extern int tmu2_register_user(void *fnt, void *data);
|
extern int tmu2_register_user(void *fnt, void *data);
|
||||||
extern void tmu2_unregister_user(void);
|
extern void tmu2_unregister_user(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* __STMMAC_TIMER_H__ */
|
||||||
|
|
|
@ -394,8 +394,10 @@ static int __devexit davinci_mdio_remove(struct platform_device *pdev)
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct davinci_mdio_data *data = dev_get_drvdata(dev);
|
struct davinci_mdio_data *data = dev_get_drvdata(dev);
|
||||||
|
|
||||||
if (data->bus)
|
if (data->bus) {
|
||||||
|
mdiobus_unregister(data->bus);
|
||||||
mdiobus_free(data->bus);
|
mdiobus_free(data->bus);
|
||||||
|
}
|
||||||
|
|
||||||
if (data->clk)
|
if (data->clk)
|
||||||
clk_put(data->clk);
|
clk_put(data->clk);
|
||||||
|
|
|
@ -673,7 +673,7 @@ void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
|
||||||
sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
|
sm_pm_get_ls(smc,port_to_mib(smc,port))) ;
|
||||||
break ;
|
break ;
|
||||||
case SMT_P_REASON :
|
case SMT_P_REASON :
|
||||||
* (u_long *) to = 0 ;
|
*(u32 *)to = 0 ;
|
||||||
sp_len = 4 ;
|
sp_len = 4 ;
|
||||||
goto sp_done ;
|
goto sp_done ;
|
||||||
case SMT_P1033 : /* time stamp */
|
case SMT_P1033 : /* time stamp */
|
||||||
|
|
|
@ -413,7 +413,9 @@ static const struct usb_device_id products[] = {
|
||||||
|
|
||||||
/* 5. Gobi 2000 and 3000 devices */
|
/* 5. Gobi 2000 and 3000 devices */
|
||||||
{QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
|
{QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
|
||||||
|
{QMI_GOBI_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */
|
||||||
{QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */
|
{QMI_GOBI_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */
|
||||||
|
{QMI_GOBI_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */
|
||||||
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
|
{QMI_GOBI_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */
|
||||||
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
|
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
|
||||||
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
|
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
|
||||||
|
@ -441,6 +443,8 @@ static const struct usb_device_id products[] = {
|
||||||
{QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */
|
{QMI_GOBI_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */
|
||||||
{QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */
|
{QMI_GOBI_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */
|
||||||
{QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */
|
{QMI_GOBI_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */
|
||||||
|
{QMI_GOBI_DEVICE(0x12d1, 0x14f1)}, /* Sony Gobi 3000 Composite */
|
||||||
|
{QMI_GOBI_DEVICE(0x1410, 0xa021)}, /* Foxconn Gobi 3000 Modem device (Novatel E396) */
|
||||||
|
|
||||||
{ } /* END */
|
{ } /* END */
|
||||||
};
|
};
|
||||||
|
|
|
@ -1573,7 +1573,7 @@ int usbnet_resume (struct usb_interface *intf)
|
||||||
netif_device_present(dev->net) &&
|
netif_device_present(dev->net) &&
|
||||||
!timer_pending(&dev->delay) &&
|
!timer_pending(&dev->delay) &&
|
||||||
!test_bit(EVENT_RX_HALT, &dev->flags))
|
!test_bit(EVENT_RX_HALT, &dev->flags))
|
||||||
rx_alloc_submit(dev, GFP_KERNEL);
|
rx_alloc_submit(dev, GFP_NOIO);
|
||||||
|
|
||||||
if (!(dev->txq.qlen >= TX_QLEN(dev)))
|
if (!(dev->txq.qlen >= TX_QLEN(dev)))
|
||||||
netif_tx_wake_all_queues(dev->net);
|
netif_tx_wake_all_queues(dev->net);
|
||||||
|
|
|
@ -1482,7 +1482,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
|
||||||
case AR5K_EEPROM_MODE_11A:
|
case AR5K_EEPROM_MODE_11A:
|
||||||
offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
|
offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version);
|
||||||
rate_pcal_info = ee->ee_rate_tpwr_a;
|
rate_pcal_info = ee->ee_rate_tpwr_a;
|
||||||
ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN;
|
ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_RATE_CHAN;
|
||||||
break;
|
break;
|
||||||
case AR5K_EEPROM_MODE_11B:
|
case AR5K_EEPROM_MODE_11B:
|
||||||
offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
|
offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version);
|
||||||
|
|
|
@ -182,6 +182,7 @@
|
||||||
#define AR5K_EEPROM_EEP_DELTA 10
|
#define AR5K_EEPROM_EEP_DELTA 10
|
||||||
#define AR5K_EEPROM_N_MODES 3
|
#define AR5K_EEPROM_N_MODES 3
|
||||||
#define AR5K_EEPROM_N_5GHZ_CHAN 10
|
#define AR5K_EEPROM_N_5GHZ_CHAN 10
|
||||||
|
#define AR5K_EEPROM_N_5GHZ_RATE_CHAN 8
|
||||||
#define AR5K_EEPROM_N_2GHZ_CHAN 3
|
#define AR5K_EEPROM_N_2GHZ_CHAN 3
|
||||||
#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
|
#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4
|
||||||
#define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4
|
#define AR5K_EEPROM_N_2GHZ_CHAN_MAX 4
|
||||||
|
|
|
@ -1233,6 +1233,9 @@ uint brcms_reset(struct brcms_info *wl)
|
||||||
/* dpc will not be rescheduled */
|
/* dpc will not be rescheduled */
|
||||||
wl->resched = false;
|
wl->resched = false;
|
||||||
|
|
||||||
|
/* inform publicly that interface is down */
|
||||||
|
wl->pub->up = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2042,7 +2042,8 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
len = ETH_ALEN;
|
len = ETH_ALEN;
|
||||||
ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, &bssid, &len);
|
ret = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ASSN_AP_BSSID, bssid,
|
||||||
|
&len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
|
IPW_DEBUG_INFO("failed querying ordinals at line %d\n",
|
||||||
__LINE__);
|
__LINE__);
|
||||||
|
|
|
@ -124,6 +124,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
|
||||||
const struct fw_img *img;
|
const struct fw_img *img;
|
||||||
size_t bufsz;
|
size_t bufsz;
|
||||||
|
|
||||||
|
if (!iwl_is_ready_rf(priv))
|
||||||
|
return -EAGAIN;
|
||||||
|
|
||||||
/* default is to dump the entire data segment */
|
/* default is to dump the entire data segment */
|
||||||
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
|
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
|
||||||
priv->dbgfs_sram_offset = 0x800000;
|
priv->dbgfs_sram_offset = 0x800000;
|
||||||
|
|
|
@ -350,7 +350,7 @@ int iwl_queue_space(const struct iwl_queue *q);
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
* Error handling
|
* Error handling
|
||||||
******************************************************/
|
******************************************************/
|
||||||
int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display);
|
int iwl_dump_fh(struct iwl_trans *trans, char **buf);
|
||||||
void iwl_dump_csr(struct iwl_trans *trans);
|
void iwl_dump_csr(struct iwl_trans *trans);
|
||||||
|
|
||||||
/*****************************************************
|
/*****************************************************
|
||||||
|
|
|
@ -555,7 +555,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
|
||||||
}
|
}
|
||||||
|
|
||||||
iwl_dump_csr(trans);
|
iwl_dump_csr(trans);
|
||||||
iwl_dump_fh(trans, NULL, false);
|
iwl_dump_fh(trans, NULL);
|
||||||
|
|
||||||
iwl_op_mode_nic_error(trans->op_mode);
|
iwl_op_mode_nic_error(trans->op_mode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1649,13 +1649,9 @@ static const char *get_fh_string(int cmd)
|
||||||
#undef IWL_CMD
|
#undef IWL_CMD
|
||||||
}
|
}
|
||||||
|
|
||||||
int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
int iwl_dump_fh(struct iwl_trans *trans, char **buf)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
int pos = 0;
|
|
||||||
size_t bufsz = 0;
|
|
||||||
#endif
|
|
||||||
static const u32 fh_tbl[] = {
|
static const u32 fh_tbl[] = {
|
||||||
FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
FH_RSCSR_CHNL0_STTS_WPTR_REG,
|
||||||
FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
FH_RSCSR_CHNL0_RBDCB_BASE_REG,
|
||||||
|
@ -1667,29 +1663,35 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
|
||||||
FH_TSSR_TX_STATUS_REG,
|
FH_TSSR_TX_STATUS_REG,
|
||||||
FH_TSSR_TX_ERROR_REG
|
FH_TSSR_TX_ERROR_REG
|
||||||
};
|
};
|
||||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
|
||||||
if (display) {
|
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||||
bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
if (buf) {
|
||||||
|
int pos = 0;
|
||||||
|
size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
|
||||||
|
|
||||||
*buf = kmalloc(bufsz, GFP_KERNEL);
|
*buf = kmalloc(bufsz, GFP_KERNEL);
|
||||||
if (!*buf)
|
if (!*buf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||||
"FH register values:\n");
|
"FH register values:\n");
|
||||||
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
|
||||||
pos += scnprintf(*buf + pos, bufsz - pos,
|
pos += scnprintf(*buf + pos, bufsz - pos,
|
||||||
" %34s: 0X%08x\n",
|
" %34s: 0X%08x\n",
|
||||||
get_fh_string(fh_tbl[i]),
|
get_fh_string(fh_tbl[i]),
|
||||||
iwl_read_direct32(trans, fh_tbl[i]));
|
iwl_read_direct32(trans, fh_tbl[i]));
|
||||||
}
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
IWL_ERR(trans, "FH register values:\n");
|
IWL_ERR(trans, "FH register values:\n");
|
||||||
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
|
for (i = 0; i < ARRAY_SIZE(fh_tbl); i++)
|
||||||
IWL_ERR(trans, " %34s: 0X%08x\n",
|
IWL_ERR(trans, " %34s: 0X%08x\n",
|
||||||
get_fh_string(fh_tbl[i]),
|
get_fh_string(fh_tbl[i]),
|
||||||
iwl_read_direct32(trans, fh_tbl[i]));
|
iwl_read_direct32(trans, fh_tbl[i]));
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1982,11 +1984,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct iwl_trans *trans = file->private_data;
|
struct iwl_trans *trans = file->private_data;
|
||||||
char *buf;
|
char *buf = NULL;
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
ssize_t ret = -EFAULT;
|
ssize_t ret = -EFAULT;
|
||||||
|
|
||||||
ret = pos = iwl_dump_fh(trans, &buf, true);
|
ret = pos = iwl_dump_fh(trans, &buf);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
ret = simple_read_from_buffer(user_buf,
|
ret = simple_read_from_buffer(user_buf,
|
||||||
count, ppos, buf, pos);
|
count, ppos, buf, pos);
|
||||||
|
|
|
@ -57,8 +57,7 @@
|
||||||
static const struct ethtool_ops xennet_ethtool_ops;
|
static const struct ethtool_ops xennet_ethtool_ops;
|
||||||
|
|
||||||
struct netfront_cb {
|
struct netfront_cb {
|
||||||
struct page *page;
|
int pull_to;
|
||||||
unsigned offset;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
|
#define NETFRONT_SKB_CB(skb) ((struct netfront_cb *)((skb)->cb))
|
||||||
|
@ -867,15 +866,9 @@ static int handle_incoming_queue(struct net_device *dev,
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
while ((skb = __skb_dequeue(rxq)) != NULL) {
|
while ((skb = __skb_dequeue(rxq)) != NULL) {
|
||||||
struct page *page = NETFRONT_SKB_CB(skb)->page;
|
int pull_to = NETFRONT_SKB_CB(skb)->pull_to;
|
||||||
void *vaddr = page_address(page);
|
|
||||||
unsigned offset = NETFRONT_SKB_CB(skb)->offset;
|
|
||||||
|
|
||||||
memcpy(skb->data, vaddr + offset,
|
__pskb_pull_tail(skb, pull_to - skb_headlen(skb));
|
||||||
skb_headlen(skb));
|
|
||||||
|
|
||||||
if (page != skb_frag_page(&skb_shinfo(skb)->frags[0]))
|
|
||||||
__free_page(page);
|
|
||||||
|
|
||||||
/* Ethernet work: Delayed to here as it peeks the header. */
|
/* Ethernet work: Delayed to here as it peeks the header. */
|
||||||
skb->protocol = eth_type_trans(skb, dev);
|
skb->protocol = eth_type_trans(skb, dev);
|
||||||
|
@ -913,7 +906,6 @@ static int xennet_poll(struct napi_struct *napi, int budget)
|
||||||
struct sk_buff_head errq;
|
struct sk_buff_head errq;
|
||||||
struct sk_buff_head tmpq;
|
struct sk_buff_head tmpq;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned int len;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
spin_lock(&np->rx_lock);
|
spin_lock(&np->rx_lock);
|
||||||
|
@ -955,24 +947,13 @@ err:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NETFRONT_SKB_CB(skb)->page =
|
NETFRONT_SKB_CB(skb)->pull_to = rx->status;
|
||||||
skb_frag_page(&skb_shinfo(skb)->frags[0]);
|
if (NETFRONT_SKB_CB(skb)->pull_to > RX_COPY_THRESHOLD)
|
||||||
NETFRONT_SKB_CB(skb)->offset = rx->offset;
|
NETFRONT_SKB_CB(skb)->pull_to = RX_COPY_THRESHOLD;
|
||||||
|
|
||||||
len = rx->status;
|
skb_shinfo(skb)->frags[0].page_offset = rx->offset;
|
||||||
if (len > RX_COPY_THRESHOLD)
|
skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status);
|
||||||
len = RX_COPY_THRESHOLD;
|
skb->data_len = rx->status;
|
||||||
skb_put(skb, len);
|
|
||||||
|
|
||||||
if (rx->status > len) {
|
|
||||||
skb_shinfo(skb)->frags[0].page_offset =
|
|
||||||
rx->offset + len;
|
|
||||||
skb_frag_size_set(&skb_shinfo(skb)->frags[0], rx->status - len);
|
|
||||||
skb->data_len = rx->status - len;
|
|
||||||
} else {
|
|
||||||
__skb_fill_page_desc(skb, 0, NULL, 0, 0);
|
|
||||||
skb_shinfo(skb)->nr_frags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = xennet_fill_frags(np, skb, &tmpq);
|
i = xennet_fill_frags(np, skb, &tmpq);
|
||||||
|
|
||||||
|
@ -999,7 +980,7 @@ err:
|
||||||
* receive throughout using the standard receive
|
* receive throughout using the standard receive
|
||||||
* buffer size was cut by 25%(!!!).
|
* buffer size was cut by 25%(!!!).
|
||||||
*/
|
*/
|
||||||
skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
|
skb->truesize += skb->data_len - RX_COPY_THRESHOLD;
|
||||||
skb->len += skb->data_len;
|
skb->len += skb->data_len;
|
||||||
|
|
||||||
if (rx->flags & XEN_NETRXF_csum_blank)
|
if (rx->flags & XEN_NETRXF_csum_blank)
|
||||||
|
|
|
@ -1576,9 +1576,14 @@ cifs_readv_callback(struct mid_q_entry *mid)
|
||||||
/* result already set, check signature */
|
/* result already set, check signature */
|
||||||
if (server->sec_mode &
|
if (server->sec_mode &
|
||||||
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
||||||
if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
|
int rc = 0;
|
||||||
server, mid->sequence_number + 1))
|
|
||||||
cERROR(1, "Unexpected SMB signature");
|
rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
|
||||||
|
server,
|
||||||
|
mid->sequence_number + 1);
|
||||||
|
if (rc)
|
||||||
|
cERROR(1, "SMB signature verification returned "
|
||||||
|
"error = %d", rc);
|
||||||
}
|
}
|
||||||
/* FIXME: should this be counted toward the initiating task? */
|
/* FIXME: should this be counted toward the initiating task? */
|
||||||
task_io_account_read(rdata->bytes);
|
task_io_account_read(rdata->bytes);
|
||||||
|
|
|
@ -356,19 +356,12 @@ cifs_create_get_file_info:
|
||||||
cifs_create_set_dentry:
|
cifs_create_set_dentry:
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
|
cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
|
||||||
|
CIFSSMBClose(xid, tcon, *fileHandle);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
d_drop(direntry);
|
d_drop(direntry);
|
||||||
d_add(direntry, newinode);
|
d_add(direntry, newinode);
|
||||||
|
|
||||||
/* ENOENT for create? How weird... */
|
|
||||||
rc = -ENOENT;
|
|
||||||
if (!newinode) {
|
|
||||||
CIFSSMBClose(xid, tcon, *fileHandle);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
rc = 0;
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(buf);
|
kfree(buf);
|
||||||
kfree(full_path);
|
kfree(full_path);
|
||||||
|
|
|
@ -124,10 +124,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||||
{
|
{
|
||||||
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
struct cifsInodeInfo *cifs_i = CIFS_I(inode);
|
||||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||||
unsigned long oldtime = cifs_i->time;
|
|
||||||
|
|
||||||
cifs_revalidate_cache(inode, fattr);
|
cifs_revalidate_cache(inode, fattr);
|
||||||
|
|
||||||
|
spin_lock(&inode->i_lock);
|
||||||
inode->i_atime = fattr->cf_atime;
|
inode->i_atime = fattr->cf_atime;
|
||||||
inode->i_mtime = fattr->cf_mtime;
|
inode->i_mtime = fattr->cf_mtime;
|
||||||
inode->i_ctime = fattr->cf_ctime;
|
inode->i_ctime = fattr->cf_ctime;
|
||||||
|
@ -148,9 +148,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||||
else
|
else
|
||||||
cifs_i->time = jiffies;
|
cifs_i->time = jiffies;
|
||||||
|
|
||||||
cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
|
|
||||||
oldtime, cifs_i->time);
|
|
||||||
|
|
||||||
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
|
||||||
|
|
||||||
cifs_i->server_eof = fattr->cf_eof;
|
cifs_i->server_eof = fattr->cf_eof;
|
||||||
|
@ -158,7 +155,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
|
||||||
* Can't safely change the file size here if the client is writing to
|
* Can't safely change the file size here if the client is writing to
|
||||||
* it due to potential races.
|
* it due to potential races.
|
||||||
*/
|
*/
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
|
if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
|
||||||
i_size_write(inode, fattr->cf_eof);
|
i_size_write(inode, fattr->cf_eof);
|
||||||
|
|
||||||
|
@ -859,12 +855,14 @@ struct inode *cifs_root_iget(struct super_block *sb)
|
||||||
|
|
||||||
if (rc && tcon->ipc) {
|
if (rc && tcon->ipc) {
|
||||||
cFYI(1, "ipc connection - fake read inode");
|
cFYI(1, "ipc connection - fake read inode");
|
||||||
|
spin_lock(&inode->i_lock);
|
||||||
inode->i_mode |= S_IFDIR;
|
inode->i_mode |= S_IFDIR;
|
||||||
set_nlink(inode, 2);
|
set_nlink(inode, 2);
|
||||||
inode->i_op = &cifs_ipc_inode_ops;
|
inode->i_op = &cifs_ipc_inode_ops;
|
||||||
inode->i_fop = &simple_dir_operations;
|
inode->i_fop = &simple_dir_operations;
|
||||||
inode->i_uid = cifs_sb->mnt_uid;
|
inode->i_uid = cifs_sb->mnt_uid;
|
||||||
inode->i_gid = cifs_sb->mnt_gid;
|
inode->i_gid = cifs_sb->mnt_gid;
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
} else if (rc) {
|
} else if (rc) {
|
||||||
iget_failed(inode);
|
iget_failed(inode);
|
||||||
inode = ERR_PTR(rc);
|
inode = ERR_PTR(rc);
|
||||||
|
@ -1110,6 +1108,15 @@ undo_setattr:
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* copied from fs/nfs/dir.c with small changes */
|
||||||
|
static void
|
||||||
|
cifs_drop_nlink(struct inode *inode)
|
||||||
|
{
|
||||||
|
spin_lock(&inode->i_lock);
|
||||||
|
if (inode->i_nlink > 0)
|
||||||
|
drop_nlink(inode);
|
||||||
|
spin_unlock(&inode->i_lock);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If dentry->d_inode is null (usually meaning the cached dentry
|
* If dentry->d_inode is null (usually meaning the cached dentry
|
||||||
|
@ -1166,13 +1173,13 @@ retry_std_delete:
|
||||||
psx_del_no_retry:
|
psx_del_no_retry:
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
if (inode)
|
if (inode)
|
||||||
drop_nlink(inode);
|
cifs_drop_nlink(inode);
|
||||||
} else if (rc == -ENOENT) {
|
} else if (rc == -ENOENT) {
|
||||||
d_drop(dentry);
|
d_drop(dentry);
|
||||||
} else if (rc == -ETXTBSY) {
|
} else if (rc == -ETXTBSY) {
|
||||||
rc = cifs_rename_pending_delete(full_path, dentry, xid);
|
rc = cifs_rename_pending_delete(full_path, dentry, xid);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
drop_nlink(inode);
|
cifs_drop_nlink(inode);
|
||||||
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
|
} else if ((rc == -EACCES) && (dosattr == 0) && inode) {
|
||||||
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
|
attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
|
||||||
if (attrs == NULL) {
|
if (attrs == NULL) {
|
||||||
|
@ -1241,9 +1248,10 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
|
||||||
* setting nlink not necessary except in cases where we failed to get it
|
* setting nlink not necessary except in cases where we failed to get it
|
||||||
* from the server or was set bogus
|
* from the server or was set bogus
|
||||||
*/
|
*/
|
||||||
|
spin_lock(&dentry->d_inode->i_lock);
|
||||||
if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
|
if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
|
||||||
set_nlink(dentry->d_inode, 2);
|
set_nlink(dentry->d_inode, 2);
|
||||||
|
spin_unlock(&dentry->d_inode->i_lock);
|
||||||
mode &= ~current_umask();
|
mode &= ~current_umask();
|
||||||
/* must turn on setgid bit if parent dir has it */
|
/* must turn on setgid bit if parent dir has it */
|
||||||
if (inode->i_mode & S_ISGID)
|
if (inode->i_mode & S_ISGID)
|
||||||
|
|
|
@ -433,7 +433,9 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
|
||||||
if (old_file->d_inode) {
|
if (old_file->d_inode) {
|
||||||
cifsInode = CIFS_I(old_file->d_inode);
|
cifsInode = CIFS_I(old_file->d_inode);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
|
spin_lock(&old_file->d_inode->i_lock);
|
||||||
inc_nlink(old_file->d_inode);
|
inc_nlink(old_file->d_inode);
|
||||||
|
spin_unlock(&old_file->d_inode->i_lock);
|
||||||
/* BB should we make this contingent on superblock flag NOATIME? */
|
/* BB should we make this contingent on superblock flag NOATIME? */
|
||||||
/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
|
/* old_file->d_inode->i_ctime = CURRENT_TIME;*/
|
||||||
/* parent dir timestamps will update from srv
|
/* parent dir timestamps will update from srv
|
||||||
|
|
|
@ -52,7 +52,8 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
|
||||||
cERROR(1, "Bad protocol string signature header %x",
|
cERROR(1, "Bad protocol string signature header %x",
|
||||||
*(unsigned int *) hdr->ProtocolId);
|
*(unsigned int *) hdr->ProtocolId);
|
||||||
if (mid != hdr->MessageId)
|
if (mid != hdr->MessageId)
|
||||||
cERROR(1, "Mids do not match");
|
cERROR(1, "Mids do not match: %llu and %llu", mid,
|
||||||
|
hdr->MessageId);
|
||||||
}
|
}
|
||||||
cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId);
|
cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -107,7 +108,7 @@ smb2_check_message(char *buf, unsigned int length)
|
||||||
* ie Validate the wct via smb2_struct_sizes table above
|
* ie Validate the wct via smb2_struct_sizes table above
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (length < 2 + sizeof(struct smb2_hdr)) {
|
if (length < sizeof(struct smb2_pdu)) {
|
||||||
if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
|
if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
|
||||||
pdu->StructureSize2 = 0;
|
pdu->StructureSize2 = 0;
|
||||||
/*
|
/*
|
||||||
|
@ -121,15 +122,15 @@ smb2_check_message(char *buf, unsigned int length)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) {
|
if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) {
|
||||||
cERROR(1, "SMB length greater than maximum, mid=%lld", mid);
|
cERROR(1, "SMB length greater than maximum, mid=%llu", mid);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_smb2_hdr(hdr, mid))
|
if (check_smb2_hdr(hdr, mid))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (hdr->StructureSize != SMB2_HEADER_SIZE) {
|
if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
|
||||||
cERROR(1, "Illegal structure size %d",
|
cERROR(1, "Illegal structure size %u",
|
||||||
le16_to_cpu(hdr->StructureSize));
|
le16_to_cpu(hdr->StructureSize));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -161,8 +162,9 @@ smb2_check_message(char *buf, unsigned int length)
|
||||||
if (4 + len != clc_len) {
|
if (4 + len != clc_len) {
|
||||||
cFYI(1, "Calculated size %u length %u mismatch mid %llu",
|
cFYI(1, "Calculated size %u length %u mismatch mid %llu",
|
||||||
clc_len, 4 + len, mid);
|
clc_len, 4 + len, mid);
|
||||||
if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */
|
/* server can return one byte more */
|
||||||
return 0; /* BB workaround Samba 3 bug SessSetup rsp */
|
if (clc_len == 4 + len + 1)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -87,10 +87,6 @@
|
||||||
|
|
||||||
#define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe)
|
#define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe)
|
||||||
|
|
||||||
#define SMB2_HEADER_SIZE __constant_le16_to_cpu(64)
|
|
||||||
|
|
||||||
#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SMB2 Header Definition
|
* SMB2 Header Definition
|
||||||
*
|
*
|
||||||
|
@ -99,6 +95,9 @@
|
||||||
* "PDU" : "Protocol Data Unit" (ie a network "frame")
|
* "PDU" : "Protocol Data Unit" (ie a network "frame")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define SMB2_HEADER_STRUCTURE_SIZE __constant_le16_to_cpu(64)
|
||||||
|
|
||||||
struct smb2_hdr {
|
struct smb2_hdr {
|
||||||
__be32 smb2_buf_length; /* big endian on wire */
|
__be32 smb2_buf_length; /* big endian on wire */
|
||||||
/* length is only two or three bytes - with
|
/* length is only two or three bytes - with
|
||||||
|
@ -140,6 +139,9 @@ struct smb2_pdu {
|
||||||
* command code name for the struct. Note that structures must be packed.
|
* command code name for the struct. Note that structures must be packed.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9)
|
||||||
|
|
||||||
struct smb2_err_rsp {
|
struct smb2_err_rsp {
|
||||||
struct smb2_hdr hdr;
|
struct smb2_hdr hdr;
|
||||||
__le16 StructureSize;
|
__le16 StructureSize;
|
||||||
|
|
|
@ -503,13 +503,16 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
|
||||||
/* convert the length into a more usable form */
|
/* convert the length into a more usable form */
|
||||||
if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
|
||||||
struct kvec iov;
|
struct kvec iov;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
iov.iov_base = mid->resp_buf;
|
iov.iov_base = mid->resp_buf;
|
||||||
iov.iov_len = len;
|
iov.iov_len = len;
|
||||||
/* FIXME: add code to kill session */
|
/* FIXME: add code to kill session */
|
||||||
if (cifs_verify_signature(&iov, 1, server,
|
rc = cifs_verify_signature(&iov, 1, server,
|
||||||
mid->sequence_number + 1) != 0)
|
mid->sequence_number + 1);
|
||||||
cERROR(1, "Unexpected SMB signature");
|
if (rc)
|
||||||
|
cERROR(1, "SMB signature verification returned error = "
|
||||||
|
"%d", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BB special case reconnect tid and uid here? */
|
/* BB special case reconnect tid and uid here? */
|
||||||
|
|
|
@ -2149,7 +2149,7 @@
|
||||||
#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8
|
#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8
|
||||||
#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9
|
#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9
|
||||||
#define PCI_DEVICE_ID_NX2_5706S 0x16aa
|
#define PCI_DEVICE_ID_NX2_5706S 0x16aa
|
||||||
#define PCI_DEVICE_ID_NX2_57840_MF 0x16ab
|
#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4
|
||||||
#define PCI_DEVICE_ID_NX2_5708S 0x16ac
|
#define PCI_DEVICE_ID_NX2_5708S 0x16ac
|
||||||
#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad
|
#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad
|
||||||
#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae
|
#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct nf_conntrack_ecache {
|
||||||
u16 ctmask; /* bitmask of ct events to be delivered */
|
u16 ctmask; /* bitmask of ct events to be delivered */
|
||||||
u16 expmask; /* bitmask of expect events to be delivered */
|
u16 expmask; /* bitmask of expect events to be delivered */
|
||||||
u32 pid; /* netlink pid of destroyer */
|
u32 pid; /* netlink pid of destroyer */
|
||||||
|
struct timer_list timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct nf_conntrack_ecache *
|
static inline struct nf_conntrack_ecache *
|
||||||
|
|
|
@ -168,25 +168,17 @@ static void poll_napi(struct net_device *dev)
|
||||||
struct napi_struct *napi;
|
struct napi_struct *napi;
|
||||||
int budget = 16;
|
int budget = 16;
|
||||||
|
|
||||||
WARN_ON_ONCE(!irqs_disabled());
|
|
||||||
|
|
||||||
list_for_each_entry(napi, &dev->napi_list, dev_list) {
|
list_for_each_entry(napi, &dev->napi_list, dev_list) {
|
||||||
local_irq_enable();
|
|
||||||
if (napi->poll_owner != smp_processor_id() &&
|
if (napi->poll_owner != smp_processor_id() &&
|
||||||
spin_trylock(&napi->poll_lock)) {
|
spin_trylock(&napi->poll_lock)) {
|
||||||
rcu_read_lock_bh();
|
|
||||||
budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
|
budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
|
||||||
napi, budget);
|
napi, budget);
|
||||||
rcu_read_unlock_bh();
|
|
||||||
spin_unlock(&napi->poll_lock);
|
spin_unlock(&napi->poll_lock);
|
||||||
|
|
||||||
if (!budget) {
|
if (!budget)
|
||||||
local_irq_disable();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
local_irq_disable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void service_arp_queue(struct netpoll_info *npi)
|
static void service_arp_queue(struct netpoll_info *npi)
|
||||||
|
|
|
@ -124,6 +124,8 @@ static DEFINE_SPINLOCK(mfc_unres_lock);
|
||||||
static struct kmem_cache *mrt_cachep __read_mostly;
|
static struct kmem_cache *mrt_cachep __read_mostly;
|
||||||
|
|
||||||
static struct mr_table *ipmr_new_table(struct net *net, u32 id);
|
static struct mr_table *ipmr_new_table(struct net *net, u32 id);
|
||||||
|
static void ipmr_free_table(struct mr_table *mrt);
|
||||||
|
|
||||||
static int ip_mr_forward(struct net *net, struct mr_table *mrt,
|
static int ip_mr_forward(struct net *net, struct mr_table *mrt,
|
||||||
struct sk_buff *skb, struct mfc_cache *cache,
|
struct sk_buff *skb, struct mfc_cache *cache,
|
||||||
int local);
|
int local);
|
||||||
|
@ -131,6 +133,7 @@ static int ipmr_cache_report(struct mr_table *mrt,
|
||||||
struct sk_buff *pkt, vifi_t vifi, int assert);
|
struct sk_buff *pkt, vifi_t vifi, int assert);
|
||||||
static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
|
static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
|
||||||
struct mfc_cache *c, struct rtmsg *rtm);
|
struct mfc_cache *c, struct rtmsg *rtm);
|
||||||
|
static void mroute_clean_tables(struct mr_table *mrt);
|
||||||
static void ipmr_expire_process(unsigned long arg);
|
static void ipmr_expire_process(unsigned long arg);
|
||||||
|
|
||||||
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
|
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
|
||||||
|
@ -271,7 +274,7 @@ static void __net_exit ipmr_rules_exit(struct net *net)
|
||||||
|
|
||||||
list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
|
list_for_each_entry_safe(mrt, next, &net->ipv4.mr_tables, list) {
|
||||||
list_del(&mrt->list);
|
list_del(&mrt->list);
|
||||||
kfree(mrt);
|
ipmr_free_table(mrt);
|
||||||
}
|
}
|
||||||
fib_rules_unregister(net->ipv4.mr_rules_ops);
|
fib_rules_unregister(net->ipv4.mr_rules_ops);
|
||||||
}
|
}
|
||||||
|
@ -299,7 +302,7 @@ static int __net_init ipmr_rules_init(struct net *net)
|
||||||
|
|
||||||
static void __net_exit ipmr_rules_exit(struct net *net)
|
static void __net_exit ipmr_rules_exit(struct net *net)
|
||||||
{
|
{
|
||||||
kfree(net->ipv4.mrt);
|
ipmr_free_table(net->ipv4.mrt);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -336,6 +339,13 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
|
||||||
return mrt;
|
return mrt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ipmr_free_table(struct mr_table *mrt)
|
||||||
|
{
|
||||||
|
del_timer_sync(&mrt->ipmr_expire_timer);
|
||||||
|
mroute_clean_tables(mrt);
|
||||||
|
kfree(mrt);
|
||||||
|
}
|
||||||
|
|
||||||
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
|
/* Service routines creating virtual interfaces: DVMRP tunnels and PIMREG */
|
||||||
|
|
||||||
static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
|
static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v)
|
||||||
|
|
|
@ -502,7 +502,10 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
|
||||||
ret = nf_ct_expect_related(rtcp_exp);
|
ret = nf_ct_expect_related(rtcp_exp);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
break;
|
break;
|
||||||
else if (ret != -EBUSY) {
|
else if (ret == -EBUSY) {
|
||||||
|
nf_ct_unexpect_related(rtp_exp);
|
||||||
|
continue;
|
||||||
|
} else if (ret < 0) {
|
||||||
nf_ct_unexpect_related(rtp_exp);
|
nf_ct_unexpect_related(rtp_exp);
|
||||||
port = 0;
|
port = 0;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -934,12 +934,14 @@ static u32 __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
|
||||||
if (mtu < ip_rt_min_pmtu)
|
if (mtu < ip_rt_min_pmtu)
|
||||||
mtu = ip_rt_min_pmtu;
|
mtu = ip_rt_min_pmtu;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) {
|
if (fib_lookup(dev_net(rt->dst.dev), fl4, &res) == 0) {
|
||||||
struct fib_nh *nh = &FIB_RES_NH(res);
|
struct fib_nh *nh = &FIB_RES_NH(res);
|
||||||
|
|
||||||
update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
|
update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
|
||||||
jiffies + ip_rt_mtu_expires);
|
jiffies + ip_rt_mtu_expires);
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return mtu;
|
return mtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,7 +958,7 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
|
||||||
dst->obsolete = DST_OBSOLETE_KILL;
|
dst->obsolete = DST_OBSOLETE_KILL;
|
||||||
} else {
|
} else {
|
||||||
rt->rt_pmtu = mtu;
|
rt->rt_pmtu = mtu;
|
||||||
dst_set_expires(&rt->dst, ip_rt_mtu_expires);
|
rt->dst.expires = max(1UL, jiffies + ip_rt_mtu_expires);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1263,7 +1265,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
|
||||||
{
|
{
|
||||||
struct rtable *rt = (struct rtable *) dst;
|
struct rtable *rt = (struct rtable *) dst;
|
||||||
|
|
||||||
if (dst->flags & DST_NOCACHE) {
|
if (!list_empty(&rt->rt_uncached)) {
|
||||||
spin_lock_bh(&rt_uncached_lock);
|
spin_lock_bh(&rt_uncached_lock);
|
||||||
list_del(&rt->rt_uncached);
|
list_del(&rt->rt_uncached);
|
||||||
spin_unlock_bh(&rt_uncached_lock);
|
spin_unlock_bh(&rt_uncached_lock);
|
||||||
|
|
|
@ -2926,13 +2926,14 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack)
|
||||||
* tcp_xmit_retransmit_queue().
|
* tcp_xmit_retransmit_queue().
|
||||||
*/
|
*/
|
||||||
static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||||||
int newly_acked_sacked, bool is_dupack,
|
int prior_sacked, bool is_dupack,
|
||||||
int flag)
|
int flag)
|
||||||
{
|
{
|
||||||
struct inet_connection_sock *icsk = inet_csk(sk);
|
struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
struct tcp_sock *tp = tcp_sk(sk);
|
struct tcp_sock *tp = tcp_sk(sk);
|
||||||
int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) &&
|
int do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) &&
|
||||||
(tcp_fackets_out(tp) > tp->reordering));
|
(tcp_fackets_out(tp) > tp->reordering));
|
||||||
|
int newly_acked_sacked = 0;
|
||||||
int fast_rexmit = 0;
|
int fast_rexmit = 0;
|
||||||
|
|
||||||
if (WARN_ON(!tp->packets_out && tp->sacked_out))
|
if (WARN_ON(!tp->packets_out && tp->sacked_out))
|
||||||
|
@ -2992,6 +2993,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||||||
tcp_add_reno_sack(sk);
|
tcp_add_reno_sack(sk);
|
||||||
} else
|
} else
|
||||||
do_lost = tcp_try_undo_partial(sk, pkts_acked);
|
do_lost = tcp_try_undo_partial(sk, pkts_acked);
|
||||||
|
newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked;
|
||||||
break;
|
break;
|
||||||
case TCP_CA_Loss:
|
case TCP_CA_Loss:
|
||||||
if (flag & FLAG_DATA_ACKED)
|
if (flag & FLAG_DATA_ACKED)
|
||||||
|
@ -3013,6 +3015,7 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked,
|
||||||
if (is_dupack)
|
if (is_dupack)
|
||||||
tcp_add_reno_sack(sk);
|
tcp_add_reno_sack(sk);
|
||||||
}
|
}
|
||||||
|
newly_acked_sacked = pkts_acked + tp->sacked_out - prior_sacked;
|
||||||
|
|
||||||
if (icsk->icsk_ca_state <= TCP_CA_Disorder)
|
if (icsk->icsk_ca_state <= TCP_CA_Disorder)
|
||||||
tcp_try_undo_dsack(sk);
|
tcp_try_undo_dsack(sk);
|
||||||
|
@ -3590,7 +3593,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||||
int prior_packets;
|
int prior_packets;
|
||||||
int prior_sacked = tp->sacked_out;
|
int prior_sacked = tp->sacked_out;
|
||||||
int pkts_acked = 0;
|
int pkts_acked = 0;
|
||||||
int newly_acked_sacked = 0;
|
|
||||||
bool frto_cwnd = false;
|
bool frto_cwnd = false;
|
||||||
|
|
||||||
/* If the ack is older than previous acks
|
/* If the ack is older than previous acks
|
||||||
|
@ -3666,8 +3668,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||||
flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);
|
flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una);
|
||||||
|
|
||||||
pkts_acked = prior_packets - tp->packets_out;
|
pkts_acked = prior_packets - tp->packets_out;
|
||||||
newly_acked_sacked = (prior_packets - prior_sacked) -
|
|
||||||
(tp->packets_out - tp->sacked_out);
|
|
||||||
|
|
||||||
if (tp->frto_counter)
|
if (tp->frto_counter)
|
||||||
frto_cwnd = tcp_process_frto(sk, flag);
|
frto_cwnd = tcp_process_frto(sk, flag);
|
||||||
|
@ -3681,7 +3681,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||||
tcp_may_raise_cwnd(sk, flag))
|
tcp_may_raise_cwnd(sk, flag))
|
||||||
tcp_cong_avoid(sk, ack, prior_in_flight);
|
tcp_cong_avoid(sk, ack, prior_in_flight);
|
||||||
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
|
is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP));
|
||||||
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
|
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
|
||||||
is_dupack, flag);
|
is_dupack, flag);
|
||||||
} else {
|
} else {
|
||||||
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
|
if ((flag & FLAG_DATA_ACKED) && !frto_cwnd)
|
||||||
|
@ -3698,7 +3698,7 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||||
no_queue:
|
no_queue:
|
||||||
/* If data was DSACKed, see if we can undo a cwnd reduction. */
|
/* If data was DSACKed, see if we can undo a cwnd reduction. */
|
||||||
if (flag & FLAG_DSACKING_ACK)
|
if (flag & FLAG_DSACKING_ACK)
|
||||||
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
|
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
|
||||||
is_dupack, flag);
|
is_dupack, flag);
|
||||||
/* If this ack opens up a zero window, clear backoff. It was
|
/* If this ack opens up a zero window, clear backoff. It was
|
||||||
* being used to time the probes, and is probably far higher than
|
* being used to time the probes, and is probably far higher than
|
||||||
|
@ -3718,8 +3718,7 @@ old_ack:
|
||||||
*/
|
*/
|
||||||
if (TCP_SKB_CB(skb)->sacked) {
|
if (TCP_SKB_CB(skb)->sacked) {
|
||||||
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
|
flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una);
|
||||||
newly_acked_sacked = tp->sacked_out - prior_sacked;
|
tcp_fastretrans_alert(sk, pkts_acked, prior_sacked,
|
||||||
tcp_fastretrans_alert(sk, pkts_acked, newly_acked_sacked,
|
|
||||||
is_dupack, flag);
|
is_dupack, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,8 +167,6 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
struct esp_data *esp = x->data;
|
struct esp_data *esp = x->data;
|
||||||
|
|
||||||
/* skb is pure payload to encrypt */
|
/* skb is pure payload to encrypt */
|
||||||
err = -ENOMEM;
|
|
||||||
|
|
||||||
aead = esp->aead;
|
aead = esp->aead;
|
||||||
alen = crypto_aead_authsize(aead);
|
alen = crypto_aead_authsize(aead);
|
||||||
|
|
||||||
|
@ -203,8 +201,10 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
|
tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
|
||||||
if (!tmp)
|
if (!tmp) {
|
||||||
|
err = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
seqhi = esp_tmp_seqhi(tmp);
|
seqhi = esp_tmp_seqhi(tmp);
|
||||||
iv = esp_tmp_iv(aead, tmp, seqhilen);
|
iv = esp_tmp_iv(aead, tmp, seqhilen);
|
||||||
|
|
|
@ -1347,11 +1347,10 @@ static void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
|
||||||
/* Remove from tunnel list */
|
/* Remove from tunnel list */
|
||||||
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
|
spin_lock_bh(&pn->l2tp_tunnel_list_lock);
|
||||||
list_del_rcu(&tunnel->list);
|
list_del_rcu(&tunnel->list);
|
||||||
|
kfree_rcu(tunnel, rcu);
|
||||||
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
|
spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
|
||||||
synchronize_rcu();
|
|
||||||
|
|
||||||
atomic_dec(&l2tp_tunnel_count);
|
atomic_dec(&l2tp_tunnel_count);
|
||||||
kfree(tunnel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a socket for the tunnel, if one isn't set up by
|
/* Create a socket for the tunnel, if one isn't set up by
|
||||||
|
|
|
@ -163,6 +163,7 @@ struct l2tp_tunnel_cfg {
|
||||||
|
|
||||||
struct l2tp_tunnel {
|
struct l2tp_tunnel {
|
||||||
int magic; /* Should be L2TP_TUNNEL_MAGIC */
|
int magic; /* Should be L2TP_TUNNEL_MAGIC */
|
||||||
|
struct rcu_head rcu;
|
||||||
rwlock_t hlist_lock; /* protect session_hlist */
|
rwlock_t hlist_lock; /* protect session_hlist */
|
||||||
struct hlist_head session_hlist[L2TP_HASH_SIZE];
|
struct hlist_head session_hlist[L2TP_HASH_SIZE];
|
||||||
/* hashed list of sessions,
|
/* hashed list of sessions,
|
||||||
|
|
|
@ -1811,37 +1811,31 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||||
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
|
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
|
||||||
sdata, NULL, NULL);
|
sdata, NULL, NULL);
|
||||||
} else {
|
} else {
|
||||||
int is_mesh_mcast = 1;
|
/* DS -> MBSS (802.11-2012 13.11.3.3).
|
||||||
const u8 *mesh_da;
|
* For unicast with unknown forwarding information,
|
||||||
|
* destination might be in the MBSS or if that fails
|
||||||
|
* forwarded to another mesh gate. In either case
|
||||||
|
* resolution will be handled in ieee80211_xmit(), so
|
||||||
|
* leave the original DA. This also works for mcast */
|
||||||
|
const u8 *mesh_da = skb->data;
|
||||||
|
|
||||||
if (is_multicast_ether_addr(skb->data))
|
if (mppath)
|
||||||
/* DA TA mSA AE:SA */
|
|
||||||
mesh_da = skb->data;
|
|
||||||
else {
|
|
||||||
static const u8 bcast[ETH_ALEN] =
|
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
|
||||||
if (mppath) {
|
|
||||||
/* RA TA mDA mSA AE:DA SA */
|
|
||||||
mesh_da = mppath->mpp;
|
mesh_da = mppath->mpp;
|
||||||
is_mesh_mcast = 0;
|
else if (mpath)
|
||||||
} else if (mpath) {
|
|
||||||
mesh_da = mpath->dst;
|
mesh_da = mpath->dst;
|
||||||
is_mesh_mcast = 0;
|
rcu_read_unlock();
|
||||||
} else {
|
|
||||||
/* DA TA mSA AE:SA */
|
|
||||||
mesh_da = bcast;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
|
||||||
mesh_da, sdata->vif.addr);
|
mesh_da, sdata->vif.addr);
|
||||||
rcu_read_unlock();
|
if (is_multicast_ether_addr(mesh_da))
|
||||||
if (is_mesh_mcast)
|
/* DA TA mSA AE:SA */
|
||||||
meshhdrlen =
|
meshhdrlen =
|
||||||
ieee80211_new_mesh_header(&mesh_hdr,
|
ieee80211_new_mesh_header(&mesh_hdr,
|
||||||
sdata,
|
sdata,
|
||||||
skb->data + ETH_ALEN,
|
skb->data + ETH_ALEN,
|
||||||
NULL);
|
NULL);
|
||||||
else
|
else
|
||||||
|
/* RA TA mDA mSA AE:DA SA */
|
||||||
meshhdrlen =
|
meshhdrlen =
|
||||||
ieee80211_new_mesh_header(&mesh_hdr,
|
ieee80211_new_mesh_header(&mesh_hdr,
|
||||||
sdata,
|
sdata,
|
||||||
|
|
|
@ -1171,8 +1171,10 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u,
|
||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
svc->stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats);
|
svc->stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats);
|
||||||
if (!svc->stats.cpustats)
|
if (!svc->stats.cpustats) {
|
||||||
|
ret = -ENOMEM;
|
||||||
goto out_err;
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* I'm the first user of the service */
|
/* I'm the first user of the service */
|
||||||
atomic_set(&svc->usecnt, 0);
|
atomic_set(&svc->usecnt, 0);
|
||||||
|
|
|
@ -249,12 +249,15 @@ static void death_by_event(unsigned long ul_conntrack)
|
||||||
{
|
{
|
||||||
struct nf_conn *ct = (void *)ul_conntrack;
|
struct nf_conn *ct = (void *)ul_conntrack;
|
||||||
struct net *net = nf_ct_net(ct);
|
struct net *net = nf_ct_net(ct);
|
||||||
|
struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
|
||||||
|
|
||||||
|
BUG_ON(ecache == NULL);
|
||||||
|
|
||||||
if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
|
if (nf_conntrack_event(IPCT_DESTROY, ct) < 0) {
|
||||||
/* bad luck, let's retry again */
|
/* bad luck, let's retry again */
|
||||||
ct->timeout.expires = jiffies +
|
ecache->timeout.expires = jiffies +
|
||||||
(random32() % net->ct.sysctl_events_retry_timeout);
|
(random32() % net->ct.sysctl_events_retry_timeout);
|
||||||
add_timer(&ct->timeout);
|
add_timer(&ecache->timeout);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* we've got the event delivered, now it's dying */
|
/* we've got the event delivered, now it's dying */
|
||||||
|
@ -268,6 +271,9 @@ static void death_by_event(unsigned long ul_conntrack)
|
||||||
void nf_ct_insert_dying_list(struct nf_conn *ct)
|
void nf_ct_insert_dying_list(struct nf_conn *ct)
|
||||||
{
|
{
|
||||||
struct net *net = nf_ct_net(ct);
|
struct net *net = nf_ct_net(ct);
|
||||||
|
struct nf_conntrack_ecache *ecache = nf_ct_ecache_find(ct);
|
||||||
|
|
||||||
|
BUG_ON(ecache == NULL);
|
||||||
|
|
||||||
/* add this conntrack to the dying list */
|
/* add this conntrack to the dying list */
|
||||||
spin_lock_bh(&nf_conntrack_lock);
|
spin_lock_bh(&nf_conntrack_lock);
|
||||||
|
@ -275,10 +281,10 @@ void nf_ct_insert_dying_list(struct nf_conn *ct)
|
||||||
&net->ct.dying);
|
&net->ct.dying);
|
||||||
spin_unlock_bh(&nf_conntrack_lock);
|
spin_unlock_bh(&nf_conntrack_lock);
|
||||||
/* set a new timer to retry event delivery */
|
/* set a new timer to retry event delivery */
|
||||||
setup_timer(&ct->timeout, death_by_event, (unsigned long)ct);
|
setup_timer(&ecache->timeout, death_by_event, (unsigned long)ct);
|
||||||
ct->timeout.expires = jiffies +
|
ecache->timeout.expires = jiffies +
|
||||||
(random32() % net->ct.sysctl_events_retry_timeout);
|
(random32() % net->ct.sysctl_events_retry_timeout);
|
||||||
add_timer(&ct->timeout);
|
add_timer(&ecache->timeout);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list);
|
EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list);
|
||||||
|
|
||||||
|
|
|
@ -2790,7 +2790,8 @@ static int __init ctnetlink_init(void)
|
||||||
goto err_unreg_subsys;
|
goto err_unreg_subsys;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (register_pernet_subsys(&ctnetlink_net_ops)) {
|
ret = register_pernet_subsys(&ctnetlink_net_ops);
|
||||||
|
if (ret < 0) {
|
||||||
pr_err("ctnetlink_init: cannot register pernet operations\n");
|
pr_err("ctnetlink_init: cannot register pernet operations\n");
|
||||||
goto err_unreg_exp_subsys;
|
goto err_unreg_exp_subsys;
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,7 +480,7 @@ __build_packet_message(struct nfulnl_instance *inst,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indev && skb_mac_header_was_set(skb)) {
|
if (indev && skb_mac_header_was_set(skb)) {
|
||||||
if (nla_put_be32(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
|
if (nla_put_be16(inst->skb, NFULA_HWTYPE, htons(skb->dev->type)) ||
|
||||||
nla_put_be16(inst->skb, NFULA_HWLEN,
|
nla_put_be16(inst->skb, NFULA_HWLEN,
|
||||||
htons(skb->dev->hard_header_len)) ||
|
htons(skb->dev->hard_header_len)) ||
|
||||||
nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len,
|
nla_put(inst->skb, NFULA_HWHEADER, skb->dev->hard_header_len,
|
||||||
|
@ -996,8 +996,10 @@ static int __init nfnetlink_log_init(void)
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
if (!proc_create("nfnetlink_log", 0440,
|
if (!proc_create("nfnetlink_log", 0440,
|
||||||
proc_net_netfilter, &nful_file_ops))
|
proc_net_netfilter, &nful_file_ops)) {
|
||||||
|
status = -ENOMEM;
|
||||||
goto cleanup_logger;
|
goto cleanup_logger;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
|
|
|
@ -1373,7 +1373,8 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
|
||||||
dst_pid = addr->nl_pid;
|
dst_pid = addr->nl_pid;
|
||||||
dst_group = ffs(addr->nl_groups);
|
dst_group = ffs(addr->nl_groups);
|
||||||
err = -EPERM;
|
err = -EPERM;
|
||||||
if (dst_group && !netlink_capable(sock, NL_NONROOT_SEND))
|
if ((dst_group || dst_pid) &&
|
||||||
|
!netlink_capable(sock, NL_NONROOT_SEND))
|
||||||
goto out;
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
dst_pid = nlk->dst_pid;
|
dst_pid = nlk->dst_pid;
|
||||||
|
@ -2147,6 +2148,7 @@ static void __init netlink_add_usersock_entry(void)
|
||||||
rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
|
rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners);
|
||||||
nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
|
nl_table[NETLINK_USERSOCK].module = THIS_MODULE;
|
||||||
nl_table[NETLINK_USERSOCK].registered = 1;
|
nl_table[NETLINK_USERSOCK].registered = 1;
|
||||||
|
nl_table[NETLINK_USERSOCK].nl_nonroot = NL_NONROOT_SEND;
|
||||||
|
|
||||||
netlink_table_ungrab();
|
netlink_table_ungrab();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1273,7 +1273,7 @@ static void __fanout_unlink(struct sock *sk, struct packet_sock *po)
|
||||||
spin_unlock(&f->lock);
|
spin_unlock(&f->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match_fanout_group(struct packet_type *ptype, struct sock * sk)
|
static bool match_fanout_group(struct packet_type *ptype, struct sock * sk)
|
||||||
{
|
{
|
||||||
if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout)
|
if (ptype->af_packet_priv == (void*)((struct packet_sock *)sk)->fanout)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1994,8 +1994,10 @@ int __xfrm_init_state(struct xfrm_state *x, bool init_replay)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
x->outer_mode = xfrm_get_mode(x->props.mode, family);
|
x->outer_mode = xfrm_get_mode(x->props.mode, family);
|
||||||
if (x->outer_mode == NULL)
|
if (x->outer_mode == NULL) {
|
||||||
|
err = -EPROTONOSUPPORT;
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (init_replay) {
|
if (init_replay) {
|
||||||
err = xfrm_init_replay(x);
|
err = xfrm_init_replay(x);
|
||||||
|
|
Loading…
Add table
Reference in a new issue