From e3b4abcb9607063735ea134eca6fad62f8147f20 Mon Sep 17 00:00:00 2001 From: Kanoj Sarcar Date: Thu, 11 May 2000 20:59:13 +0000 Subject: 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. --- arch/mips64/kernel/process.c | 11 ++++++----- arch/mips64/kernel/ptrace.c | 11 +++++++++-- arch/mips64/kernel/signal.c | 9 +++++---- arch/mips64/kernel/signal32.c | 10 ++++++---- arch/mips64/kernel/traps.c | 10 ++++++++++ include/asm-mips64/processor.h | 8 ++++++++ include/asm-mips64/system.h | 17 +++++++++++++++++ 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 #include #include #include @@ -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 #include #include #include @@ -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 #include #include +#include #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 #include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #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) -- cgit v1.2.3