Procházet zdrojové kódy

[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 <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Atsushi Nemoto před 18 roky
rodič
revize
e04582b7bc

+ 1 - 1
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);
 	seq_printf(m, "processor\t\t: %ld\n", n);
 	sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\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 ?
 	seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ?
 	                            cpu_data[n].cputype : CPU_UNKNOWN],
 	                            cpu_data[n].cputype : CPU_UNKNOWN],
 	                           (version >> 4) & 0x0f, version & 0x0f,
 	                           (version >> 4) & 0x0f, version & 0x0f,

+ 1 - 1
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;
 	status |= KU_USER;
 	regs->cp0_status = status;
 	regs->cp0_status = status;
 	clear_used_math();
 	clear_used_math();
-	lose_fpu();
+	clear_fpu_owner();
 	if (cpu_has_dsp)
 	if (cpu_has_dsp)
 		__init_dsp();
 		__init_dsp();
 	regs->cp0_epc = pc;
 	regs->cp0_epc = pc;

+ 10 - 8
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 ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
 {
 {
 	int i;
 	int i;
+	unsigned int tmp;
 
 
 	if (!access_ok(VERIFY_WRITE, data, 33 * 8))
 	if (!access_ok(VERIFY_WRITE, data, 33 * 8))
 		return -EIO;
 		return -EIO;
@@ -121,10 +122,10 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
 
 
 	__put_user (child->thread.fpu.fcr31, data + 64);
 	__put_user (child->thread.fpu.fcr31, data + 64);
 
 
+	preempt_disable();
 	if (cpu_has_fpu) {
 	if (cpu_has_fpu) {
-		unsigned int flags, tmp;
+		unsigned int flags;
 
 
-		preempt_disable();
 		if (cpu_has_mipsmt) {
 		if (cpu_has_mipsmt) {
 			unsigned int vpflags = dvpe();
 			unsigned int vpflags = dvpe();
 			flags = read_c0_status();
 			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));
 			__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
 			write_c0_status(flags);
 			write_c0_status(flags);
 		}
 		}
-		preempt_enable();
-		__put_user (tmp, data + 65);
 	} else {
 	} else {
-		__put_user ((__u32) 0, data + 65);
+		tmp = 0;
 	}
 	}
+	preempt_enable();
+	__put_user (tmp, data + 65);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -245,16 +246,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 			unsigned int mtflags;
 			unsigned int mtflags;
 #endif /* CONFIG_MIPS_MT_SMTC */
 #endif /* CONFIG_MIPS_MT_SMTC */
 
 
-			if (!cpu_has_fpu)
+			preempt_disable();
+			if (!cpu_has_fpu) {
+				preempt_enable();
 				break;
 				break;
+			}
 
 
 #ifdef CONFIG_MIPS_MT_SMTC
 #ifdef CONFIG_MIPS_MT_SMTC
 			/* Read-modify-write of Status must be atomic */
 			/* Read-modify-write of Status must be atomic */
 			local_irq_save(irqflags);
 			local_irq_save(irqflags);
 			mtflags = dmt();
 			mtflags = dmt();
 #endif /* CONFIG_MIPS_MT_SMTC */
 #endif /* CONFIG_MIPS_MT_SMTC */
-
-			preempt_disable();
 			if (cpu_has_mipsmt) {
 			if (cpu_has_mipsmt) {
 				unsigned int vpflags = dvpe();
 				unsigned int vpflags = dvpe();
 				flags = read_c0_status();
 				flags = read_c0_status();

+ 2 - 1
arch/mips/kernel/ptrace32.c

@@ -175,7 +175,9 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
 			unsigned int mtflags;
 			unsigned int mtflags;
 #endif /* CONFIG_MIPS_MT_SMTC */
 #endif /* CONFIG_MIPS_MT_SMTC */
 
 
+			preempt_disable();
 			if (!cpu_has_fpu) {
 			if (!cpu_has_fpu) {
+				preempt_enable();
 				tmp = 0;
 				tmp = 0;
 				break;
 				break;
 			}
 			}
@@ -186,7 +188,6 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
 			mtflags = dmt();
 			mtflags = dmt();
 #endif /* CONFIG_MIPS_MT_SMTC */
 #endif /* CONFIG_MIPS_MT_SMTC */
 
 
-			preempt_disable();
 			if (cpu_has_mipsmt) {
 			if (cpu_has_mipsmt) {
 				unsigned int vpflags = dvpe();
 				unsigned int vpflags = dvpe();
 				flags = read_c0_status();
 				flags = read_c0_status();

+ 9 - 7
arch/mips/kernel/traps.c

@@ -66,7 +66,7 @@ extern asmlinkage void handle_mcheck(void);
 extern asmlinkage void handle_reserved(void);
 extern asmlinkage void handle_reserved(void);
 
 
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
 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);
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
 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();
 		preempt_enable();
 
 
 		/* Run the emulator */
 		/* Run the emulator */
-		sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu);
+		sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu, 1);
 
 
 		preempt_disable();
 		preempt_disable();
 
 
@@ -791,11 +791,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 			set_used_math();
 			set_used_math();
 		}
 		}
 
 
-		preempt_enable();
-
-		if (!cpu_has_fpu) {
-			int sig = fpu_emulator_cop1Handler(regs,
-						&current->thread.fpu);
+		if (cpu_has_fpu) {
+			preempt_enable();
+		} else {
+			int sig;
+			preempt_enable();
+			sig = fpu_emulator_cop1Handler(regs,
+						&current->thread.fpu, 0);
 			if (sig)
 			if (sig)
 				force_sig(sig, current);
 				force_sig(sig, current);
 #ifdef CONFIG_MIPS_MT_FPAFF
 #ifdef CONFIG_MIPS_MT_FPAFF

+ 3 - 4
arch/mips/math-emu/cp1emu.c

@@ -38,8 +38,6 @@
 
 
 #include <asm/inst.h>
 #include <asm/inst.h>
 #include <asm/bootinfo.h>
 #include <asm/bootinfo.h>
-#include <asm/cpu.h>
-#include <asm/cpu-features.h>
 #include <asm/processor.h>
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/ptrace.h>
 #include <asm/signal.h>
 #include <asm/signal.h>
@@ -1233,7 +1231,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 	return 0;
 	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;
 	unsigned long oldepc, prevepc;
 	mips_instruction insn;
 	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];
 			ieee754_csr.rm = mips_rm[ieee754_csr.rm];
 		}
 		}
 
 
-		if (cpu_has_fpu)
+		if (has_fpu)
 			break;
 			break;
 		if (sig)
 		if (sig)
 			break;
 			break;

+ 4 - 2
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)
 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);
 			_save_fp(current);
+		preempt_enable();
 	}
 	}
 
 
 	return tsk->thread.fpu.fpr;
 	return tsk->thread.fpu.fpr;