[PATCH] Cyrix detection for kernels 2.0.34+

Andrew Derrick Balsa (andrebalsa@altern.org)
Mon, 15 Jun 1998 02:29:23 -0100


This is a multi-part message in MIME format.

--------------4BA9967668D56011981F135
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 8bit

Hi,

After Rafael posted his patch, I put some finishing touches to it,
converted it to kernel 2.0.34, and actually *tested* the thing.

Here is what I get on my 6x86L @ 150MHz machine (using it now to write
this email):

processor : 0
cpu : 586
model : 6x86L
vendor_id : CyrixInstead
stepping : 4.2, core/bus clock ratio: 2x
fdiv_bug : no
hlt_bug : no
f00f_bug : no
fpu : yes
fpu_exception : yes
cpuid : yes
wp : yes
flags : fpu de cx8
bogomips : 124.52

The bogomips reading is wrong because of the way the small loop in
/arch/i386/lib/delay.S gets aligned when one compiles a kernel for
Pentium or PPro. I am all ears for suggestions on how to workaround
this. When compiled as a 386 the bogomips rating is correct. However the
innacurate bogomips actually doesn't cause any problems, as far as I can
tell.

Anyways, attached is the patch for 2.0.34. Users of kernels 2.1.10x will
have to wait for Rafael's version, available next week.

And yes this patch has all the safe save_flag/cli/restore_flag sequences
needed. And it has finally moved everything Cyrix specific originally in
head.S to bugs.h, just as Linus requested.

I'll just add that if Rafael hadn't started this and done 95% of the
hard work, I would have left things just as they were.

Cheers,
------------------------
André Balsa
andrebalsa@altern.org

--------------4BA9967668D56011981F135
Content-Type: text/plain; charset=us-ascii; name="Cyrix_detect.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="Cyrix_detect.patch"

--- ./linux/include/asm-i386/bugs.h.orig Sun Jun 14 10:07:58 1998
+++ ./linux/include/asm-i386/bugs.h Mon Jun 15 01:33:05 1998
@@ -2,6 +2,8 @@
* include/asm-i386/bugs.h
*
* Copyright (C) 1994 Linus Torvalds
+ *
+ * Cyrix stuff by Rafael R. Reilova & Andrew D. Balsa, June 1998
*/

/*
@@ -145,9 +147,151 @@
}
}

+/* Cyrix stuff from this point on */
+
+/* Cyrix CPU port access macros */
+static inline unsigned char getCx86(unsigned char reg)
+{
+ unsigned char data;
+
+ __asm__ __volatile__("movb %1,%%al\n\t"
+ "outb %%al,$0x22\n\t"
+ "inb $0x23,%%al" : "=al" (data) : "q" (reg));
+ return data;
+}
+
+static inline void setCx86(unsigned char reg, unsigned char data)
+{
+ __asm__ __volatile__("outb %%al,$0x22\n\t"
+ "movb %1,%%al\n\t"
+ "outb %%al,$0x23" : : "al" (reg), "q" (data));
+}
+
+/* cpuid ripped from setup.c (should it go in an include somewhere?) */
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ __asm__("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "a" (op)
+ : "cc");
+}
+
+/* perform the Cyrix 5/2 test (!0 means it's a Cyrix) */
+static inline int test_cyrix_52div(void)
+{
+ int test;
+
+ __asm__ __volatile__("xor %%eax,%%eax\n\t"
+ "sahf\n\t"
+ "movb $5,%%al\n\t"
+ "movb $2,%%bl\n\t"
+ "div %%bl\n\t"
+ "lahf\n\t"
+ "andl $0x200,%%eax": "=eax" (test) : : "bx");
+
+ return test;
+}
+
+/* redo the cpuid test in head.S, so that those Cx686(L) now get
+ detected properly (0 == no cpuid) */
+static inline int test_cpuid(void)
+{
+ int test;
+
+ __asm__("pushfl\n\t"
+ "popl %%eax\n\t"
+ "movl %%eax,%%ecx\n\t"
+ "xorl $0x200000,%%eax\n\t"
+ "pushl %%eax\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %%eax\n\t"
+ "xorl %%ecx,%%eax\n\t"
+ "pushl %%ecx\n\t"
+ "popfl" : "=eax" (test) : : "cx");
+
+ return test;
+}
+
+/* All Cyrix 6x86 and 6x86L need the SLOP bit reset so that the udelay loop
+ * calibration works well.
+ * This routine must be called with MAPEN enabled, otherwise we don't
+ * have access to CCR5.
+ */
+
+static void check_6x86_slop(void)
+{
+#define Cx6x86_CCR5 0xe9
+ if (x86_model == 2) /* if 6x86 or 6x86L */
+ setCx86(Cx6x86_CCR5, getCx86(Cx6x86_CCR5) & 0xfd); /* reset SLOP */
+}
+
+/* Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
+ by the fact that they preserve the flags across the division of 5/2.
+ PII and PPro exhibit this behavior too, but they have cpuid available */
+static void check_cyrix_various(void)
+{
+#define Cx6x86_CCR3 0xc3
+#define Cx6x86_CCR4 0xe8
+
+
+ if (x86 == 4 && test_cyrix_52div()) {
+ unsigned char ccr3;
+ unsigned long flags;
+ int cpuid_level = 0;
+
+ /* default to a generic Cx486 */
+ strcpy(x86_vendor_id, "CyrixInstead");
+ x86_model = 1;
+ x86_mask = 0;
+
+ /* Disable interrupts */
+ /* and enable MAPEN */
+ save_flags(flags);
+ cli();
+
+ ccr3 = getCx86(Cx6x86_CCR3);
+ setCx86(Cx6x86_CCR3, (ccr3 & 0x0f) | 0x10);
+
+ /* try enabling cpuid */
+ setCx86(Cx6x86_CCR4, getCx86(Cx6x86_CCR4) | 0x80);
+
+ if (test_cpuid()) {
+
+ /* get vendor string and cpuid levels */
+ /* careful here with the order of the 4-byte strings */
+ cpuid(0, &cpuid_level,
+ (int *) &x86_vendor_id,
+ (int *) &x86_vendor_id+8,
+ (int *) &x86_vendor_id+4);
+
+ /* get processor info if available */
+ if (cpuid_level) {
+ int eax, dummy;
+
+ cpuid(1, &eax, &dummy, &dummy,
+ &x86_capability);
+
+ have_cpuid = 1;
+ x86_model = (eax >> 4) & 0xf;
+ x86 = (eax >> 8) & 0xf;
+ check_6x86_slop();
+ }
+ }
+ /* disable MAPEN */
+ setCx86(Cx6x86_CCR3, ccr3);
+ /* and restore interrupt state */
+ restore_flags(flags);
+ }
+}

+/* Check various processor bugs */
static void check_bugs(void)
{
+ check_cyrix_various();
check_tlb();
check_fpu();
check_hlt();
--- ./linux/init/main.c.orig Sun Jun 14 10:08:13 1998
+++ ./linux/init/main.c Sun Jun 14 21:24:20 1998
@@ -858,6 +858,7 @@
#endif
memory_start = kmalloc_init(memory_start,memory_end);
sti();
+ check_bugs();
calibrate_delay();
memory_start = inode_init(memory_start,memory_end);
memory_start = file_table_init(memory_start,memory_end);
@@ -878,7 +879,6 @@
dquot_init();
arch_syms_export();
sti();
- check_bugs();

printk(linux_banner);
#ifdef __SMP__
--- ./linux/arch/i386/kernel/setup.c.orig Sun Jun 14 10:08:02 1998
+++ ./linux/arch/i386/kernel/setup.c Mon Jun 15 01:31:20 1998
@@ -32,7 +32,7 @@
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/smp.h>
-
+#include <asm/io.h>
/*
* Tell us the machine setup..
*/
@@ -48,9 +48,16 @@
char x86_vendor_id[13] = "unknown";

unsigned char Cx86_step = 0;
+
static const char *Cx86_type[] = {
- "unknown", "1.3", "1.4", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
- };
+ "unknown", "1.3", "1.4", "1.5", "1.6", "2.8", "2.4", "2.5", "2.6", "2.7 or 3.7", "4.2"
+ };
+
+static const char *x86_clkmult[] = {
+ "unknown", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5", "6"
+ };
+
+unsigned char Cx86_mult = 1; /* clock multiplier for Cyrix 6x86 CPUs */

char ignore_irq13 = 0; /* set if exception 16 works */
char wp_works_ok = -1; /* set if paging hardware honours WP */
@@ -234,8 +241,9 @@
static const char * Cx86model(void)
{
unsigned char nr6x86 = 0;
+ unsigned int flags;
static const char *model[] = {
- "unknown", "6x86", "6x86L", "6x86MX", "6x86MXi"
+ "unknown", "6x86", "6x86L", "6x86MX", "MII"
};
switch (x86) {
case 5:
@@ -247,32 +255,53 @@
default:
nr6x86 = 0;
}
- switch (x86_mask) {
- case 0x03:
- Cx86_step = 1; /* 6x86MX Rev 1.3 */
- break;
- case 0x04:
- Cx86_step = 2; /* 6x86MX Rev 1.4 */
- break;
- case 0x14:
- Cx86_step = 3; /* 6x86 Rev 2.4 */
- break;
- case 0x15:
- Cx86_step = 4; /* 6x86 Rev 2.5 */
- break;
- case 0x16:
- Cx86_step = 5; /* 6x86 Rev 2.6 */
- break;
- case 0x17:
- Cx86_step = 6; /* 6x86 Rev 2.7 or 3.7 */
- break;
- case 0x22:
- Cx86_step = 7; /* 6x86L Rev 4.2 */
- break;
- default:
- Cx86_step = 0;
- }
- return model[nr6x86];
+
+ /* We must get the stepping number by reading DIR1 */
+ save_flags(flags);
+ cli();
+ outb(0xff, 0x22); x86_mask=inb(0x23);
+ restore_flags(flags);
+ switch (x86_mask) {
+ case 0x03:
+ Cx86_step = 1; /* 6x86MX Rev 1.3 */
+ break;
+ case 0x04:
+ Cx86_step = 2; /* 6x86MX Rev 1.4 */
+ break;
+ case 0x05:
+ Cx86_step = 3; /* 6x86MX Rev 1.5 */
+ break;
+ case 0x06:
+ Cx86_step = 4; /* 6x86MX Rev 1.6 */
+ break;
+ case 0x08:
+ Cx86_step = 5; /* MII Rev 2.8 */
+ nr6x86++;
+ break;
+ case 0x14:
+ Cx86_step = 6; /* 6x86 Rev 2.4 */
+ break;
+ case 0x15:
+ Cx86_step = 7; /* 6x86 Rev 2.5 */
+ break;
+ case 0x16:
+ Cx86_step = 8; /* 6x86 Rev 2.6 */
+ break;
+ case 0x17:
+ Cx86_step = 9; /* 6x86 Rev 2.7 or 3.7 */
+ break;
+ case 0x22:
+ Cx86_step = 10; /* 6x86L Rev 4.2 */
+ break;
+ default:
+ Cx86_step = 0;
+ }
+ /* And we get the clock multiplier by reading DIR0 */
+ save_flags(flags);
+ cli();
+ outb(0xfe, 0x22); Cx86_mult=(inb(0x23) & 0x07) + 1;
+ restore_flags(flags);
+ return model[nr6x86];
}

static const char * i686model(unsigned int nr)
@@ -357,9 +386,9 @@
}
else { /* we have a Cyrix */
len += sprintf(buffer+len,
- "stepping\t: %s\n",
- Cx86_type[Cx86_step]);
- }
+ "stepping\t: %s, core/bus clock ratio: %sx\n",
+ Cx86_type[Cx86_step], x86_clkmult[Cx86_mult]);
+ }
else
len += sprintf(buffer+len,
"stepping\t: unknown\n");

--------------4BA9967668D56011981F135--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu