Commit b6254ced authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/signal: Don't manage floating point regs when no FPU

There is no point in copying floating point regs when there
is no FPU and MATH_EMULATION is not selected.

Create a new CONFIG_PPC_FPU_REGS bool that is selected by
CONFIG_MATH_EMULATION and CONFIG_PPC_FPU, and use it to
opt out everything related to fp_state in thread_struct.

The asm const used only by fpu.S are opted out with CONFIG_PPC_FPU
as fpu.S build is conditionnal to CONFIG_PPC_FPU.

The following app spends approx 8.1 seconds system time on an 8xx
without the patch, and 7.0 seconds with the patch (13.5% reduction).

On an 832x, it spends approx 2.6 seconds system time without
the patch and 2.1 seconds with the patch (19% reduction).

	void sigusr1(int sig) { }

	int main(int argc, char **argv)
	{
		int i = 100000;

		signal(SIGUSR1, sigusr1);
		for (;i--;)
			raise(SIGUSR1);
		exit(0);
	}
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@csgroup.eu>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/7569070083e6cd5b279bb5023da601aba3c06f3c.1597770847.git.christophe.leroy@csgroup.eu
parent 4d90eb97
...@@ -422,6 +422,7 @@ config HUGETLB_PAGE_SIZE_VARIABLE ...@@ -422,6 +422,7 @@ config HUGETLB_PAGE_SIZE_VARIABLE
config MATH_EMULATION config MATH_EMULATION
bool "Math emulation" bool "Math emulation"
depends on 4xx || PPC_8xx || PPC_MPC832x || BOOKE depends on 4xx || PPC_8xx || PPC_MPC832x || BOOKE
select PPC_FPU_REGS
help help
Some PowerPC chips designed for embedded applications do not have Some PowerPC chips designed for embedded applications do not have
a floating-point unit and therefore do not implement the a floating-point unit and therefore do not implement the
......
...@@ -164,8 +164,10 @@ struct thread_struct { ...@@ -164,8 +164,10 @@ struct thread_struct {
#endif #endif
/* Debug Registers */ /* Debug Registers */
struct debug_reg debug; struct debug_reg debug;
#ifdef CONFIG_PPC_FPU_REGS
struct thread_fp_state fp_state; struct thread_fp_state fp_state;
struct thread_fp_state *fp_save_area; struct thread_fp_state *fp_save_area;
#endif
int fpexc_mode; /* floating-point exception mode */ int fpexc_mode; /* floating-point exception mode */
unsigned int align_ctl; /* alignment handling control */ unsigned int align_ctl; /* alignment handling control */
#ifdef CONFIG_HAVE_HW_BREAKPOINT #ifdef CONFIG_HAVE_HW_BREAKPOINT
......
...@@ -110,9 +110,11 @@ int main(void) ...@@ -110,9 +110,11 @@ int main(void)
#ifdef CONFIG_BOOKE #ifdef CONFIG_BOOKE
OFFSET(THREAD_NORMSAVES, thread_struct, normsave[0]); OFFSET(THREAD_NORMSAVES, thread_struct, normsave[0]);
#endif #endif
#ifdef CONFIG_PPC_FPU
OFFSET(THREAD_FPEXC_MODE, thread_struct, fpexc_mode); OFFSET(THREAD_FPEXC_MODE, thread_struct, fpexc_mode);
OFFSET(THREAD_FPSTATE, thread_struct, fp_state.fpr); OFFSET(THREAD_FPSTATE, thread_struct, fp_state.fpr);
OFFSET(THREAD_FPSAVEAREA, thread_struct, fp_save_area); OFFSET(THREAD_FPSAVEAREA, thread_struct, fp_save_area);
#endif
OFFSET(FPSTATE_FPSCR, thread_fp_state, fpscr); OFFSET(FPSTATE_FPSCR, thread_fp_state, fpscr);
OFFSET(THREAD_LOAD_FP, thread_struct, load_fp); OFFSET(THREAD_LOAD_FP, thread_struct, load_fp);
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
......
...@@ -1730,7 +1730,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, ...@@ -1730,7 +1730,9 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
p->thread.ptrace_bps[i] = NULL; p->thread.ptrace_bps[i] = NULL;
#endif #endif
#ifdef CONFIG_PPC_FPU_REGS
p->thread.fp_save_area = NULL; p->thread.fp_save_area = NULL;
#endif
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
p->thread.vr_save_area = NULL; p->thread.vr_save_area = NULL;
#endif #endif
...@@ -1855,8 +1857,10 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) ...@@ -1855,8 +1857,10 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
#endif #endif
current->thread.load_slb = 0; current->thread.load_slb = 0;
current->thread.load_fp = 0; current->thread.load_fp = 0;
#ifdef CONFIG_PPC_FPU_REGS
memset(&current->thread.fp_state, 0, sizeof(current->thread.fp_state)); memset(&current->thread.fp_state, 0, sizeof(current->thread.fp_state));
current->thread.fp_save_area = NULL; current->thread.fp_save_area = NULL;
#endif
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
memset(&current->thread.vr_state, 0, sizeof(current->thread.vr_state)); memset(&current->thread.vr_state, 0, sizeof(current->thread.vr_state));
current->thread.vr_state.vscr.u[3] = 0x00010000; /* Java mode disabled */ current->thread.vr_state.vscr.u[3] = 0x00010000; /* Java mode disabled */
......
...@@ -6,11 +6,11 @@ ...@@ -6,11 +6,11 @@
CFLAGS_ptrace-view.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' CFLAGS_ptrace-view.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
obj-y += ptrace.o ptrace-view.o obj-y += ptrace.o ptrace-view.o
obj-y += ptrace-fpu.o obj-$(CONFIG_PPC_FPU_REGS) += ptrace-fpu.o
obj-$(CONFIG_COMPAT) += ptrace32.o obj-$(CONFIG_COMPAT) += ptrace32.o
obj-$(CONFIG_VSX) += ptrace-vsx.o obj-$(CONFIG_VSX) += ptrace-vsx.o
ifneq ($(CONFIG_VSX),y) ifneq ($(CONFIG_VSX),y)
obj-y += ptrace-novsx.o obj-$(CONFIG_PPC_FPU_REGS) += ptrace-novsx.o
endif endif
obj-$(CONFIG_ALTIVEC) += ptrace-altivec.o obj-$(CONFIG_ALTIVEC) += ptrace-altivec.o
obj-$(CONFIG_SPE) += ptrace-spe.o obj-$(CONFIG_SPE) += ptrace-spe.o
......
...@@ -165,8 +165,22 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data); ...@@ -165,8 +165,22 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data);
extern const struct user_regset_view user_ppc_native_view; extern const struct user_regset_view user_ppc_native_view;
/* ptrace-fpu */ /* ptrace-fpu */
#ifdef CONFIG_PPC_FPU_REGS
int ptrace_get_fpr(struct task_struct *child, int index, unsigned long *data); int ptrace_get_fpr(struct task_struct *child, int index, unsigned long *data);
int ptrace_put_fpr(struct task_struct *child, int index, unsigned long data); int ptrace_put_fpr(struct task_struct *child, int index, unsigned long data);
#else
static inline int
ptrace_get_fpr(struct task_struct *child, int index, unsigned long *data)
{
return -EIO;
}
static inline int
ptrace_put_fpr(struct task_struct *child, int index, unsigned long data)
{
return -EIO;
}
#endif
/* ptrace-(no)adv */ /* ptrace-(no)adv */
void ppc_gethwdinfo(struct ppc_debug_info *dbginfo); void ppc_gethwdinfo(struct ppc_debug_info *dbginfo);
......
...@@ -521,11 +521,13 @@ static const struct user_regset native_regsets[] = { ...@@ -521,11 +521,13 @@ static const struct user_regset native_regsets[] = {
.size = sizeof(long), .align = sizeof(long), .size = sizeof(long), .align = sizeof(long),
.regset_get = gpr_get, .set = gpr_set .regset_get = gpr_get, .set = gpr_set
}, },
#ifdef CONFIG_PPC_FPU_REGS
[REGSET_FPR] = { [REGSET_FPR] = {
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG, .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
.size = sizeof(double), .align = sizeof(double), .size = sizeof(double), .align = sizeof(double),
.regset_get = fpr_get, .set = fpr_set .regset_get = fpr_get, .set = fpr_set
}, },
#endif
#ifdef CONFIG_ALTIVEC #ifdef CONFIG_ALTIVEC
[REGSET_VMX] = { [REGSET_VMX] = {
.core_note_type = NT_PPC_VMX, .n = 34, .core_note_type = NT_PPC_VMX, .n = 34,
......
...@@ -34,7 +34,7 @@ unsigned long copy_fpr_to_user(void __user *to, struct task_struct *task); ...@@ -34,7 +34,7 @@ unsigned long copy_fpr_to_user(void __user *to, struct task_struct *task);
unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task); unsigned long copy_ckfpr_to_user(void __user *to, struct task_struct *task);
unsigned long copy_fpr_from_user(struct task_struct *task, void __user *from); unsigned long copy_fpr_from_user(struct task_struct *task, void __user *from);
unsigned long copy_ckfpr_from_user(struct task_struct *task, void __user *from); unsigned long copy_ckfpr_from_user(struct task_struct *task, void __user *from);
#else #elif defined(CONFIG_PPC_FPU_REGS)
static inline unsigned long static inline unsigned long
copy_fpr_to_user(void __user *to, struct task_struct *task) copy_fpr_to_user(void __user *to, struct task_struct *task)
{ {
...@@ -63,6 +63,18 @@ copy_ckfpr_from_user(struct task_struct *task, void __user *from) ...@@ -63,6 +63,18 @@ copy_ckfpr_from_user(struct task_struct *task, void __user *from)
ELF_NFPREG * sizeof(double)); ELF_NFPREG * sizeof(double));
} }
#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
#else
static inline unsigned long
copy_fpr_to_user(void __user *to, struct task_struct *task)
{
return 0;
}
static inline unsigned long
copy_fpr_from_user(struct task_struct *task, void __user *from)
{
return 0;
}
#endif #endif
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
......
...@@ -814,7 +814,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -814,7 +814,9 @@ int handle_rt_signal32(struct ksignal *ksig, sigset_t *oldset,
} }
regs->link = tramp; regs->link = tramp;
#ifdef CONFIG_PPC_FPU_REGS
tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
#endif
/* create a stack frame for the caller of the handler */ /* create a stack frame for the caller of the handler */
newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16); newsp = ((unsigned long)rt_sf) - (__SIGNAL_FRAMESIZE + 16);
...@@ -1271,7 +1273,9 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset, ...@@ -1271,7 +1273,9 @@ int handle_signal32(struct ksignal *ksig, sigset_t *oldset,
regs->link = tramp; regs->link = tramp;
#ifdef CONFIG_PPC_FPU_REGS
tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */ tsk->thread.fp_state.fpscr = 0; /* turn off all fp exceptions */
#endif
/* create a stack frame for the caller of the handler */ /* create a stack frame for the caller of the handler */
newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE; newsp = ((unsigned long)frame) - __SIGNAL_FRAMESIZE;
......
...@@ -1190,7 +1190,9 @@ static void parse_fpe(struct pt_regs *regs) ...@@ -1190,7 +1190,9 @@ static void parse_fpe(struct pt_regs *regs)
flush_fp_to_thread(current); flush_fp_to_thread(current);
#ifdef CONFIG_PPC_FPU_REGS
code = __parse_fpscr(current->thread.fp_state.fpscr); code = __parse_fpscr(current->thread.fp_state.fpscr);
#endif
_exception(SIGFPE, regs, code, regs->nip); _exception(SIGFPE, regs, code, regs->nip);
} }
......
...@@ -218,9 +218,13 @@ config PPC_E500MC ...@@ -218,9 +218,13 @@ config PPC_E500MC
such as e5500/e6500), and must be disabled for running on such as e5500/e6500), and must be disabled for running on
e500v1 or e500v2. e500v1 or e500v2.
config PPC_FPU_REGS
bool
config PPC_FPU config PPC_FPU
bool bool
default y if PPC64 default y if PPC64
select PPC_FPU_REGS
config FSL_EMB_PERFMON config FSL_EMB_PERFMON
bool "Freescale Embedded Perfmon" bool "Freescale Embedded Perfmon"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment