patch-2.4.22 linux-2.4.22/arch/mips64/kernel/cpu-probe.c

Next file: linux-2.4.22/arch/mips64/kernel/entry.S
Previous file: linux-2.4.22/arch/mips64/kernel/branch.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/arch/mips64/kernel/cpu-probe.c linux-2.4.22/arch/mips64/kernel/cpu-probe.c
@@ -1,9 +1,27 @@
+/*
+ *	arch/mips64/kernel/cpu-probe.c
+ *
+ *	Processor capabilities determination functions.
+ *
+ *	Copyright (C) xxxx  the Anonymous
+ *	Copyright (C) 2003  Maciej W. Rozycki
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/ptrace.h>
 #include <linux/stddef.h>
+
 #include <asm/bugs.h>
 #include <asm/cpu.h>
+#include <asm/fpu.h>
 #include <asm/mipsregs.h>
+#include <asm/system.h>
 
 /*
  * Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
@@ -16,14 +34,14 @@
 
 static void r3081_wait(void)
 {
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-	write_32bit_cp0_register(CP0_CONF, cfg|CONF_HALT);
+	unsigned long cfg = read_c0_conf();
+	write_c0_conf(cfg | R30XX_CONF_HALT);
 }
 
 static void r39xx_wait(void)
 {
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
-	write_32bit_cp0_register(CP0_CONF, cfg|TX39_CONF_HALT);
+	unsigned long cfg = read_c0_conf();
+	write_c0_conf(cfg | TX39_CONF_HALT);
 }
 
 static void r4k_wait(void)
@@ -39,23 +57,29 @@
 	/* using the wait instruction makes CP0 counter unusable */
 	__asm__(".set\tmips3\n\t"
 		"wait\n\t"
-		"nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set\tmips0");
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		"nop\n\t"
+		".set\tmips0");
 #else
-	__asm__("nop\n\t" "nop\n\t");
+	__asm__("nop\n\t"
+		"nop");
 #endif
 }
 
 static inline void check_wait(void)
 {
+	struct cpuinfo_mips *c = &current_cpu_data;
+
 	printk("Checking for 'wait' instruction... ");
-	switch(mips_cpu.cputype) {
+	switch (c->cputype) {
 	case CPU_R3081:
 	case CPU_R3081E:
 		cpu_wait = r3081_wait;
 		printk(" available.\n");
 		break;
 	case CPU_TX3927:
-	case CPU_TX39XX:
 		cpu_wait = r39xx_wait;
 		printk(" available.\n");
 		break;
@@ -89,9 +113,229 @@
 	}
 }
 
+static inline void check_mult_sh(void)
+{
+	unsigned long flags;
+	int m1, m2;
+	long p, s, v;
+
+	printk("Checking for the multiply/shift bug... ");
+
+	local_irq_save(flags);
+	/*
+	 * The following code leads to a wrong result of dsll32 when
+	 * executed on R4000 rev. 2.2 or 3.0.
+	 *
+	 * See "MIPS R4000PC/SC Errata, Processor Revision 2.2 and
+	 * 3.0" by MIPS Technologies, Inc., errata #16 and #28 for
+	 * details.  I got no permission to duplicate them here,
+	 * sigh... --macro
+	 */
+	asm volatile(
+		".set	push\n\t"
+		".set	noat\n\t"
+		".set	noreorder\n\t"
+		".set	nomacro\n\t"
+		"mult	%1, %2\n\t"
+		"dsll32	%0, %3, %4\n\t"
+		"mflo	$0\n\t"
+		".set	pop"
+		: "=r" (v)
+		: "r" (5), "r" (8), "r" (5), "I" (0)
+		: "hi", "lo", "accum");
+	local_irq_restore(flags);
+
+	if (v == 5L << 32) {
+		printk("no.\n");
+		return;
+	}
+
+	printk("yes, workaround... ");
+	local_irq_save(flags);
+	/*
+	 * We want the multiply and the shift to be isolated from the
+	 * rest of the code to disable gcc optimizations.  Hence the
+	 * asm statements that execute nothing, but make gcc not know
+	 * what the values of m1, m2 and s are and what v and p are
+	 * used for.
+	 *
+	 * We have to use single integers for m1 and m2 and a double
+	 * one for p to be sure the mulsidi3 gcc's RTL multiplication
+	 * instruction has the workaround applied.  Older versions of
+	 * gcc have correct mulsi3, but other multiplication variants
+	 * lack the workaround.
+	 */
+	asm volatile(
+		""
+		: "=r" (m1), "=r" (m2), "=r" (s)
+		: "0" (5), "1" (8), "2" (5));
+	p = m1 * m2;
+	v = s << 32;
+	asm volatile(
+		""
+		: "=r" (v)
+		: "0" (v), "r" (p));
+	local_irq_restore(flags);
+
+	if (v == 5L << 32) {
+		printk("yes.\n");
+		return;
+	}
+
+	printk("no.\n");
+	panic("Reliable operation impossible!\n"
+#ifndef CONFIG_CPU_R4000
+	      "Configure for R4000 to enable the workaround."
+#else
+	      "Please report to <linux-mips@linux-mips.org>."
+#endif
+	      );
+}
+
+static volatile int daddi_ov __initdata = 0;
+
+asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
+{
+	daddi_ov = 1;
+	regs->cp0_epc += 4;
+}
+
+static inline void check_daddi(void)
+{
+	extern asmlinkage void handle_daddi_ov(void);
+	unsigned long flags;
+	void *handler;
+	long v;
+
+	printk("Checking for the daddi bug... ");
+
+	local_irq_save(flags);
+	handler = set_except_vector(12, handle_daddi_ov);
+	/*
+	 * The following code fails to trigger an overflow exception
+	 * when executed on R4000 rev. 2.2 or 3.0.
+	 *
+	 * See "MIPS R4000PC/SC Errata, Processor Revision 2.2 and
+	 * 3.0" by MIPS Technologies, Inc., erratum #23 for details.
+	 * I got no permission to duplicate it here, sigh... --macro
+	 */
+	asm volatile(
+		".set	push\n\t"
+		".set	noat\n\t"
+		".set	noreorder\n\t"
+		".set	nomacro\n\t"
+#ifdef HAVE_AS_SET_DADDI
+		".set	daddi\n\t"
+#endif
+		"daddi	%0, %1, %2\n\t"
+		".set	pop"
+		: "=r" (v)
+		: "r" (0x7fffffffffffedcd), "I" (0x1234));
+	set_except_vector(12, handler);
+	local_irq_restore(flags);
+
+	if (daddi_ov) {
+		printk("no.\n");
+		return;
+	}
+
+	printk("yes, workaround... ");
+
+	local_irq_save(flags);
+	handler = set_except_vector(12, handle_daddi_ov);
+	asm volatile(
+		"daddi	%0, %1, %2"
+		: "=r" (v)
+		: "r" (0x7fffffffffffedcd), "I" (0x1234));
+	set_except_vector(12, handler);
+	local_irq_restore(flags);
+
+	if (daddi_ov) {
+		printk("yes.\n");
+		return;
+	}
+
+	printk("no.\n");
+	panic("Reliable operation impossible!\n"
+#if !defined(CONFIG_CPU_R4000) && !defined(CONFIG_CPU_R4400)
+	      "Configure for R4000 or R4400 to enable the workaround."
+#else
+	      "Please report to <linux-mips@linux-mips.org>."
+#endif
+	      );
+}
+
+static inline void check_daddiu(void)
+{
+	long v, w;
+
+	printk("Checking for the daddiu bug... ");
+
+	/*
+	 * The following code leads to a wrong result of daddiu when
+	 * executed on R4400 rev. 1.0.
+	 *
+	 * See "MIPS R4400PC/SC Errata, Processor Revision 1.0" by
+	 * MIPS Technologies, Inc., erratum #7 for details.
+	 *
+	 * According to "MIPS R4000PC/SC Errata, Processor Revision
+	 * 2.2 and 3.0" by MIPS Technologies, Inc., erratum #41 this
+	 * problem affects R4000 rev. 2.2 and 3.0, too.  Testing
+	 * failed to trigger it so far.
+	 *
+	 * I got no permission to duplicate the errata here, sigh...
+	 * --macro
+	 */
+	asm volatile(
+		".set	push\n\t"
+		".set	noat\n\t"
+		".set	noreorder\n\t"
+		".set	nomacro\n\t"
+#ifdef HAVE_AS_SET_DADDI
+		".set	daddi\n\t"
+#endif
+		"daddiu	%0, %2, %3\n\t"
+		"addiu	%1, $0, %3\n\t"
+		"daddu	%1, %2\n\t"
+		".set	pop"
+		: "=&r" (v), "=&r" (w)
+		: "r" (0x7fffffffffffedcd), "I" (0x1234));
+
+	if (v == w) {
+		printk("no.\n");
+		return;
+	}
+
+	printk("yes, workaround... ");
+
+	asm volatile(
+		"daddiu	%0, %2, %3\n\t"
+		"addiu	%1, $0, %3\n\t"
+		"daddu	%1, %2"
+		: "=&r" (v), "=&r" (w)
+		: "r" (0x7fffffffffffedcd), "I" (0x1234));
+
+	if (v == w) {
+		printk("yes.\n");
+		return;
+	}
+
+	printk("no.\n");
+	panic("Reliable operation impossible!\n"
+#if !defined(CONFIG_CPU_R4000) && !defined(CONFIG_CPU_R4400)
+	      "Configure for R4000 or R4400 to enable the workaround."
+#else
+	      "Please report to <linux-mips@linux-mips.org>."
+#endif
+	      );
+}
+
 void __init check_bugs(void)
 {
 	check_wait();
+	check_mult_sh();
+	check_daddi();
+	check_daddiu();
 }
 
 /*
@@ -104,12 +348,12 @@
 #ifdef CONFIG_CPU_R3000
 	extern unsigned long r3k_cache_size(unsigned long);
 	unsigned long size1, size2;
-	unsigned long cfg = read_32bit_cp0_register(CP0_CONF);
+	unsigned long cfg = read_c0_conf();
 
 	size1 = r3k_cache_size(ST0_ISC);
-	write_32bit_cp0_register(CP0_CONF, cfg^CONF_AC);
+	write_c0_conf(cfg ^ R30XX_CONF_AC);
 	size2 = r3k_cache_size(ST0_ISC);
-	write_32bit_cp0_register(CP0_CONF, cfg);
+	write_c0_conf(cfg);
 	return size1 != size2;
 #else
 	return 0;
@@ -123,143 +367,138 @@
 {
 	unsigned long tmp, fpu_id;
 
-	tmp = read_32bit_cp0_register(CP0_STATUS);
+	tmp = read_c0_status();
 	__enable_fpu();
 	fpu_id = read_32bit_cp1_register(CP1_REVISION);
-	write_32bit_cp0_register(CP0_STATUS, tmp);
+	write_c0_status(tmp);
 	return fpu_id;
 }
 
 /*
  * Check the CPU has an FPU the official way.
  */
-static inline int cpu_has_fpu(void)
+static inline int __cpu_has_fpu(void)
 {
 	return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
 }
 
-/* declaration of the global struct */
-struct mips_cpu mips_cpu = {
-    processor_id:	PRID_IMP_UNKNOWN,
-    fpu_id:		FPIR_IMP_NONE,
-    cputype:		CPU_UNKNOWN
-};
-
-/* Shortcut for assembler access to mips_cpu.options */
-int *cpuoptions = &mips_cpu.options;
-
 #define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4KTLB \
 		| MIPS_CPU_COUNTER | MIPS_CPU_CACHE_CDEX)
 
 __init void cpu_probe(void)
 {
-#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
-	unsigned long config0 = read_32bit_cp0_register(CP0_CONFIG);
+	struct cpuinfo_mips *c = &current_cpu_data;
+	unsigned long config0 = read_c0_config();
 	unsigned long config1;
 
+	c->processor_id	= PRID_IMP_UNKNOWN;
+	c->fpu_id	= FPIR_IMP_NONE;
+	c->cputype	= CPU_UNKNOWN;
+
         if (config0 & (1 << 31)) {
 		/* MIPS32 or MIPS64 compliant CPU. Read Config 1 register. */
-		mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-			MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC;
-		config1 = read_mips32_cp0_config1();
+		c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			MIPS_CPU_4KTLB | MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+			MIPS_CPU_LLSC;
+		config1 = read_c0_config1();
 		if (config1 & (1 << 3))
-			mips_cpu.options |= MIPS_CPU_WATCH;
+			c->options |= MIPS_CPU_WATCH;
 		if (config1 & (1 << 2))
-			mips_cpu.options |= MIPS_CPU_MIPS16;
+			c->options |= MIPS_CPU_MIPS16;
 		if (config1 & (1 << 1))
-			mips_cpu.options |= MIPS_CPU_EJTAG;
+			c->options |= MIPS_CPU_EJTAG;
 		if (config1 & 1) {
-			mips_cpu.options |= MIPS_CPU_FPU;
-#if defined(CONFIG_CPU_MIPS64)
-			mips_cpu.options |= MIPS_CPU_32FPR;
-#endif
+			c->options |= MIPS_CPU_FPU;
+			c->options |= MIPS_CPU_32FPR;
 		}
-		mips_cpu.scache.flags = MIPS_CACHE_NOT_PRESENT;
+		c->scache.flags = MIPS_CACHE_NOT_PRESENT;
+
+		c->tlbsize = ((config1 >> 25) & 0x3f) + 1;
 	}
-#endif
-	mips_cpu.processor_id = read_32bit_cp0_register(CP0_PRID);
-	switch (mips_cpu.processor_id & 0xff0000) {
+
+	c->processor_id = read_c0_prid();
+	switch (c->processor_id & 0xff0000) {
 	case PRID_COMP_LEGACY:
-		switch (mips_cpu.processor_id & 0xff00) {
+		switch (c->processor_id & 0xff00) {
 		case PRID_IMP_R2000:
-			mips_cpu.cputype = CPU_R2000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
-			if (cpu_has_fpu())
-				mips_cpu.options |= MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 64;
+			c->cputype = CPU_R2000;
+			c->isa_level = MIPS_CPU_ISA_I;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX |
+			             MIPS_CPU_LLSC;
+			if (__cpu_has_fpu())
+				c->options |= MIPS_CPU_FPU;
+			c->tlbsize = 64;
 			break;
 		case PRID_IMP_R3000:
-			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R3000A)
+			if ((c->processor_id & 0xff) == PRID_REV_R3000A)
 				if (cpu_has_confreg())
-					mips_cpu.cputype = CPU_R3081E;
+					c->cputype = CPU_R3081E;
 				else
-					mips_cpu.cputype = CPU_R3000A;
+					c->cputype = CPU_R3000A;
 			else
-				mips_cpu.cputype = CPU_R3000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX;
-			if (cpu_has_fpu())
-				mips_cpu.options |= MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 64;
+				c->cputype = CPU_R3000;
+			c->isa_level = MIPS_CPU_ISA_I;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_NOFPUEX |
+			             MIPS_CPU_LLSC;
+			if (__cpu_has_fpu())
+				c->options |= MIPS_CPU_FPU;
+			c->tlbsize = 64;
 			break;
 		case PRID_IMP_R4000:
-			if ((mips_cpu.processor_id & 0xff) == PRID_REV_R4400)
-				mips_cpu.cputype = CPU_R4400SC;
+			if ((c->processor_id & 0xff) >= PRID_REV_R4400)
+				c->cputype = CPU_R4400SC;
 			else
-				mips_cpu.cputype = CPU_R4000SC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH |
-			                   MIPS_CPU_VCE;
-			mips_cpu.tlbsize = 48;
+				c->cputype = CPU_R4000SC;
+			c->isa_level = MIPS_CPU_ISA_III;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_WATCH | MIPS_CPU_VCE |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
                 case PRID_IMP_VR41XX:
-			switch (mips_cpu.processor_id & 0xf0) {
+			switch (c->processor_id & 0xf0) {
 #ifndef CONFIG_VR4181
 			case PRID_REV_VR4111:
-				mips_cpu.cputype = CPU_VR4111;
+				c->cputype = CPU_VR4111;
 				break;
 #else
 			case PRID_REV_VR4181:
-				mips_cpu.cputype = CPU_VR4181;
+				c->cputype = CPU_VR4181;
 				break;
 #endif
 			case PRID_REV_VR4121:
-				mips_cpu.cputype = CPU_VR4121;
+				c->cputype = CPU_VR4121;
 				break;
 			case PRID_REV_VR4122:
-				if ((mips_cpu.processor_id & 0xf) < 0x3)
-					mips_cpu.cputype = CPU_VR4122;
+				if ((c->processor_id & 0xf) < 0x3)
+					c->cputype = CPU_VR4122;
 				else
-					mips_cpu.cputype = CPU_VR4181A;
+					c->cputype = CPU_VR4181A;
 				break;
 			case PRID_REV_VR4131:
-				mips_cpu.cputype = CPU_VR4131;
-				mips_cpu.icache.ways = 2;
-				mips_cpu.dcache.ways = 2;
+				c->cputype = CPU_VR4131;
 				break;
 			default:
 				printk(KERN_INFO "Unexpected CPU of NEC VR4100 series\n");
-				mips_cpu.cputype = CPU_VR41XX;
+				c->cputype = CPU_VR41XX;
 				break;
 			}
-                        mips_cpu.isa_level = MIPS_CPU_ISA_III;
-                        mips_cpu.options = R4K_OPTS;
-                        mips_cpu.tlbsize = 32;
+                        c->isa_level = MIPS_CPU_ISA_III;
+                        c->options = R4K_OPTS;
+                        c->tlbsize = 32;
                         break;
 		case PRID_IMP_R4300:
-			mips_cpu.cputype = CPU_R4300;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-					   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 32;
+			c->cputype = CPU_R4300;
+			c->isa_level = MIPS_CPU_ISA_III;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 32;
 			break;
 		case PRID_IMP_R4600:
-			mips_cpu.cputype = CPU_R4600;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 48;
+			c->cputype = CPU_R4600;
+			c->isa_level = MIPS_CPU_ISA_III;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		#if 0
  		case PRID_IMP_R4650:
@@ -269,101 +508,97 @@
 			 * for documentation.  Commented out because it shares
 			 * it's c0_prid id number with the TX3900.
 			 */
-	 		mips_cpu.cputype = CPU_R4650;
-		 	mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU;
-		        mips_cpu.tlbsize = 48;
+	 		c->cputype = CPU_R4650;
+		 	c->isa_level = MIPS_CPU_ISA_III;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_LLSC;
+		        c->tlbsize = 48;
 			break;
 		#endif
 		case PRID_IMP_TX39:
-			mips_cpu.isa_level = MIPS_CPU_ISA_I;
-			mips_cpu.options = MIPS_CPU_TLB;
+			c->isa_level = MIPS_CPU_ISA_I;
+			c->options = MIPS_CPU_TLB;
 
-			if ((mips_cpu.processor_id & 0xf0) ==
+			if ((c->processor_id & 0xf0) ==
 			    (PRID_REV_TX3927 & 0xf0)) {
-				mips_cpu.cputype = CPU_TX3927;
-				mips_cpu.tlbsize = 64;
-				mips_cpu.icache.ways = 2;
-				mips_cpu.dcache.ways = 2;
+				c->cputype = CPU_TX3927;
+				c->tlbsize = 64;
 			} else {
-				switch (mips_cpu.processor_id & 0xff) {
+				switch (c->processor_id & 0xff) {
 				case PRID_REV_TX3912:
-					mips_cpu.cputype = CPU_TX3912;
-					mips_cpu.tlbsize = 32;
+					c->cputype = CPU_TX3912;
+					c->tlbsize = 32;
 					break;
 				case PRID_REV_TX3922:
-					mips_cpu.cputype = CPU_TX3922;
-					mips_cpu.tlbsize = 64;
+					c->cputype = CPU_TX3922;
+					c->tlbsize = 64;
 					break;
 				default:
-					mips_cpu.cputype = CPU_UNKNOWN;
+					c->cputype = CPU_UNKNOWN;
 					break;
 				}
 			}
 			break;
 		case PRID_IMP_R4700:
-			mips_cpu.cputype = CPU_R4700;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
+			c->cputype = CPU_R4700;
+			c->isa_level = MIPS_CPU_ISA_III;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		case PRID_IMP_TX49:
-			mips_cpu.cputype = CPU_TX49XX;
-			mips_cpu.isa_level = MIPS_CPU_ISA_III;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
-			mips_cpu.icache.ways = 4;
-			mips_cpu.dcache.ways = 4;
+			c->cputype = CPU_TX49XX;
+			c->isa_level = MIPS_CPU_ISA_III;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		case PRID_IMP_R5000:
-			mips_cpu.cputype = CPU_R5000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 48;
+			c->cputype = CPU_R5000;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		case PRID_IMP_R5432:
-			mips_cpu.cputype = CPU_R5432;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 48;
+			c->cputype = CPU_R5432;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_WATCH | MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		case PRID_IMP_R5500:
-			mips_cpu.cputype = CPU_R5500;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 48;
+			c->cputype = CPU_R5500;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_WATCH | MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		case PRID_IMP_NEVADA:
-			mips_cpu.cputype = CPU_NEVADA;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR | MIPS_CPU_DIVEC;
-			mips_cpu.tlbsize = 48;
-			mips_cpu.icache.ways = 2;
-			mips_cpu.dcache.ways = 2;
+			c->cputype = CPU_NEVADA;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_DIVEC | MIPS_CPU_LLSC;
+			c->tlbsize = 48;
 			break;
 		case PRID_IMP_R6000:
-			mips_cpu.cputype = CPU_R6000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_II;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 32;
+			c->cputype = CPU_R6000;
+			c->isa_level = MIPS_CPU_ISA_II;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 32;
 			break;
 		case PRID_IMP_R6000A:
-			mips_cpu.cputype = CPU_R6000A;
-			mips_cpu.isa_level = MIPS_CPU_ISA_II;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_FPU;
-			mips_cpu.tlbsize = 32;
+			c->cputype = CPU_R6000A;
+			c->isa_level = MIPS_CPU_ISA_II;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_FPU |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 32;
 			break;
 		case PRID_IMP_RM7000:
-			mips_cpu.cputype = CPU_RM7000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = R4K_OPTS | MIPS_CPU_FPU |
-			                   MIPS_CPU_32FPR;
+			c->cputype = CPU_RM7000;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = R4K_OPTS | MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_LLSC;
 			/*
 			 * Undocumented RM7000:  Bit 29 in the info register of
 			 * the RM7000 v2.0 indicates if the TLB has 48 or 64
@@ -372,118 +607,139 @@
 			 * 29      1 =>    64 entry JTLB
 			 *         0 =>    48 entry JTLB
 			 */
-			mips_cpu.tlbsize = (get_info() & (1 << 29)) ? 64 : 48;
+			c->tlbsize = (read_c0_info() & (1 << 29)) ? 64 : 48;
 			break;
 		case PRID_IMP_R8000:
-			mips_cpu.cputype = CPU_R8000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR;
-			mips_cpu.tlbsize = 384;      /* has weird TLB: 3-way x 128 */
+			c->cputype = CPU_R8000;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			             MIPS_CPU_FPU | MIPS_CPU_32FPR |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 384;      /* has weird TLB: 3-way x 128 */
 			break;
 		case PRID_IMP_R10000:
-			mips_cpu.cputype = CPU_R10000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR |
-				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 64;
+			c->cputype = CPU_R10000;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			             MIPS_CPU_FPU | MIPS_CPU_32FPR |
+				     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 64;
 			break;
 		case PRID_IMP_R12000:
-			mips_cpu.cputype = CPU_R12000;
-			mips_cpu.isa_level = MIPS_CPU_ISA_IV;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-				           MIPS_CPU_FPU | MIPS_CPU_32FPR |
-				           MIPS_CPU_COUNTER | MIPS_CPU_WATCH;
-			mips_cpu.tlbsize = 64;
+			c->cputype = CPU_R12000;
+			c->isa_level = MIPS_CPU_ISA_IV;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			             MIPS_CPU_FPU | MIPS_CPU_32FPR |
+				     MIPS_CPU_COUNTER | MIPS_CPU_WATCH |
+			             MIPS_CPU_LLSC;
+			c->tlbsize = 64;
 			break;
 		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
+			c->cputype = CPU_UNKNOWN;
 			break;
 		}
 		break;
-#if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
 	case PRID_COMP_MIPS:
-		switch (mips_cpu.processor_id & 0xff00) {
+		switch (c->processor_id & 0xff00) {
 		case PRID_IMP_4KC:
-			mips_cpu.cputype = CPU_4KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			c->cputype = CPU_4KC;
+			c->isa_level = MIPS_CPU_ISA_M32;
 			break;
 		case PRID_IMP_4KEC:
-			mips_cpu.cputype = CPU_4KEC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			c->cputype = CPU_4KEC;
+			c->isa_level = MIPS_CPU_ISA_M32;
 			break;
 		case PRID_IMP_4KSC:
-			mips_cpu.cputype = CPU_4KSC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			c->cputype = CPU_4KSC;
+			c->isa_level = MIPS_CPU_ISA_M32;
 			break;
 		case PRID_IMP_5KC:
-			mips_cpu.cputype = CPU_5KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			c->cputype = CPU_5KC;
+			c->isa_level = MIPS_CPU_ISA_M64;
 			break;
 		case PRID_IMP_20KC:
-			mips_cpu.cputype = CPU_20KC;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
+			c->cputype = CPU_20KC;
+			c->isa_level = MIPS_CPU_ISA_M64;
 			break;
 		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
+			c->cputype = CPU_UNKNOWN;
 			break;
 		}
 		break;
 	case PRID_COMP_ALCHEMY:
-		switch (mips_cpu.processor_id & 0xff00) {
+		switch (c->processor_id & 0xff00) {
 		case PRID_IMP_AU1_REV1:
 		case PRID_IMP_AU1_REV2:
-			switch ((mips_cpu.processor_id >> 24) & 0xff) {
+			switch ((c->processor_id >> 24) & 0xff) {
 			case 0:
- 				mips_cpu.cputype = CPU_AU1000;
+ 				c->cputype = CPU_AU1000;
 				break;
 			case 1:
-				mips_cpu.cputype = CPU_AU1500;
+				c->cputype = CPU_AU1500;
 				break;
 			case 2:
-				mips_cpu.cputype = CPU_AU1100;
+				c->cputype = CPU_AU1100;
 				break;
 			default:
 				panic("Unknown Au Core!");
 				break;
 			}
-			mips_cpu.isa_level = MIPS_CPU_ISA_M32;
+			c->isa_level = MIPS_CPU_ISA_M32;
  			break;
 		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
+			c->cputype = CPU_UNKNOWN;
 			break;
 		}
 		break;
-#endif /* CONFIG_CPU_MIPS32 */
 	case PRID_COMP_SIBYTE:
-		switch (mips_cpu.processor_id & 0xff00) {
+		switch (c->processor_id & 0xff00) {
 		case PRID_IMP_SB1:
-			mips_cpu.cputype = CPU_SB1;
-			mips_cpu.isa_level = MIPS_CPU_ISA_M64;
-			mips_cpu.options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
-			                   MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
-			                   MIPS_CPU_MCHECK;
+			c->cputype = CPU_SB1;
+			c->isa_level = MIPS_CPU_ISA_M64;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+			             MIPS_CPU_COUNTER | MIPS_CPU_DIVEC |
+			             MIPS_CPU_MCHECK | MIPS_CPU_EJTAG |
+			             MIPS_CPU_WATCH | MIPS_CPU_LLSC;
 #ifndef CONFIG_SB1_PASS_1_WORKAROUNDS
 			/* FPU in pass1 is known to have issues. */
-			mips_cpu.options |= MIPS_CPU_FPU;
+			c->options |= MIPS_CPU_FPU | MIPS_CPU_32FPR;
 #endif
 			break;
 		default:
-			mips_cpu.cputype = CPU_UNKNOWN;
+			c->cputype = CPU_UNKNOWN;
+			break;
+		}
+		break;
+
+	case PRID_COMP_SANDCRAFT:
+		switch (c->processor_id & 0xff00) {
+		case PRID_IMP_SR71000:
+			c->cputype = CPU_SR71000;
+			c->isa_level = MIPS_CPU_ISA_M64;
+			c->options = MIPS_CPU_TLB | MIPS_CPU_4KEX |
+                                     MIPS_CPU_4KTLB | MIPS_CPU_FPU |
+			             MIPS_CPU_COUNTER | MIPS_CPU_MCHECK;
+			c->scache.ways = 8;
+			c->tlbsize = 64;
+			break;
+		default:
+			c->cputype = CPU_UNKNOWN;
 			break;
 		}
 		break;
 	default:
-		mips_cpu.cputype = CPU_UNKNOWN;
+		c->cputype = CPU_UNKNOWN;
 	}
-	if (mips_cpu.options & MIPS_CPU_FPU)
-		mips_cpu.fpu_id = cpu_get_fpu_id();
+	if (c->options & MIPS_CPU_FPU)
+		c->fpu_id = cpu_get_fpu_id();
 }
 
 __init void cpu_report(void)
 {
-	printk("CPU revision is: %08x\n", mips_cpu.processor_id);
-	if (mips_cpu.options & MIPS_CPU_FPU)
-		printk("FPU revision is: %08x\n", mips_cpu.fpu_id);
+	struct cpuinfo_mips *c = &current_cpu_data;
+
+	printk("CPU revision is: %08x\n", c->processor_id);
+	if (c->options & MIPS_CPU_FPU)
+		printk("FPU revision is: %08x\n", c->fpu_id);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)