Subject: Re: Toshiba TX3927 board boot problem.

From: Atsushi Nemoto <[email-masked]>
Date: Fri, 26 Oct 2001 22:58:06 +0900 (JST)

>>>>> On Fri, 26 Oct 2001 17:49:26 +0800, 8route <[email-masked]> said:
ajob4me>   I'm working on Toshiba TX3927 RISC Processor Reference
ajob4me> board.During development I met a problem.Can someone give me
ajob4me> some good suggestions?
...
ajob4me> and the reset switch on the TX3927 board cann't work anymore.

I have seen TX39 dead on "cfc1" insturuction if STATUS.CU1 bit
enabled.  Such codes were in arch/mips/kernel/process.c.

---
Atsushi Nemoto

---

From: Atsushi Nemoto <[email-masked]>
Date: Mon, 29 Oct 2001 16:02:25 +0900 (JST)

>>>>> On Fri, 26 Oct 2001 22:58:06 +0900 (JST), Atsushi Nemoto <[email-masked]> said:
nemoto> I have seen TX39 dead on "cfc1" insturuction if STATUS.CU1 bit
nemoto> enabled.  Such codes were in arch/mips/kernel/process.c.

So, please apply this patch to CVS for TX39XX support.

I use CONFIG_CPU_TX39XX in this patch, but I suppose other FPU-less
CPUs may need this also.

Does anybody know how about on other CPUs?

diff -u linux-sgi-cvs/arch/mips/kernel/process.c linux.new/arch/mips/kernel/
--- linux-sgi-cvs/arch/mips/kernel/process.c	Mon Oct 22 10:29:56 2001
+++ linux.new/arch/mips/kernel/process.c	Mon Oct 29 15:49:37 2001
@@ -57,6 +57,12 @@
 {
 	/* Forget lazy fpu state */
 	if (last_task_used_math == current) {
+#ifdef CONFIG_CPU_TX39XX
+		if (!(mips_cpu.options & MIPS_CPU_FPU)) {
+			last_task_used_math = NULL;
+			return;
+		}
+#endif
 		set_cp0_status(ST0_CU1);
 		__asm__ __volatile__("cfc1\t$0,$31");
 		last_task_used_math = NULL;
@@ -67,6 +73,12 @@
 {
 	/* Forget lazy fpu state */
 	if (last_task_used_math == current) {
+#ifdef CONFIG_CPU_TX39XX
+		if (!(mips_cpu.options & MIPS_CPU_FPU)) {
+			last_task_used_math = NULL;
+			return;
+		}
+#endif
 		set_cp0_status(ST0_CU1);
 		__asm__ __volatile__("cfc1\t$0,$31");
 		last_task_used_math = NULL;
---
Atsushi Nemoto

---

From: Carsten Langgaard <[email-masked]>
Date: Mon, 29 Oct 2001 09:32:14 +0100

This doesn't look right, you still need to enable the CU1 bit in the status register to let the FP
emulator kick-in.
FPU-less CPUs should take a coprocessor unusable exception on any floating-point instructions.
I have been running this on several FPU-less CPUs, and it works fine for me.

Actually there is a problem with this code on CPUs, which have a FPU. The problem is that a lot of
CPUs have a CP0 hazard of 4 nops, between setting the CU1 bit in the status register and executing
the first floating point instruction thereafter. It probably only a performance issue, because if
the setting of CU1 hasn't taken effect yet, then we get a coprocessor unusable exception and the
the exception handler will also set the CU1 bit.

/Carsten

--
_    _ ____  ___   Carsten Langgaard   Mailto:[email-masked]
|\  /|||___)(___   MIPS Denmark        Direct: +45 4486 5527
| \/ |||    ____)  Lautrupvang 4B      Switch: +45 4486 5555
  TECHNOLOGIES     2750 Ballerup       Fax...: +45 4486 5556
                   Denmark             http://www.mips.com

---

From: Alice Hennessy <[email-masked]>
Date: Mon, 29 Oct 2001 16:17:23 -0800

> I have been running this on several FPU-less CPUs, and it works fine for me.

Maybe the FPU-less CPUs you have been using define the CU1 bit as reserved
or is unused (ignore on write, zero on read)? The TX3927 actually allows the setting of the CU1 bit.
Have you seen
a case where you need to set the CU1 bit for the emulation to kick-in?   I would think that the CU1
bit should
never be set to one for FPU-less CPUs.

Alice

---

From: Ralf Baechle <[email-masked]>
Date: Tue, 30 Oct 2001 01:32:23 +0100

On Mon, Oct 29, 2001 at 04:17:23PM -0800, Alice Hennessy wrote:

> > This doesn't look right, you still need to enable the CU1 bit in the
> > status register to let the FP emulator kick-in.  FPU-less CPUs should
> > take a coprocessor unusable exception on any floating-point instructions.
> or is unused (ignore on write, zero on read)? The TX3927 actually allows
> the setting of the CU1 bit.  Have you seen a case where you need to set
> the CU1 bit for the emulation to kick-in?   I would think that the CU1
> bit should never be set to one for FPU-less CPUs.

There are subtle differences in how CUx bits for unimplemented coprocessors
are handled in the various processors.  MIPS32 and MIPS64 specifies the
behaviour as 0 on read, writes ignored; previous processors such as the
R4000 handled this differently and as a consequence a fp instruction on
a fpu-less r4000 class cpu may either throw a CU or a reserved instruction
exception.  To make things easier for everybody this is documented in the
R10000 user's manual ...

  Ralf

---

From: Alice Hennessy <[email-masked]>
Date: Mon, 29 Oct 2001 18:25:51 -0800

> exception.  To make things easier for everybody this is documented in the

So,  we should not set CU1 generically for FPU-less CPUs especially since a
known problem exists
for the tx3927?  Ie, qualify all setting of CU1 as follows:

if (mips_cpu.options & MIPS_CPU_FPU)
                   set_cp0_status(ST0_CU1);

Alice

---

From: Atsushi Nemoto <[email-masked]>
Date: Tue, 30 Oct 2001 12:14:03 +0900 (JST)

>>>>> On Mon, 29 Oct 2001 16:17:23 -0800, Alice Hennessy <[email-masked]> said:
ahennessy> I would think that the CU1 bit should never be set to one
ahennessy> for FPU-less CPUs.

I think so too.

Talking about TX3927, When I tried, TX3927 did NOT raise any exception
on cp1 instruction if CU1 bit enabled.  The CPU just locked there.  So
some workaround is necessary for TX3927.

---
Atsushi Nemoto

---

From: Carsten Langgaard <[email-masked]>
Date: Tue, 30 Oct 2001 09:20:04 +0100

> never be set to one for FPU-less CPUs.

You are right, you don't need to set the CU1 bit for the emulator to kick-in (you just need a
coprocessor unusable exception), sorry my mistake.
So generally I think we should use the check against a FPU present (mips_cpu.options & MIPS_CPU_FPU),
instead of the TX39XX specific fix.

---

From: Carsten Langgaard <[email-masked]>
Date: Tue, 30 Oct 2001 09:36:01 +0100

> if (mips_cpu.options & MIPS_CPU_FPU)

And while we are at it, could we handle the CP0 hazard of 4 nops, between setting
the CU1 bit in the status register and executing
the first floating point instruction, on CPU which got a FPU.

---

From: Ralf Baechle <[email-masked]>
Date: Tue, 30 Oct 2001 15:13:08 +0100

On Tue, Oct 30, 2001 at 09:36:01AM +0100, Carsten Langgaard wrote:

> And while we are at it, could we handle the CP0 hazard of 4 nops, between
> setting the CU1 bit in the status register and executing

Which CPUs actually need four nops?

Just working on a patch; I found a bunch more place where we were playing
with the CU1 bit.

  Ralf

---

From: Carsten Langgaard <[email-masked]>
Date: Tue, 30 Oct 2001 15:17:18 +0100

> Just working on a patch; I found a bunch more place where we were playing

The MIPS32 spec specify 4 nops.

---

From: Ralf Baechle <[email-masked]>
Date: Tue, 30 Oct 2001 15:55:33 +0100

On Tue, Oct 30, 2001 at 09:20:04AM +0100, Carsten Langgaard wrote:

> You are right, you don't need to set the CU1 bit for the emulator to kick-in
> (you just need a coprocessor unusable exception), sorry my mistake.
> So generally I think we should use the check against a FPU present
> (mips_cpu.options & MIPS_CPU_FPU), instead of the TX39XX specific fix.

So here is a preliminiary version of my patch.  Still untested and needs
to be applied to mips64 also.

  Ralf

Index: arch/mips/kernel/process.c
===================================================================
RCS file: /home/pub/cvs/linux/arch/mips/kernel/process.c,v
retrieving revision 1.31
diff -u -r1.31 process.c
--- arch/mips/kernel/process.c 2001/10/19 01:23:37 1.31  
+++ arch/mips/kernel/process.c 2001/10/30 14:46:30   
@@ -56,8 +56,8 @@
 void exit_thread(void)
 {
 	/* Forget lazy fpu state */
-	if (last_task_used_math == current) {
-		set_cp0_status(ST0_CU1);
+	if (last_task_used_math == current && mips_cpu.options & MIPS_CPU_FPU) {
+		__enable_fpu();
 		__asm__ __volatile__("cfc1\t$0,$31");
 		last_task_used_math = NULL;
 	}
@@ -66,8 +66,8 @@
 void flush_thread(void)
 {
 	/* Forget lazy fpu state */
-	if (last_task_used_math == current) {
-		set_cp0_status(ST0_CU1);
+	if (last_task_used_math == current && mips_cpu.options & MIPS_CPU_FPU) {
+		__enable_fpu();
 		__asm__ __volatile__("cfc1\t$0,$31");
 		last_task_used_math = NULL;
 	}
@@ -85,7 +85,7 @@
 
 	if (last_task_used_math == current)
 		if (mips_cpu.options & MIPS_CPU_FPU) {
-			set_cp0_status(ST0_CU1);
+			__enable_fpu();
 			save_fp(p);
 		}
 	/* set up new TSS. */
Index: arch/mips/kernel/ptrace.c
===================================================================
RCS file: /home/pub/cvs/linux/arch/mips/kernel/ptrace.c,v
retrieving revision 1.32
diff -u -r1.32 ptrace.c
--- arch/mips/kernel/ptrace.c 2001/10/19 01:23:37 1.32  
+++ arch/mips/kernel/ptrace.c 2001/10/30 14:46:30   
@@ -20,7 +20,6 @@
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 
-#include <asm/fp.h>
 #include <asm/mipsregs.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
@@ -126,9 +125,9 @@
 						child->thread.fpu.soft.regs;
 				} else 
 					if (last_task_used_math == child) {
-						enable_cp1();
+						__enable_fpu();
 						save_fp(child);
-						disable_cp1();
+						__disable_fpu();
 						last_task_used_math = NULL;
 						regs->cp0_status &= ~ST0_CU1;
 					}
@@ -174,8 +173,13 @@
 		case FPC_EIR: {	/* implementation / version register */
 			unsigned int flags;
 
+			if (!(mips_cpu.options & MIPS_CPU_FPU)) {
+				res = -EIO;
+				goto out;
+			}
+
 			__save_flags(flags);
-			enable_cp1();
+			__enable_fpu();
 			__asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
 			__restore_flags(flags);
 			break;
@@ -217,9 +221,9 @@
 						fregs = (unsigned long long *)
 						child->thread.fpu.soft.regs;
 					} else {
-						enable_cp1();
+						__enable_fpu();
 						save_fp(child);
-						disable_cp1();
+						__disable_fpu();
 						last_task_used_math = NULL;
 						regs->cp0_status &= ~ST0_CU1;
 					}
Index: arch/mips/kernel/signal.c
===================================================================
RCS file: /home/pub/cvs/linux/arch/mips/kernel/signal.c,v
retrieving revision 1.37
diff -u -r1.37 signal.c
--- arch/mips/kernel/signal.c 2001/10/19 01:23:37 1.37  
+++ arch/mips/kernel/signal.c 2001/10/30 14:46:30   
@@ -22,6 +22,7 @@
 
 #include <asm/asm.h>
 #include <asm/bitops.h>
+#include <asm/cpu.h>
 #include <asm/pgalloc.h>
 #include <asm/stackframe.h>
 #include <asm/uaccess.h>
@@ -355,7 +356,7 @@
 	err |= __put_user(owned_fp, &sc->sc_ownedfp);
 
 	if (current->used_math) {	/* fp is active.  */
-		set_cp0_status(ST0_CU1);
+		enable_fpu();
 		err |= save_fp_context(sc);
 		last_task_used_math = NULL;
 		regs->cp0_status &= ~ST0_CU1;
Index: arch/mips64/kernel/ptrace.c
===================================================================
RCS file: /home/pub/cvs/linux/arch/mips64/kernel/ptrace.c,v
retrieving revision 1.12
diff -u -r1.12 ptrace.c
--- arch/mips64/kernel/ptrace.c 2001/10/27 00:49:55 1.12  
+++ arch/mips64/kernel/ptrace.c 2001/10/30 14:46:33   
@@ -119,9 +119,9 @@
 
 #ifndef CONFIG_SMP
 				if (last_task_used_math == child) {
-					set_cp0_status(ST0_CU1);
+					__enable_fpu();
 					save_fp(child);
-					clear_cp0_status(ST0_CU1, 0);
+					__disable_fpu();
 					last_task_used_math = NULL;
 				}
 #endif
@@ -197,9 +197,9 @@
 			if (child->used_math) {
 #ifndef CONFIG_SMP
 				if (last_task_used_math == child) {
-					set_cp0_status(ST0_CU1);
+					__enable_fpu();
 					save_fp(child);
-					clear_cp0_status(ST0_CU1);
+					__disable_fpu(ST0_CU1);
 					last_task_used_math = NULL;
 					regs->cp0_status &= ~ST0_CU1;
 				}
Index: include/asm-mips/bootinfo.h
===================================================================
RCS file: /home/pub/cvs/linux/include/asm-mips/bootinfo.h,v
retrieving revision 1.37
diff -u -r1.37 bootinfo.h
--- include/asm-mips/bootinfo.h 2001/10/24 23:00:44 1.37  
+++ include/asm-mips/bootinfo.h 2001/10/30 14:46:46   
@@ -298,7 +298,6 @@
  * values in setup.c (or whereever suitable) so they are in
  * .data section
  */
-extern struct mips_cpu mips_cpu;
 extern unsigned long mips_machtype;
 extern unsigned long mips_machgroup;
 extern unsigned long mips_tlb_entries;
Index: include/asm-mips/cpu.h
===================================================================
RCS file: /home/pub/cvs/linux/include/asm-mips/cpu.h,v
retrieving revision 1.16
diff -u -r1.16 cpu.h
--- include/asm-mips/cpu.h 2001/10/26 21:28:47 1.16  
+++ include/asm-mips/cpu.h 2001/10/30 14:46:46   
@@ -111,6 +111,8 @@
 	struct cache_desc tcache;	/* Tertiary/split secondary cache */
 };
 
+extern struct mips_cpu mips_cpu;
+
 #endif
 
 /*
Index: include/asm-mips/fp.h
===================================================================
RCS file: fp.h
diff -N fp.h
--- include/asm-mips/fp.h Tue Oct 30 15:48:07 2001
+++ include/asm-mips/fp.h Tue May 5 22:32:27 1998
@@ -1,33 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1998 by Ralf Baechle
- */
-
-/*
- * Activate and deactive the floatingpoint accelerator.
- */
-#define enable_cp1()							\
-	__asm__ __volatile__(						\
-		".set\tpush\n\t"					\
-		".set\tnoat\n\t"					\
-		".set\treorder\n\t"					\
-		"mfc0\t$1,$12\n\t"					\
-		"or\t$1,%0\n\t"						\
-		"mtc0\t$1,$12\n\t"					\
-		".set\tpop"						\
-		: : "r" (ST0_CU1));
-
-#define disable_cp1()							\
-	__asm__ __volatile__(						\
-		".set\tpush\n\t"					\
-		".set\tnoat\n\t"					\
-		".set\treorder\n\t"					\
-		"mfc0\t$1,$12\n\t"					\
-		"or\t$1,%0\n\t"						\
-		"xor\t$1,%0\n\t"					\
-		"mtc0\t$1,$12\n\t"					\
-		".set\tpop"						\
-		: : "r" (ST0_CU1));
Index: include/asm-mips/mipsregs.h
===================================================================
RCS file: /home/pub/cvs/linux/include/asm-mips/mipsregs.h,v
retrieving revision 1.26
diff -u -r1.26 mipsregs.h
--- include/asm-mips/mipsregs.h 2001/10/27 00:49:55 1.26  
+++ include/asm-mips/mipsregs.h 2001/10/30 14:46:46   
@@ -148,12 +148,15 @@
  */
 #include <linux/config.h>
 #ifdef CONFIG_CPU_VR41XX
+
 #define PM_1K   0x00000000
 #define PM_4K   0x00001800
 #define PM_16K  0x00007800
 #define PM_64K  0x0001f800
 #define PM_256K 0x0007f800
+
 #else
+
 #define PM_4K   0x00000000
 #define PM_16K  0x00006000
 #define PM_64K  0x0001e000
@@ -161,6 +164,7 @@
 #define PM_1M   0x001fe000
 #define PM_4M   0x007fe000
 #define PM_16M  0x01ffe000
+
 #endif
 
 /*
@@ -175,75 +179,6 @@
 #define PL_16M  24
 
 /*
- * Macros to access the system control coprocessor
- */
-#define read_32bit_cp0_register(source)                         \
-({ int __res;                                                   \
-        __asm__ __volatile__(                                   \
-	".set\tpush\n\t"					\
-	".set\treorder\n\t"					\
-        "mfc0\t%0,"STR(source)"\n\t"                            \
-	".set\tpop"						\
-        : "=r" (__res));                                        \
-        __res;})
-
-#define read_32bit_cp0_set1_register(source)                    \
-({ int __res;                                                   \
-        __asm__ __volatile__(                                   \
-	".set\tpush\n\t"					\
-	".set\treorder\n\t"					\
-        "cfc0\t%0,"STR(source)"\n\t"                            \
-	".set\tpop"						\
-        : "=r" (__res));                                        \
-        __res;})
-
-/*
- * For now use this only with interrupts disabled!
- */
-#define read_64bit_cp0_register(source)                         \
-({ int __res;                                                   \
-        __asm__ __volatile__(                                   \
-        ".set\tmips3\n\t"                                       \
-        "dmfc0\t%0,"STR(source)"\n\t"                           \
-        ".set\tmips0"                                           \
-        : "=r" (__res));                                        \
-        __res;})
-
-#define write_32bit_cp0_register(register,value)                \
-        __asm__ __volatile__(                                   \
-        "mtc0\t%0,"STR(register)"\n\t"				\
-	"nop"							\
-        : : "r" (value));
-
-#define write_32bit_cp0_set1_register(register,value)           \
-        __asm__ __volatile__(                                   \
-        "ctc0\t%0,"STR(register)"\n\t"				\
-	"nop"							\
-        : : "r" (value));
-
-#define write_64bit_cp0_register(register,value)                \
-        __asm__ __volatile__(                                   \
-        ".set\tmips3\n\t"                                       \
-        "dmtc0\t%0,"STR(register)"\n\t"                         \
-        ".set\tmips0"                                           \
-        : : "r" (value))
-
-/* 
- * This should be changed when we get a compiler that support the MIPS32 ISA. 
- */
-#define read_mips32_cp0_config1()                               \
-({ int __res;                                                   \
-        __asm__ __volatile__(                                   \
-	".set\tnoreorder\n\t"                                   \
-	".set\tnoat\n\t"                                        \
-     	".word\t0x40018001\n\t"                                 \
-	"move\t%0,$1\n\t"                                       \
-	".set\tat\n\t"                                          \
-	".set\treorder"                                         \
-	:"=r" (__res));                                         \
-        __res;})
-
-/*
  * R4x00 interrupt enable / cause bits
  */
 #define IE_SW0          (1<< 8)
@@ -267,55 +202,6 @@
 #define C_IRQ4          (1<<14)
 #define C_IRQ5          (1<<15)
 
-#ifndef _LANGUAGE_ASSEMBLY
-/*
- * Manipulate the status register.
- * Mostly used to access the interrupt bits.
- */
-#define __BUILD_SET_CP0(name,register)				\
-extern inline unsigned int					\
-set_cp0_##name(unsigned int set)				\
-{								\
-	unsigned int res;					\
-								\
-	res = read_32bit_cp0_register(register);		\
-	res |= set;						\
-	write_32bit_cp0_register(register, res);		\
-								\
-	return res;						\
-}								\
-								\
-extern inline unsigned int					\
-clear_cp0_##name(unsigned int clear)				\
-{								\
-	unsigned int res;					\
-								\
-	res = read_32bit_cp0_register(register);		\
-	res &= ~clear;						\
-	write_32bit_cp0_register(register, res);		\
-								\
-	return res;						\
-}								\
-								\
-extern inline unsigned int					\
-change_cp0_##name(unsigned int change, unsigned int new)	\
-{								\
-	unsigned int res;					\
-								\
-	res = read_32bit_cp0_register(register);		\
-	res &= ~change;						\
-	res |= (new & change);					\
-	write_32bit_cp0_register(register, res);		\
-								\
-	return res;						\
-}
-
-__BUILD_SET_CP0(status,CP0_STATUS)
-__BUILD_SET_CP0(cause,CP0_CAUSE)
-__BUILD_SET_CP0(config,CP0_CONFIG)
-
-#endif /* defined (_LANGUAGE_ASSEMBLY) */
-
 /*
  * Bitfields in the R4xx0 cp0 status register
  */
@@ -547,5 +433,440 @@
 #define CEB_SUPERVISOR	4	/* Count events in supvervisor mode EXL = ERL = 0 */
 #define CEB_KERNEL	2	/* Count events in kernel mode EXL = ERL = 0 */
 #define CEB_EXL		1	/* Count events with EXL = 1, ERL = 0 */
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+/*
+ * Macros to access the system control coprocessor
+ */
+#define read_32bit_cp0_register(source)                         \
+({ int __res;                                                   \
+        __asm__ __volatile__(                                   \
+	".set\tpush\n\t"					\
+	".set\treorder\n\t"					\
+        "mfc0\t%0,"STR(source)"\n\t"                            \
+	".set\tpop"						\
+        : "=r" (__res));                                        \
+        __res;})
+
+#define read_32bit_cp0_set1_register(source)                    \
+({ int __res;                                                   \
+        __asm__ __volatile__(                                   \
+	".set\tpush\n\t"					\
+	".set\treorder\n\t"					\
+        "cfc0\t%0,"STR(source)"\n\t"                            \
+	".set\tpop"						\
+        : "=r" (__res));                                        \
+        __res;})
+
+/*
+ * For now use this only with interrupts disabled!
+ */
+#define read_64bit_cp0_register(source)                         \
+({ int __res;                                                   \
+        __asm__ __volatile__(                                   \
+        ".set\tmips3\n\t"                                       \
+        "dmfc0\t%0,"STR(source)"\n\t"                           \
+        ".set\tmips0"                                           \
+        : "=r" (__res));                                        \
+        __res;})
+
+#define write_32bit_cp0_register(register,value)                \
+        __asm__ __volatile__(                                   \
+        "mtc0\t%0,"STR(register)"\n\t"				\
+	"nop"							\
+        : : "r" (value));
+
+#define write_32bit_cp0_set1_register(register,value)           \
+        __asm__ __volatile__(                                   \
+        "ctc0\t%0,"STR(register)"\n\t"				\
+	"nop"							\
+        : : "r" (value));
+
+#define write_64bit_cp0_register(register,value)                \
+        __asm__ __volatile__(                                   \
+        ".set\tmips3\n\t"                                       \
+        "dmtc0\t%0,"STR(register)"\n\t"                         \
+        ".set\tmips0"                                           \
+        : : "r" (value))
+
+/* 
+ * This should be changed when we get a compiler that support the MIPS32 ISA. 
+ */
+#define read_mips32_cp0_config1()                               \
+({ int __res;                                                   \
+        __asm__ __volatile__(                                   \
+	".set\tnoreorder\n\t"                                   \
+	".set\tnoat\n\t"                                        \
+     	".word\t0x40018001\n\t"                                 \
+	"move\t%0,$1\n\t"                                       \
+	".set\tat\n\t"                                          \
+	".set\treorder"                                         \
+	:"=r" (__res));                                         \
+        __res;})
+
+/* TLB operations. */
+static inline void tlb_probe(void)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"tlbp\n\t"
+		".set pop");
+}
+
+static inline void tlb_read(void)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"tlbr\n\t"
+		".set pop");
+}
+
+static inline void tlb_write_indexed(void)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"tlbwi\n\t"
+		".set pop");
+}
+
+static inline void tlb_write_random(void)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"tlbwr\n\t"
+		".set pop");
+}
+
+/* Dealing with various CP0 mmu/cache related registers. */
+
+
+static inline unsigned long get_pagemask(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $5\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_pagemask(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $5\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/* CP0_ENTRYLO0 and CP0_ENTRYLO1 registers */
+static inline unsigned long get_entrylo0(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(	
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $2\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_entrylo0(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $2\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+static inline unsigned long get_entrylo1(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $3\n\t"
+		".set pop" : "=r" (val));
+
+	return val;
+}
+
+static inline void set_entrylo1(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $3\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/* CP0_ENTRYHI register */
+static inline unsigned long get_entryhi(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $10\n\t"
+		".set pop"
+		: "=r" (val));
+
+	return val;
+}
+
+static inline void set_entryhi(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $10\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/* CP0_INDEX register */
+static inline unsigned long get_index(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $0\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_index(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $0\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/* CP0_WIRED register */
+static inline unsigned long get_wired(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $6\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_wired(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $6\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/* CP0_STATUS register */
+static inline unsigned int get_status(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $12\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_status(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $12\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+static inline unsigned long get_info(void)
+{
+	unsigned long val;
+
+	__asm__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $7\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+/* CP0_TAGLO and CP0_TAGHI registers */
+static inline unsigned long get_taglo(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $28\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_taglo(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $28\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+static inline unsigned long get_taghi(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $29\n\t"
+		".set pop"
+		: "=r" (val));
+	return val;
+}
+
+static inline void set_taghi(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $29\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/* CP0_CONTEXT register */
+static inline unsigned long get_context(void)
+{
+	unsigned long val;
+
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mfc0 %0, $4\n\t"
+		".set pop"
+		: "=r" (val));
+
+	return val;
+}
+
+static inline void set_context(unsigned long val)
+{
+	__asm__ __volatile__(
+		".set push\n\t"
+		".set reorder\n\t"
+		"mtc0 %z0, $4\n\t"
+		".set pop"
+		: : "Jr" (val));
+}
+
+/*
+ * Manipulate the status register.
+ * Mostly used to access the interrupt bits.
+ */
+#define __BUILD_SET_CP0(name,register)				\
+static inline unsigned int					\
+set_cp0_##name(unsigned int set)				\
+{								\
+	unsigned int res;					\
+								\
+	res = read_32bit_cp0_register(register);		\
+	res |= set;						\
+	write_32bit_cp0_register(register, res);		\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned int					\
+clear_cp0_##name(unsigned int clear)				\
+{								\
+	unsigned int res;					\
+								\
+	res = read_32bit_cp0_register(register);		\
+	res &= ~clear;						\
+	write_32bit_cp0_register(register, res);		\
+								\
+	return res;						\
+}								\
+								\
+static inline unsigned int					\
+change_cp0_##name(unsigned int change, unsigned int new)	\
+{								\
+	unsigned int res;					\
+								\
+	res = read_32bit_cp0_register(register);		\
+	res &= ~change;						\
+	res |= (new & change);					\
+	write_32bit_cp0_register(register, res);		\
+								\
+	return res;						\
+}
+
+__BUILD_SET_CP0(status,CP0_STATUS)
+__BUILD_SET_CP0(cause,CP0_CAUSE)
+__BUILD_SET_CP0(config,CP0_CONFIG)
+
+#define __enable_fpu()							\
+do {									\
+	set_cp0_status(ST0_CU1);					\
+	asm("nop;nop;nop;nop");		/* max. hazard */		\
+} while (0)
+
+#define __disable_fpu()							\
+do {									\
+	clear_cp0_status(ST0_CU1);					\
+	/* We don't care about the cp0 hazard here  */			\
+} while (0)
+
+#define enable_fpu()							\
+do {									\
+	if (mips_cpu.options & MIPS_CPU_FPU)				\
+		__enable_fpu();						\
+} while (0)
+
+#define disable_fpu()							\
+do {									\
+	if (mips_cpu.options & MIPS_CPU_FPU)				\
+		__disable_fpu();					\
+} while (0)
+
+#endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
 #endif /* _ASM_MIPSREGS_H */
Index: include/asm-mips/pgtable.h
===================================================================
RCS file: /home/pub/cvs/linux/include/asm-mips/pgtable.h,v
retrieving revision 1.60
diff -u -r1.60 pgtable.h
--- include/asm-mips/pgtable.h 2001/10/24 23:00:44 1.60  
+++ include/asm-mips/pgtable.h 2001/10/30 14:46:46   
@@ -507,274 +507,6 @@
 #define PageSkip(page)		(0)
 #define kern_addr_valid(addr)	(1)
 
-/* TLB operations. */
-extern inline void tlb_probe(void)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"tlbp\n\t"
-		".set pop");
-}
-
-extern inline void tlb_read(void)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"tlbr\n\t"
-		".set pop");
-}
-
-extern inline void tlb_write_indexed(void)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"tlbwi\n\t"
-		".set pop");
-}
-
-extern inline void tlb_write_random(void)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"tlbwr\n\t"
-		".set pop");
-}
-
-/* Dealing with various CP0 mmu/cache related registers. */
-
-/* CP0_PAGEMASK register */
-extern inline unsigned long get_pagemask(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $5\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-extern inline void set_pagemask(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $5\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-/* CP0_ENTRYLO0 and CP0_ENTRYLO1 registers */
-extern inline unsigned long get_entrylo0(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(	
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $2\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-extern inline void set_entrylo0(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $2\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-extern inline unsigned long get_entrylo1(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $3\n\t"
-		".set pop" : "=r" (val));
-
-	return val;
-}
-
-extern inline void set_entrylo1(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $3\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-/* CP0_ENTRYHI register */
-extern inline unsigned long get_entryhi(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $10\n\t"
-		".set pop"
-		: "=r" (val));
-
-	return val;
-}
-
-extern inline void set_entryhi(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $10\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-/* CP0_INDEX register */
-extern inline unsigned long get_index(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $0\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-extern inline void set_index(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $0\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-/* CP0_WIRED register */
-extern inline unsigned long get_wired(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $6\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-extern inline void set_wired(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $6\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-extern inline unsigned long get_info(void)
-{
-	unsigned long val;
-
-	__asm__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $7\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-/* CP0_TAGLO and CP0_TAGHI registers */
-extern inline unsigned long get_taglo(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $28\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-extern inline void set_taglo(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $28\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-extern inline unsigned long get_taghi(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $29\n\t"
-		".set pop"
-		: "=r" (val));
-	return val;
-}
-
-extern inline void set_taghi(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $29\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
-/* CP0_CONTEXT register */
-extern inline unsigned long get_context(void)
-{
-	unsigned long val;
-
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mfc0 %0, $4\n\t"
-		".set pop"
-		: "=r" (val));
-
-	return val;
-}
-
-extern inline void set_context(unsigned long val)
-{
-	__asm__ __volatile__(
-		".set push\n\t"
-		".set reorder\n\t"
-		"mtc0 %z0, $4\n\t"
-		".set pop"
-		: : "Jr" (val));
-}
-
 #include <asm-generic/pgtable.h>
 
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */

---

From: Atsushi Nemoto <[email-masked]>
Date: Wed, 31 Oct 2001 11:58:56 +0900 (JST)

>>>>> On Tue, 30 Oct 2001 15:55:33 +0100, Ralf Baechle <[email-masked]> said:
ralf> So here is a preliminiary version of my patch.  Still untested
ralf> and needs to be applied to mips64 also.

Thank you.  This patch works fine for me.

One request: with this patch, a ptrace call for FPC_EIR returns error
on FPU-less CPUs.  The call can be handled without error (as for other
FP registers).

--- /tmp/ptrace.c	Wed Oct 31 11:44:16 2001
+++ arch/mips/kernel/ptrace.c	Wed Oct 31 11:46:10 2001
@@ -174,8 +174,7 @@
 			unsigned int flags;
 
 			if (!(mips_cpu.options & MIPS_CPU_FPU)) {
-				res = -EIO;
-				goto out;
+				break;
 			}
 
 			__save_flags(flags);
---
Atsushi Nemoto

---

From: Ralf Baechle <[email-masked]>
Date: Wed, 31 Oct 2001 05:06:37 +0100

> on FPU-less CPUs.  The call can be handled without error (as for other

I don't think there is much point in returning a version number if there is
nothing we could return a version number of.  Well, maybe the fp emulation
sw version or kernel version.  What would you consider a sensible return
value?

  Ralf

---

From: Atsushi Nemoto <[email-masked]>
Date: Wed, 31 Oct 2001 13:30:11 +0900 (JST)

>>>>> On Wed, 31 Oct 2001 05:06:37 +0100, Ralf Baechle <[email-masked]> said:
ralf> I don't think there is much point in returning a version number
ralf> if there is nothing we could return a version number of.  Well,
ralf> maybe the fp emulation sw version or kernel version.  What would
ralf> you consider a sensible return value?

The reason of my request is that user-mode gdb reports error on "info
reg" command.  "info reg" command shows fsr and fir.

So, I don't care the return value.  I think "0" is enough for FPU-less
CPUs.

---
Atsushi Nemoto

---

From: Ralf Baechle <[email-masked]>
Date: Wed, 31 Oct 2001 05:31:42 +0100

> So, I don't care the return value.  I think "0" is enough for FPU-less

Ok, applied.

  Ralf

---

From: Daniel Jacobowitz <[email-masked]>
Date: Wed, 31 Oct 2001 00:07:56 -0500

> > So, I don't care the return value.  I think "0" is enough for FPU-less

Thanks; returning 0 is the best GDB can expect here.

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer