From e04582b7bc70b40c57287cdc24f81964ee88f565 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Mon, 9 Oct 2006 00:10:01 +0900 Subject: [PATCH] [MIPS] Make sure cpu_has_fpu is used only in atomic context Make sure cpu_has_fpu (which uses smp_processor_id()) is used only in atomic context. Signed-off-by: Atsushi Nemoto Signed-off-by: Ralf Baechle --- arch/mips/kernel/proc.c | 2 +- arch/mips/kernel/process.c | 2 +- arch/mips/kernel/ptrace.c | 18 ++++++++++-------- arch/mips/kernel/ptrace32.c | 3 ++- arch/mips/kernel/traps.c | 16 +++++++++------- arch/mips/math-emu/cp1emu.c | 7 +++---- include/asm-mips/fpu.h | 6 ++++-- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 46ee5a68ab13..4ed37ba19731 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c @@ -107,7 +107,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "processor\t\t: %ld\n", n); sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", - cpu_has_fpu ? " FPU V%d.%d" : ""); + cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : ""); seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ? cpu_data[n].cputype : CPU_UNKNOWN], (version >> 4) & 0x0f, version & 0x0f, diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 045d987bc683..9f307eb1a31e 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -115,7 +115,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) status |= KU_USER; regs->cp0_status = status; clear_used_math(); - lose_fpu(); + clear_fpu_owner(); if (cpu_has_dsp) __init_dsp(); regs->cp0_epc = pc; diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 362d1728e531..258d74fd0b63 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -106,6 +106,7 @@ int ptrace_setregs (struct task_struct *child, __s64 __user *data) int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) { int i; + unsigned int tmp; if (!access_ok(VERIFY_WRITE, data, 33 * 8)) return -EIO; @@ -121,10 +122,10 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) __put_user (child->thread.fpu.fcr31, data + 64); + preempt_disable(); if (cpu_has_fpu) { - unsigned int flags, tmp; + unsigned int flags; - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); @@ -138,11 +139,11 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data) __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp)); write_c0_status(flags); } - preempt_enable(); - __put_user (tmp, data + 65); } else { - __put_user ((__u32) 0, data + 65); + tmp = 0; } + preempt_enable(); + __put_user (tmp, data + 65); return 0; } @@ -245,16 +246,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) unsigned int mtflags; #endif /* CONFIG_MIPS_MT_SMTC */ - if (!cpu_has_fpu) + preempt_disable(); + if (!cpu_has_fpu) { + preempt_enable(); break; + } #ifdef CONFIG_MIPS_MT_SMTC /* Read-modify-write of Status must be atomic */ local_irq_save(irqflags); mtflags = dmt(); #endif /* CONFIG_MIPS_MT_SMTC */ - - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index f40ecd8be05f..d9a39c169450 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -175,7 +175,9 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) unsigned int mtflags; #endif /* CONFIG_MIPS_MT_SMTC */ + preempt_disable(); if (!cpu_has_fpu) { + preempt_enable(); tmp = 0; break; } @@ -186,7 +188,6 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) mtflags = dmt(); #endif /* CONFIG_MIPS_MT_SMTC */ - preempt_disable(); if (cpu_has_mipsmt) { unsigned int vpflags = dvpe(); flags = read_c0_status(); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index b7292a56d4cd..cce8313ec27d 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -66,7 +66,7 @@ extern asmlinkage void handle_mcheck(void); extern asmlinkage void handle_reserved(void); extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, - struct mips_fpu_struct *ctx); + struct mips_fpu_struct *ctx, int has_fpu); void (*board_be_init)(void); int (*board_be_handler)(struct pt_regs *regs, int is_fixup); @@ -641,7 +641,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_enable(); /* Run the emulator */ - sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu); + sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); preempt_disable(); @@ -791,11 +791,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) set_used_math(); } - preempt_enable(); - - if (!cpu_has_fpu) { - int sig = fpu_emulator_cop1Handler(regs, - ¤t->thread.fpu); + if (cpu_has_fpu) { + preempt_enable(); + } else { + int sig; + preempt_enable(); + sig = fpu_emulator_cop1Handler(regs, + ¤t->thread.fpu, 0); if (sig) force_sig(sig, current); #ifdef CONFIG_MIPS_MT_FPAFF diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 3f0d5d26d506..80531b35cd61 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -38,8 +38,6 @@ #include #include -#include -#include #include #include #include @@ -1233,7 +1231,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return 0; } -int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx) +int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, + int has_fpu) { unsigned long oldepc, prevepc; mips_instruction insn; @@ -1263,7 +1262,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx) ieee754_csr.rm = mips_rm[ieee754_csr.rm]; } - if (cpu_has_fpu) + if (has_fpu) break; if (sig) break; diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h index 58c561a9ec6b..efef843b93f0 100644 --- a/include/asm-mips/fpu.h +++ b/include/asm-mips/fpu.h @@ -134,9 +134,11 @@ static inline void restore_fp(struct task_struct *tsk) static inline fpureg_t *get_fpu_regs(struct task_struct *tsk) { - if (cpu_has_fpu) { - if ((tsk == current) && __is_fpu_owner()) + if (tsk == current) { + preempt_disable(); + if (is_fpu_owner()) _save_fp(current); + preempt_enable(); } return tsk->thread.fpu.fpr;