summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKanoj Sarcar <kanoj@engr.sgi.com>2000-05-11 20:59:13 +0000
committerKanoj Sarcar <kanoj@engr.sgi.com>2000-05-11 20:59:13 +0000
commite3b4abcb9607063735ea134eca6fad62f8147f20 (patch)
tree3cb2e5fa1795bfc2b2df6b0e72ce4b39e44f4ae0
parentaed9bea016318b0f4cd8b3ac9aae9cb0f78526ef (diff)
SMP FPU management: similar to what sparc does, no lazy fpu context
switching in SMP mode, use PF_USEDFPU to determine whether a program used the fpu in the last time quantum and so needs the fpu context to be saved during context switch.
-rw-r--r--arch/mips64/kernel/process.c11
-rw-r--r--arch/mips64/kernel/ptrace.c11
-rw-r--r--arch/mips64/kernel/signal.c9
-rw-r--r--arch/mips64/kernel/signal32.c10
-rw-r--r--arch/mips64/kernel/traps.c10
-rw-r--r--include/asm-mips64/processor.h8
-rw-r--r--include/asm-mips64/system.h17
7 files changed, 61 insertions, 15 deletions
diff --git a/arch/mips64/kernel/process.c b/arch/mips64/kernel/process.c
index d6d8b7435..22ce0ed6d 100644
--- a/arch/mips64/kernel/process.c
+++ b/arch/mips64/kernel/process.c
@@ -7,6 +7,7 @@
* Copyright (C) 1994 - 1999 by Ralf Baechle and others.
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -52,20 +53,20 @@ asmlinkage void ret_from_fork(void);
void exit_thread(void)
{
/* Forget lazy fpu state */
- if (last_task_used_math == current) {
+ if (IS_FPU_OWNER()) {
set_cp0_status(ST0_CU1, ST0_CU1);
__asm__ __volatile__("cfc1\t$0,$31");
- last_task_used_math = NULL;
+ CLEAR_FPU_OWNER();
}
}
void flush_thread(void)
{
/* Forget lazy fpu state */
- if (last_task_used_math == current) {
+ if (IS_FPU_OWNER()) {
set_cp0_status(ST0_CU1, ST0_CU1);
__asm__ __volatile__("cfc1\t$0,$31");
- last_task_used_math = NULL;
+ CLEAR_FPU_OWNER();
}
}
@@ -77,7 +78,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
- if (last_task_used_math == current) {
+ if (IS_FPU_OWNER()) {
save_fp(p);
}
/* set up new TSS. */
diff --git a/arch/mips64/kernel/ptrace.c b/arch/mips64/kernel/ptrace.c
index 0301a66a3..b79a61f0e 100644
--- a/arch/mips64/kernel/ptrace.c
+++ b/arch/mips64/kernel/ptrace.c
@@ -13,6 +13,7 @@
* At this time Linux/MIPS64 only supports syscall tracing, even for 32-bit
* binaries.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -36,7 +37,6 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
struct task_struct *child;
unsigned long flags;
int ret;
- extern void save_fp(void*);
lock_kernel();
#if 0
@@ -132,12 +132,14 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
break;
case FPR_BASE ... FPR_BASE + 31:
if (child->used_math) {
+#ifndef CONFIG_SMP
if (last_task_used_math == child) {
set_cp0_status(ST0_CU1, ST0_CU1);
save_fp(child);
set_cp0_status(ST0_CU1, 0);
last_task_used_math = NULL;
}
+#endif
tmp = child->thread.fpu.hard.fp_regs[addr - 32];
} else {
tmp = -EIO;
@@ -199,6 +201,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
case FPR_BASE ... FPR_BASE + 31: {
unsigned long *fregs;
if (child->used_math) {
+#ifndef CONFIG_SMP
if (last_task_used_math == child) {
set_cp0_status(ST0_CU1, ST0_CU1);
save_fp(child);
@@ -206,6 +209,7 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
last_task_used_math = NULL;
regs->cp0_status &= ~ST0_CU1;
}
+#endif
} else {
/* FP not yet used */
memset(&child->thread.fpu.hard, ~0,
@@ -293,7 +297,6 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
struct task_struct *child;
unsigned long flags;
int ret;
- extern void save_fp(void*);
lock_kernel();
#if 0
@@ -389,12 +392,14 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
break;
case FPR_BASE ... FPR_BASE + 31:
if (child->used_math) {
+#ifndef CONFIG_SMP
if (last_task_used_math == child) {
set_cp0_status(ST0_CU1, ST0_CU1);
save_fp(child);
set_cp0_status(ST0_CU1, 0);
last_task_used_math = NULL;
}
+#endif
tmp = child->thread.fpu.hard.fp_regs[addr - 32];
} else {
tmp = -EIO;
@@ -456,6 +461,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
case FPR_BASE ... FPR_BASE + 31: {
unsigned long *fregs;
if (child->used_math) {
+#ifndef CONFIG_SMP
if (last_task_used_math == child) {
set_cp0_status(ST0_CU1, ST0_CU1);
save_fp(child);
@@ -463,6 +469,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
last_task_used_math = NULL;
regs->cp0_status &= ~ST0_CU1;
}
+#endif
} else {
/* FP not yet used */
memset(&child->thread.fpu.hard, ~0,
diff --git a/arch/mips64/kernel/signal.c b/arch/mips64/kernel/signal.c
index 40a727831..7f644a437 100644
--- a/arch/mips64/kernel/signal.c
+++ b/arch/mips64/kernel/signal.c
@@ -26,6 +26,7 @@
#include <asm/stackframe.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
+#include <asm/system.h>
#define DEBUG_SIG 0
@@ -209,8 +210,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
err |= __get_user(owned_fp, &sc->sc_ownedfp);
if (owned_fp) {
- if (current == last_task_used_math) {
- last_task_used_math = 0;
+ if (IS_FPU_OWNER()) {
+ CLEAR_FPU_OWNER();
regs->cp0_status &= ~ST0_CU1;
}
current->used_math = 1;
@@ -338,9 +339,9 @@ setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
if (current->used_math) { /* fp is active. */
- if (current == last_task_used_math) {
+ if (IS_FPU_OWNER()) {
lazy_fpu_switch(current, 0);
- last_task_used_math = NULL;
+ CLEAR_FPU_OWNER();
regs->cp0_status &= ~ST0_CU1;
}
err |= __put_user(1, &sc->sc_ownedfp);
diff --git a/arch/mips64/kernel/signal32.c b/arch/mips64/kernel/signal32.c
index 4addc707c..e33a69d5e 100644
--- a/arch/mips64/kernel/signal32.c
+++ b/arch/mips64/kernel/signal32.c
@@ -8,6 +8,7 @@
* Copyright (C) 1994 - 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
+#include <linux/config.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
@@ -25,6 +26,7 @@
#include <asm/stackframe.h>
#include <asm/uaccess.h>
#include <asm/ucontext.h>
+#include <asm/system.h>
#define DEBUG_SIG 0
@@ -239,8 +241,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
err |= __get_user(owned_fp, &sc->sc_ownedfp);
if (owned_fp) {
- if (current == last_task_used_math) {
- last_task_used_math = 0;
+ if (IS_FPU_OWNER()) {
+ CLEAR_FPU_OWNER();
regs->cp0_status &= ~ST0_CU1;
}
current->used_math = 1;
@@ -373,9 +375,9 @@ setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
if (current->used_math) { /* fp is active. */
- if (current == last_task_used_math) {
+ if (IS_FPU_OWNER()) {
lazy_fpu_switch(current, 0);
- last_task_used_math = NULL;
+ CLEAR_FPU_OWNER();
regs->cp0_status &= ~ST0_CU1;
}
err |= __put_user(1, &sc->sc_ownedfp);
diff --git a/arch/mips64/kernel/traps.c b/arch/mips64/kernel/traps.c
index 9f97fb0d8..fa58017cf 100644
--- a/arch/mips64/kernel/traps.c
+++ b/arch/mips64/kernel/traps.c
@@ -346,6 +346,7 @@ void do_cpu(struct pt_regs *regs)
goto bad_cid;
regs->cp0_status |= ST0_CU1;
+#ifndef CONFIG_SMP
if (last_task_used_math == current)
return;
@@ -357,6 +358,15 @@ void do_cpu(struct pt_regs *regs)
current->used_math = 1;
}
last_task_used_math = current;
+#else
+ if (current->used_math) {
+ lazy_fpu_switch(0, current);
+ } else {
+ init_fpu();
+ current->used_math = 1;
+ }
+ current->flags |= PF_USEDFPU;
+#endif
return;
bad_cid:
diff --git a/include/asm-mips64/processor.h b/include/asm-mips64/processor.h
index 0532dbf0c..1932672e7 100644
--- a/include/asm-mips64/processor.h
+++ b/include/asm-mips64/processor.h
@@ -87,6 +87,14 @@ extern int EISA_bus;
/* Lazy FPU handling on uni-processor */
extern struct task_struct *last_task_used_math;
+#ifndef CONFIG_SMP
+#define IS_FPU_OWNER() (last_task_used_math == current)
+#define CLEAR_FPU_OWNER() last_task_used_math = NULL;
+#else
+#define IS_FPU_OWNER() (current->flags & PF_USEDFPU)
+#define CLEAR_FPU_OWNER() current->flags &= ~PF_USEDFPU;
+#endif
+
/*
* User space process size: 1TB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing. TASK_SIZE
diff --git a/include/asm-mips64/system.h b/include/asm-mips64/system.h
index 7f518a8b8..3592b3821 100644
--- a/include/asm-mips64/system.h
+++ b/include/asm-mips64/system.h
@@ -169,8 +169,25 @@ extern asmlinkage void *resume(void *last, void *next);
#endif /* !defined (_LANGUAGE_ASSEMBLY) */
#define prepare_to_switch() do { } while(0)
+
+extern asmlinkage void lazy_fpu_switch(void *, void *);
+extern asmlinkage void init_fpu(void);
+extern asmlinkage void save_fp(void *);
+
+#ifdef CONFIG_SMP
+#define SWITCH_DO_LAZY_FPU \
+ if (prev->flags & PF_USEDFPU) { \
+ lazy_fpu_switch(prev, 0); \
+ set_cp0_status(ST0_CU1, ~ST0_CU1); \
+ prev->flags &= ~PF_USEDFPU; \
+ }
+#else /* CONFIG_SMP */
+#define SWITCH_DO_LAZY_FPU do { } while(0)
+#endif /* CONFIG_SMP */
+
#define switch_to(prev,next,last) \
do { \
+ SWITCH_DO_LAZY_FPU; \
(last) = resume(prev, next); \
} while(0)