Cyrix VSPM Patches for 2.1.62

Christoph Lameter (chris@waterf.org)
Mon, 3 Nov 1997 18:27:07 -0800 (PST)


I found the Cyrix VSPM patches for 2.1.39. They were difficult to handle
since they were based on RCS. Here they come adapted for 2.1.62 in regular
customary diff format:

diff -urN --exclude=.* linux-2.1.62/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.1.62/Documentation/Configure.help Mon Nov 3 14:22:51 1997
+++ linux/Documentation/Configure.help Mon Nov 3 17:13:52 1997
@@ -855,11 +855,11 @@
you have use for it.
If you don't know what to answer at this point, say Y.

-Processor type
+Processor family
CONFIG_M386
This is the processor type of your CPU. This information is used for
optimizing purposes. In order to compile a kernel that can run on
- all Intel CPU types (albeit not optimally fast), you can specify
+ all x86 CPU types (albeit not optimally fast), you can specify
"386" here. If you specify one of "486" or "Pentium" or "PPro",
then the kernel will run on all of these CPUs: 486 and Pentium
(=586) and Pentium Pro (=686). In rare cases, it can make sense to
@@ -5659,6 +5659,87 @@
called AP1000+. For details on our efforts to port Linux to this
machine see http://cap.anu.edu.au/cap/projects/linux or mail to
hackers@cafe.anu.edu.au
+
+Support for Cyrix processors
+CONFIG_CYRIX
+ This enables recognition of Cyrix processors. Without it
+ /proc/cpuinfo will list your processor as an unknown model
+ of Cyrix. With it it will list the correct details. It should
+ be safe to say Y here regardless of what processor you are
+ actually using. If this option is not enabled none of the
+ Cyrix feature options are available.
+
+Enable suspend on halt power saving feature
+CONFIG_CYRIX_SUSP_HLT
+ Suspend on halt causes the processor to enter a low power state
+ when the "hlt" instruction is executed. This is disabled at
+ power up and many BIOSs leave it that way. You probably want it
+ enabled since it dramatically reduces the operating temperature
+ of the processor. In a few rare cases there may be problems
+ with some bus master DMA cards if this is enabled.
+
+No I/O recovery delays
+CONFIG_CYRIX_FAST_IO
+ Historically programmers used "jmp $+2" instructions to create
+ delays between I/O instructions. The branch prediction of 5x86
+ and higher processors renders this ineffective and so a selectable
+ delay is implemented for I/O instructions in the processor. Linux
+ uses dummy I/O instructions where necessary rather than jumps
+ and so the extra processor imposed delay should not be necessary.
+ Enabling this option removes this delay.
+
+5x86 performance features
+CONFIG_CYRIX_5X86
+ The Cyrix 5x86 has several performance feature which are enabled
+ using on-chip registers. This code attempts to ensure that the
+ useful features are set to suit Linux. Read Documentation/Cyrix
+ before enabling this.
+ WARNING: If this is enabled you may find that the only way to
+ reboot is to power cycle the machine. Even a hard reboot seems
+ to fail on some systems.
+
+6x86 performance features
+CONFIG_CYRIX_6X86
+ The Cyrix 6x86 has several performance feature which are enabled
+ using on-chip registers. Most are normally enabled by the BIOS
+ however this code ensures that all the useful ones are set to
+ suit Linux. Read Documentation/Cyrix before enabling this.
+
+Avoid unnecessary locked cycles
+CONFIG_CYRIX_6X86_NOLOCK
+ Enabling this option causes the 6x86 not to use locked bus cycles
+ except for page table access and interrupt acknowledge cycles.
+ This allows the data used by descriptor tables, xchg instructions
+ and instructions preceeded by the LOCK prefix to be cached leading
+ to improved performance. Enabling this option has no effect if
+ an SMP kernel is being built - SMP requires locked cycles to
+ guarantee processor synchronization.
+
+Allocate L1 cache lines on write misses
+CONFIG_CYRIX_6X86_WTALLOC
+ If this is enabled L1 cache write misses will cause a cache line
+ to be allocated. This may result in increased performance. On the
+ other hand it may cause excessive trashing of the L1 cache when
+ copying or zeroing pages.
+
+Branch Target Buffer features
+CONFIG_CYRIX_6X86_BTB
+ The Cyrix 6x86 has branch prediction logic which is normally
+ only set to handle short branches (as in small loops and ifs).
+ This code attempts on configure the branch prediction logic
+ approriately. Read Documentation/Cyrix before enabling this.
+
+Variable sized paging mechanism (VSPM)
+CONFIG_CYRIX_6X86_VSPM
+ Variable sized paging mechanism (VSPM) is a feature of the Cyrix
+ 6x86 family of processors that allows large regions of memory
+ to be mapped in one go, significantly reducing the amount of work
+ the MMU has to do compared with traditional paging. However VSPM
+ is known to be buggy in many 6x86 chip revisions. Please read
+ Documentation/Cyrix before enabling this.
+ WARNING: If this is enabled you may find that the only way to
+ reboot is to power cycle the machine. Even a hard reboot seems
+ to fail on some systems.

Sparc ESP SCSI support
CONFIG_SCSI_SUNESP
diff -urN --exclude=.* linux-2.1.62/Documentation/Cyrix linux/Documentation/Cyrix
--- linux-2.1.62/Documentation/Cyrix Wed Dec 31 16:00:00 1969
+++ linux/Documentation/Cyrix Mon Nov 3 17:13:52 1997
@@ -0,0 +1,148 @@
+ Cyrix Processor Support
+ -----------------------
+
+Processor Recognition
+---------------------
+
+Cyrix processors prior to the M2 power up in a default mode which
+is designed to avoid compatibility problems with software that
+makes assumptions about processor capabilities based solely on
+the apparent family of processor. Unless special handling is
+provided Cyrix chips will be identified as some unknown model
+of 486.
+
+ The Cyrix processor recognition kernel build option compiles
+in code that enables the CPUID instruction on Cyrix processors
+and that uses the Cyrix specific DEVID feature to identify the
+particular type of Cyrix chip present.
+
+ The M2 and later processors have CPUID enabled by default
+however special handling is still required to read the specific
+processor type using DEVID since the CPUID information gives
+family 6, model 0 - i.e. an A step PPro.
+
+ The combination of CPUID and DEVID allows all current Cyrix
+processors to be recognised and listed correctly in /proc/cpuinfo.
+This includes Cx486, 5x86, 6x86, Gx86 (aka MediaGx) and M2.
+
+ Processor recognition is required for all other Cyrix specific
+options.
+
+
+Suspend on Halt Power Saving
+----------------------------
+
+The suspend on halt power saving feature allows the processor to
+enter a low power mode when the "hlt" instruction is executed. This
+results in dramatically reduced operating temperatures if you do
+not spend long periods of time running processor intensive tasks.
+Cyrix processors allow this feature to be enabled an disabled
+through their configuration registers. The default state on reset
+is disabled and many (most?) BIOSs leave it disabled hence a
+kernel configuration option is provided that adds code to explicitly
+enabled suspend on halt when Linux boots.
+
+ However there appear to be a few rare cases in which the
+combination of suspend on halt and some bus master DMA cards can
+cause the system to lock up. If this appears to happen you may
+need to leave suspend on halt in its default state. (Note that
+an option to _disable_ suspend on halt is not provided. If your
+BIOS enables it you have to live with it)
+
+
+5x86 Performance Features
+-------------------------
+
+The 5x86 contains a performance control register that allows
+several performance enhancing features to be turned on. Unfortunately
+many of these features do not appear to work correctly. The 5x86
+performance features kernel build option will attempt to set
+the performance control register appropriately but it is
+impossible to guarantee that even these conservative settings
+will work on all chips.
+
+ WARNING: If this is enabled you may find that the only way to
+reboot is to power cycle the machine. Even a hard reboot seems
+to fail on some systems.
+
+
+6x86 Performance Features
+-------------------------
+
+Like the 5x86 the 6x86 has several Cyrix specific performance
+features. Normally a 6x86 aware BIOS will set these to reasonable,
+if not fully optimal, settings. The 6x86 performance features
+kernel build option mostly just fine tunes them.
+
+
+6x86 Branch Prediction
+----------------------
+
+The 6x86 uses speculative execution coupled with several levels
+of branch prediction to maximise processing speed. While the
+default power up state is reasonable the branch prediction logic
+is configurable and there may be some benefit in fine tuning it.
+
+ Unfortunately Cyrix offer no documentation on how to configure
+branch prediction and IBM have only partial documentation available.
+Further detail and speculation is available from the 6x86opt package
+by Mikael Johansson <Mikael.Johansson@helsinki.fi>.
+
+ The initial power up state of the 6x86 configures the branch
+prediction logic to handle short branches. The 6x86 branch target
+buffer features kernel build option enables code that enables
+handling of long branches as well. It is not clear if this will
+benefit in your particular case or not.
+
+
+6x86 Variable Sized Paging Mechanism
+------------------------------------
+
+The variable sized paging mechanism (VSPM) is a feature of the Cyrix
+6x86 family of processors that allows large regions of memory
+to be mapped using a single MMU entry rather than many individual
+page sized entries. This significantly reduces the overhead in
+accessing such regions. It is also ideally suited to use for the
+linear mapping of physical memory to kernel memory used by Linux.
+
+ The Cyrix documenation offers only a brief paragraph of explanation.
+Unfortunately the observed behaviour of VSPM suggests that even
+this little information is not entirely correct. Worse still, no one
+at Cyrix is able to answer questions concerning VSPM. Given that
+every revision of 6x86 has *different* VSPM bugs this is not entirely
+surprising! Work arounds are in place for the known bugs in step 1,
+revisions 4, 5 and 6 chips. Revision 7 is also believed to work.
+
+ WARNING: There appears to be no way to disable a VSPM entry once
+it has been created short of a hard reset (which may mean a power
+cycle). Failure to clear the VSPM entries means that programs that
+use virtual memory layouts different from Linux will crash unexpectedly
+after Linux has been running. This includes Windows NT/95, programs
+that use DOS extenders etc.
+
+ By experiment:
+
+ * VSPM pages must be power of two sizes. A single 24MB page fails.
+ This is not entirely surprising but the documentation could give
+ the impression that VSPM supports arbitrary sizes.
+
+ * Documentation suggests there are 8 VSPM slots (3 bit index) but
+ tests show the upper four slots mirror the lower four.
+
+ * With a 16MB page followed by an 8MB page I always get a write
+ fault on the last 4k of the 8MB page. With 8MB plus 4MB I can't
+ even boot.
+ If we have such a memory size we map the first power of two
+ with a VSPM entry and use traditional paging for the rest.
+
+ * VSPM entries appear to override traditional page table entries
+ so we must not overlap the start of the vmalloc region.
+
+ * Do not try and create a mapping with dirty and accessed flags
+ clear - a step 1 rev 5 chip will crash.
+
+ * The valid bit in a VSPM entry is non-functional. There is no way
+ to invalidate a VSPM entry once it has been written.
+
+ * Attempting to replace a VSPM entry with one that maps a zero
+ sized region from 0 to 0 crashes the CPU.
diff -urN --exclude=.* linux-2.1.62/arch/i386/config.in linux/arch/i386/config.in
--- linux-2.1.62/arch/i386/config.in Sat Oct 25 08:16:23 1997
+++ linux/arch/i386/config.in Mon Nov 3 17:13:52 1997
@@ -9,6 +9,34 @@
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu

+choice 'Processor family' \
+ "386 CONFIG_M386 \
+ 486 CONFIG_M486 \
+ Pentium CONFIG_M586 \
+ PPro CONFIG_M686" Pentium
+
+mainmenu_option next_comment
+comment 'Processor features'
+
+comment 'Some or all of the following may cause problems'
+comment 'with some drivers or hardware. Please read the'
+comment 'help text and Documentation/Cyrix before enabling'
+comment 'any of these options.'
+bool 'Cyrix processor recognition' CONFIG_CYRIX
+if [ "$CONFIG_CYRIX" = "y" ]; then
+ bool 'Enable suspend on halt power saving' CONFIG_CYRIX_SUSP_HLT
+ bool 'No I/O recovery delays' CONFIG_CYRIX_FAST_IO
+ bool '5x86 performance features' CONFIG_CYRIX_5X86
+ bool '6x86 performance features' CONFIG_CYRIX_6X86
+ if [ "$CONFIG_CYRIX_6X86" = "y" ]; then
+ bool ' Avoid unnecessary locked cycles' CONFIG_CYRIX_6X86_NOLOCK
+ bool ' Allocate L1 cache lines on write misses' CONFIG_CYRIX_6X86_WTALLOC
+ bool ' Branch Target Buffer features' CONFIG_CYRIX_6X86_BTB
+ bool ' Variable sized paging mechanism (VSPM)' CONFIG_CYRIX_6X86_VSPM
+ fi
+fi
+endmenu
+
mainmenu_option next_comment
comment 'Loadable module support'
bool 'Enable loadable module support' CONFIG_MODULES
@@ -41,11 +69,6 @@
tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA
fi

-choice 'Processor type' \
- "386 CONFIG_M386 \
- 486 CONFIG_M486 \
- Pentium CONFIG_M586 \
- PPro CONFIG_M686" Pentium
bool 'Video mode selection support' CONFIG_VIDEO_SELECT

tristate 'Parallel port support' CONFIG_PARPORT
diff -urN --exclude=.* linux-2.1.62/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.1.62/arch/i386/defconfig Thu Oct 30 18:22:07 1997
+++ linux/arch/i386/defconfig Mon Nov 3 17:17:31 1997
@@ -8,6 +8,23 @@
# CONFIG_EXPERIMENTAL is not set

#
+# Processor options
+#
+# CONFIG_M386 is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+CONFIG_M686=y
+CONFIG_CYRIX=y
+CONFIG_CYRIX_SUSP_HLT=y
+# CONFIG_CYRIX_FAST_IO is not set
+# CONFIG_CYRIX_5X86 is not set
+# CONFIG_CYRIX_6X86 is not set
+# CONFIG_CYRIX_6X86_NOLOCK is not set
+# CONFIG_CYRIX_6X86_WTALLOC is not set
+# CONFIG_CYRIX_6X86_BTB is not set
+# CONFIG_CYRIX_6X86_VSPM is not set
+
+#
# Loadable module support
#
CONFIG_MODULES=y
@@ -28,10 +45,6 @@
CONFIG_BINFMT_AOUT=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
-# CONFIG_M386 is not set
-# CONFIG_M486 is not set
-# CONFIG_M586 is not set
-CONFIG_M686=y
# CONFIG_VIDEO_SELECT is not set
# CONFIG_PARPORT is not set

diff -urN --exclude=.* linux-2.1.62/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- linux-2.1.62/arch/i386/kernel/head.S Tue Aug 5 09:21:29 1997
+++ linux/arch/i386/kernel/head.S Mon Nov 3 17:13:52 1997
@@ -135,13 +135,80 @@
checkCPUtype:
#endif

+ movl $-1,SYMBOL_NAME(have_cpuid) # -1 for no CPUID initially
+
/* check if it is 486 or 386. */
/*
* XXX - this does a lot of unnecessary setup. Alignment checks don't
* apply at our cpl of 0 and the stack ought to be aligned already, and
* we don't need to preserve eflags.
*/
- movl $3, SYMBOL_NAME(x86)
+ /*
+ * A Cyrix preserves flags in cases where other CPUs change
+ * them in undefined ways. We need to know this since we may
+ * need to enable the CPUID instruction at least. (Cyrix chips
+ * prior to M2 have CPUID disabled by default, the Cx486s
+ * didn't have it at all.)
+ */
+ xor %ax,%ax
+ sahf
+ movb $5,%ax
+ movb $2,%bx
+ div %bl
+ lahf
+ cmpb $2,%ah
+ jne ncyrix
+
+ /*
+ * It behaves like a Cyrix so put "Cyrix" in the vendor id
+ * field. It may be overwritten later with the real thing
+ * if CPUID works.
+ */
+ movl $0x69727943,SYMBOL_NAME(x86_vendor_id) # low 4 chars
+ movl $0x00000078,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
+
+#ifdef CONFIG_CYRIX
+ /*
+ * N.B. The pattern of accesses to 0x22 and 0x23 is *important*
+ * so do not try and "optimise" it! For the same reason we
+ * do all this with interrupts off just to be sure.
+ */
+#define setCx86(reg, val) \
+ movb reg,%ax; \
+ outb %ax,$0x22; \
+ movb val,%ax; \
+ outb %ax,$0x23
+
+#define getCx86(reg) \
+ movb reg,%ax; \
+ outb %ax,$0x22; \
+ inb $0x23,%ax
+
+ cli
+ getCx86($0xc3) # get CCR3
+ movb %ax,%cx # Save old value
+ movb %ax,%bx
+ andb $0x0f,%bx # Enable all config registers (for CCR4 access)
+ orb $0x10,%bx
+ setCx86($0xc3,%bx)
+
+#ifdef CONFIG_CYRIX_SUSP_HLT
+ getCx86($0xc2) # CCR2 |= SUSP_HLT
+ orb $8,%ax
+ movb %ax,%bx
+ setCx86($0xc2,%bx)
+#endif
+
+ getCx86($0xe8) # CCR4 |= CPUID | DTE_EN
+ orb $0x90,%ax
+ movb %ax,%bx
+ setCx86($0xe8,%bx)
+
+ setCx86($0xc3,%cx) # Restore old CCR3
+ sti
+#endif /* CONFIG_CYRIX */
+
+ncyrix: movl $3, SYMBOL_NAME(x86)# at least 386
pushfl # push EFLAGS
popl %eax # get EFLAGS
movl %eax,%ecx # save original EFLAGS
@@ -153,7 +220,8 @@
xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed
je is386
- movl $4,SYMBOL_NAME(x86)
+
+ movl $4,SYMBOL_NAME(x86)# at least 486
movl %ecx,%eax
xorl $0x200000,%eax # check ID flag
pushl %eax
@@ -161,14 +229,23 @@
pushfl # 487SX we can't change it
popl %eax
xorl %ecx,%eax
- andl $0x200000,%eax
- je is486
-isnew: pushl %ecx # restore original EFLAGS
+ pushl %ecx # restore original EFLAGS
popfl
- incl SYMBOL_NAME(have_cpuid) # we have CPUID
+ andl $0x200000,%eax
+ je nocpuid
+
+ /* get vendor info */
+ xorl %eax, %eax # call CPUID with 0 -> return vendor ID
+ .byte 0x0f, 0xa2 # CPUID
+ movl %eax,SYMBOL_NAME(have_cpuid) # save CPUID level
+ movl %ebx,SYMBOL_NAME(x86_vendor_id) # lo 4 chars
+ movl %edx,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
+ movl %ecx,SYMBOL_NAME(x86_vendor_id)+8 # last 4 chars
+
+ cmpl $0,%eax # do we have processor info as well?
+ je nocpuid
+
/* get processor type */
- # LINUS WE HAVE A BUG HERE - MUST CHECK WITH
- # CPUID#0 THAT CPUID#1 IS SUPPORTED...
movl $1, %eax # Use the CPUID instruction to
.byte 0x0f, 0xa2 # check the processor type
movb %al, %cl # save reg for future use
@@ -180,23 +257,162 @@
andb $0x0f, %cl # mask mask revision
movb %cl,SYMBOL_NAME(x86_mask)
movl %edx,SYMBOL_NAME(x86_capability)
- /* get vendor info */
- xorl %eax, %eax # call CPUID with 0 -> return vendor ID
- .byte 0x0f, 0xa2 # CPUID
- movl %ebx,SYMBOL_NAME(x86_vendor_id) # lo 4 chars
- movl %edx,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
- movl %ecx,SYMBOL_NAME(x86_vendor_id)+8 # last 4 chars

- movl %cr0,%eax # 486+
- andl $0x80000011,%eax # Save PG,PE,ET
- orl $0x50022,%eax # set AM, WP, NE and MP
- jmp 2f
-is486: pushl %ecx # restore original EFLAGS
- popfl
- movl %cr0,%eax # 486
+ cmpl $0x444d4163,SYMBOL_NAME(x86_vendor_id)+8 # "[Authenti]cAMD"?
+ jne nocpuid
+
+ orb $0x20,SYMBOL_NAME(x86) # Flag as AMD
+ cmpb $0x25,SYMBOL_NAME(x86) # K5 model 0 has swapped
+ jne is486 # feature flags
+ andl $0x00000200,%edx # move bit 9 to bit 13
+ roll $4,%edx # and clear bit 9
+ orl %edx,SYMBOL_NAME(x86_capability)
+ andl $0xfffffdff,SYMBOL_NAME(x86_capability)
+ jmp is486
+
+nocpuid:
+ /*
+ * Even if we had CPUID Cyrix tries to look compatible with
+ * Intel so we have to go elsewhere for the nitty gritty.
+ */
+ cmpl $0x69727943,SYMBOL_NAME(x86_vendor_id) # "Cyri[x.*]"?
+ jne is486 # maybe ...
+
+chkdevid:
+ orb $0x10,SYMBOL_NAME(x86) # Flag as Cyrix
+ movb $0xfe,SYMBOL_NAME(x86_model) # Generic Cx486?
+ movb $0,SYMBOL_NAME(x86_mask)
+
+#ifdef CONFIG_CYRIX
+ cli # Test for DEVID
+ getCx86($0xc3) # by writing CCR3
+ movb %ax,%cx
+ movb %ax,%bx
+ orb $0x80,%bx
+ setCx86($0xc3,%bx)
+ getCx86($0xc0) # dummy to change bus
+ getCx86($0xc3)
+ sti
+ cmp %ax,%cx
+ je is486 # not writable == no DEVID
+
+ cli
+ setCx86($0xc3,%cx) # restore CCR3
+
+ getCx86($0xff) # get DEVID in preference to any CPUID
+ movb %al,SYMBOL_NAME(x86_mask)
+ getCx86($0xfe)
+ movb %al,SYMBOL_NAME(x86_model)
+ sti
+
+#if defined(CONFIG_CYRIX_5X86) || defined(CONFIG_CYRIX_6X86)
+ andb $0xf0,%al
+# ifdef CONFIG_CYRIX_6X86
+ cmpb $0x30,%al
+ je is6x86
+# endif
+# ifdef CONFIG_CYRIX_5X86
+ cmpb $0x20,%al
+ je is5x86
+# endif
+ /* Cx486 or something beyond a 6x86 (M2 or better). Note that
+ * the Cx486 also have performance features we could tweak
+ * but given the problems with [56]x86, the number of Cx486
+ * variants, the fact that the Cx486 is pretty well dead
+ * now and the fact that I have no Cx486 myself I haven't
+ * risked it. Nor have I looked at the M2 in any detail yet.
+ */
+ jmp is486
+#endif
+
+#if defined(CONFIG_CYRIX_5X86) || defined(CONFIG_CYRIX_FAST_IO)
+ /* Special set up for 5x86 */
+is5x86:
+ cli
+ movb %cx,%bx
+ andb $0x0f,%bx # Enable all config registers
+ orb $0x10,%bx
+ setCx86($0xc3,%bx)
+
+ getCx86($0x20) # PCR0 |= LSSER | BTB_EN
+ orb $0x82,%ax # LOOP_EN is broken, RSTK_EN shows no benefit
+ movb %ax,%bx # and LSSER=0 could break memory mapped
+ setCx86($0x20,%bx) # devices - we have no way of knowing)
+
+#ifdef CONFIG_CYRIX_FAST_IO
+ getCx86($0xe8) # CCR4: IORT=0 (nodelay)
+ andb $0xf1,%ax
+ movb %ax,%bx
+ setCx86($0xe8,%bx)
+#endif
+
+ setCx86($0xc3,%cx) # restore CCR3
+ sti
+ jmp is486
+#endif
+
+#if defined(CONFIG_CYRIX_6X86) || defined(CONFIG_CYRIX_FAST_IO)
+ /* Special set up for 6x86 */
+is6x86:
+ cli
+ movb %cx,%bx
+ andb $0x0f,%bx # Enable all config registers
+ orb $0x10,%bx
+ setCx86($0xc3,%bx)
+
+#if !defined(__SMP__) && defined(CONFIG_CYRIX_6X86_NOLOCK)
+ getCx86($0xc1) # CCR1 |= NO_LOCK
+ orb $0x10,%ax
+ movb %ax,%bx
+ setCx86($0xe8,%bx)
+#endif
+
+#ifdef CONFIG_CYRIX_FAST_IO
+ getCx86($0xe8) # CCR4: IORT=7 (nodelay)
+ orb $0x97,%ax
+ movb %ax,%bx
+ setCx86($0xe8,%bx)
+#endif
+
+ getCx86($0xe9) # CCR5 &= ~SLOP
+ andb $0xfd,%ax
+#ifdef CONFIG_CYRIX_6X86_WTALLOC
+ orb $0x01,%ax # CCR5 |= WT_ALLOC
+#endif
+ movb %ax,%bx
+ setCx86($0xe9,%bx)
+
+#ifdef CONFIG_CYRIX_6X86_BTB # IBM documentation, no Cyrix docs
+ getCx86($0x30) # Enable test register opcodes
+ movb %ax,%dx
+ orb $0x40,%ax
+ movb %ax,%bx
+ setCx86($0x30,%bx)
+
+ mov $0x28,%ebx # Enable FAR COFs in BTB
+ .byte 0x0f,0x26,0xcb # mov %ebx,%tr1
+ .byte 0x0f,0x24,0xd0 # mov %tr2,%eax
+#if 0
+ and $0xfffffffd,%eax # according to Cyrix/IBM documentation
+#else
+ and $0xfffffff8,%eax # according to 6x86opt
+ or $0x00000070,%eax
+#endif
+ .byte 0x0f,0x26,0xd0 # mov %eax,%tr2
+
+ setCx86($0x30,%dx) # Disable test register opcodes
+#endif /* CONFIG_CYRIX_6X86_BTB */
+
+ setCx86($0xc3,%cx) # restore CCR3
+ sti
+#endif /* CONFIG_CYRIX_6X86 or CONFIG_CYRIX_FAST_IO */
+#endif /* CONFIG_CYRIX */
+
+is486: movl %cr0,%eax # 486 or better
andl $0x80000011,%eax # Save PG,PE,ET
orl $0x50022,%eax # set AM, WP, NE and MP
jmp 2f
+
is386: pushl %ecx # restore original EFLAGS
popfl
movl %cr0,%eax # 386
diff -urN --exclude=.* linux-2.1.62/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.1.62/arch/i386/kernel/setup.c Fri Sep 19 21:46:38 1997
+++ linux/arch/i386/kernel/setup.c Mon Nov 3 17:13:53 1997
@@ -42,7 +42,7 @@
char x86_mask = 0; /* set by kernel/head.S */
int x86_capability = 0; /* set by kernel/head.S */
int fdiv_bug = 0; /* set if Pentium(TM) with FP bug */
-int have_cpuid = 0; /* set if CPUID instruction works */
+int have_cpuid = -1; /* CPUID level (-1 if no CPUID) */

char x86_vendor_id[13] = "unknown";

@@ -275,11 +275,83 @@
return NULL;
}

-static const char * getmodel(int x86, int model)
+static const char * cyrixmodel(unsigned int nr)
+{
+ static char nbuf[32];
+
+ /* Note that some of the possibilities this decoding allows
+ * have never actually been manufactured - but those that
+ * do actually exist are correctly decoded.
+ */
+ if (nr < 0x20) {
+ strcpy(nbuf, "Cx486");
+ if (!(nr & 0x10)) {
+ sprintf(nbuf+5, "%c%s%c",
+ (nr & 0x01) ? 'D' : 'S',
+ (nr & 0x04) ? "Rx" : "LC",
+ (nr & 0x02) ? '2' : '\000');
+ } else if (!(nr & 0x08)) {
+ sprintf(nbuf+5, "S%s%c",
+ (nr & 0x01) ? "2" : "",
+ (nr & 0x02) ? 'e' : '\000');
+ } else {
+ sprintf(nbuf+5, "DX%c",
+ nr == 0x1b ? '2'
+ : (nr == 0x1f ? '4' : '\000'));
+ }
+ return nbuf;
+ } else if (nr >= 0x20 && nr <= 0x4f) { /* 5x86, 6x86 or Gx86 */
+ sprintf(nbuf, "%cx86 %cx Core/Bus Clock",
+ "??56G"[nr>>4],
+ "12??43"[nr & 0x05]);
+ return nbuf;
+ } else if (nr >= 0x50 && nr <= 0x5f) { /* Cyrix M2 */
+ sprintf(nbuf, "M2 %c%sx Core/Bus Clock",
+ "12233445"[nr & 0x07],
+ (nr && !(nr&1)) ? ".5" : "");
+ return nbuf;
+ }
+
+ /* Probably 0xfd (Cx486[SD]LC with no ID register)
+ * or 0xfe (Cx486 A step with no ID register).
+ */
+ return "Cx486";
+}
+
+static const char * getmodel(int x86, int model, int have_cpuid)
{
const char *p = NULL;
- static char nbuf[12];
- switch (x86) {
+ static char nbuf[49];
+
+ if ((x86 & 0xf0) == 0x10) { /* Cyrix */
+ p = cyrixmodel(model);
+ } else if ((x86 & 0xf0) == 0x20) { /* AMD */
+ /* Actually we must have cpuid or we could never have
+ * figured out that this was AMD from the vendor info :-).
+ */
+ if (have_cpuid < 0)
+ p = "Am486";
+ else {
+ int n, dummy;
+ cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
+ if (!n) {
+ if ((x86 & 0x0f) == 4)
+ p = i486model(model);
+ else if ((x86 & 0x0f) == 5)
+ p = "AMD-K5 (Model 0)";
+ } else {
+ int *v = (int *)nbuf;
+ cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+ cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+ cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+ nbuf[48] = '\0';
+ p = nbuf;
+ }
+ }
+ } else switch (x86) { /* Intel */
+ case 0:
+ p = "unknown";
+ break;
case 4:
p = i486model(model);
break;
@@ -330,28 +402,31 @@
#endif

len += sprintf(buffer+len,"processor\t: %d\n"
- "cpu\t\t: %c86\n"
+ "cpu family\t: %c\n"
"model\t\t: %s\n"
"vendor_id\t: %s\n",
CPUN,
- CD(x86)+'0',
- CD(have_cpuid) ?
- getmodel(CD(x86), CD(x86_model)) :
- "unknown",
+ (CD(x86) & 0x0f)+'0',
+ getmodel(CD(x86), CD(x86_model), CD(have_cpuid)),
CD(x86_vendor_id));

- if (CD(x86_mask))
- len += sprintf(buffer+len,
- "stepping\t: %d\n",
- CD(x86_mask));
- else
+ if (CD(x86_mask)) {
+ if ((CD(x86) & 0xf0) == 0x10)
+ len += sprintf(buffer+len,
+ "stepping\t: %d rev %d\n",
+ CD(x86_mask) >> 4,
+ CD(x86_mask) & 0x0f);
+ else
+ len += sprintf(buffer+len,
+ "stepping\t: %d\n",
+ CD(x86_mask));
+ } else
len += sprintf(buffer+len,
"stepping\t: unknown\n");

- sep_bug = CD(have_cpuid) &&
+ sep_bug = CD(x86) == 0x06 && /* Intel family 6 */
+ CD(have_cpuid) >= 0 &&
(CD(x86_capability) & 0x800) &&
- !memcmp(x86_vendor_id, "GenuineIntel", 12) &&
- CD(x86) == 6 &&
CD(x86_model) < 3 &&
CD(x86_mask) < 3;

@@ -361,7 +436,7 @@
"sep_bug\t\t: %s\n"
"fpu\t\t: %s\n"
"fpu_exception\t: %s\n"
- "cpuid\t\t: %s\n"
+ "cpuid level\t: %d\n"
"wp\t\t: %s\n"
"flags\t\t:",
CD(fdiv_bug) ? "yes" : "no",
@@ -370,7 +445,7 @@
CD(hard_math) ? "yes" : "no",
(CD(hard_math) && ignore_irq13)
? "yes" : "no",
- CD(have_cpuid) ? "yes" : "no",
+ CD(have_cpuid),
CD(wp_works_ok) ? "yes" : "no");

for ( i = 0 ; i < 32 ; i++ ) {
diff -urN --exclude=.* linux-2.1.62/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- linux-2.1.62/arch/i386/mm/init.c Sat Sep 13 10:11:17 1997
+++ linux/arch/i386/mm/init.c Mon Nov 3 17:13:53 1997
@@ -171,6 +171,67 @@
unsigned long tmp;
unsigned long address;

+#if defined(CONFIG_CYRIX) && defined(CONFIG_CYRIX_6X86_VSPM) && !defined(__SMP__)
+ unsigned long vspm_max = __va(0);
+
+ /* If this is a Cyrix 6x86 we use the variable size paging
+ * mechanism (VSPM) to map physical memory at 0xc0000000.
+ * Note that VSPM pages are stored on the CPU only so this
+ * needs to be done for each processor in a multi-processor
+ * system. If we have a mixture of processors we would also
+ * need to set up the traditional page tables for them.
+ * Note also that VSPM pages will be global to all memory
+ * spaces since they are not stored in the normal page
+ * directories.
+ */
+ if ((x86 & 0xf0) == 0x10 && (x86_model & 0xf0) == 0x30) {
+ int vspm_index = 0;
+
+ do {
+ unsigned long mem_size;
+
+ mem_size = 4096;
+ while (vspm_max+mem_size < end_mem)
+ mem_size <<= 1;
+ if (vspm_max+mem_size > end_mem)
+ if ((mem_size >>= 1) < 4096)
+ break;
+
+ asm( "movl %0,%%eax\n"
+ "movl %%eax,%%tr7\n"
+ "movl $0x00000004,%%eax\n"
+ "movl %%eax,%%tr6\n"
+ "movl %1,%%eax\n"
+ "movl %%eax,%%tr7\n"
+ "movl %2,%%eax\n"
+ "movl %%eax,%%tr6\n"
+ : /* no outputs */
+ : "g" ((((mem_size-1) & 0xfffff000)) | (vspm_index<<7)),
+ "g" ((__pa(vspm_max) & 0xfffff000) | (vspm_index<<7)),
+ "g" ((vspm_max & 0xfffff000) | 0x00000cd6)
+ : "eax", "cc"
+ );
+
+ vspm_max += mem_size;
+
+#if 1
+ /* Just use one VSPM page for now, anything
+ * over will be traditionally paged.
+ * (See Documentation/Cyrix.)
+ */
+ break;
+#endif
+ } while (vspm_max < end_mem && vspm_index++ < 4);
+
+ /* Write protect does work correctly but the test
+ * will fail because we can't map just page 0 read
+ * only from under the VSPM big page. If we didn't
+ * know before we do now.
+ */
+ wp_works_ok = 1;
+ }
+#endif
+
/*
* Physical page 0 is special; it's not touched by Linux since BIOS
* and SMM (for laptops with [34]86/SL chips) may need it. It is read
@@ -235,6 +296,17 @@
address += 4*1024*1024;
continue;
}
+
+#if defined(CONFIG_CYRIX) && defined(CONFIG_CYRIX_6X86_VSPM) && !defined(__SMP__)
+ if ((x86 & 0xf0) == 0x10 /* Cyrix */
+ && (x86_model & 0xf0) == 0x30 /* 6x86 */
+ && (address + PAGE_SIZE*PTRS_PER_PTE) < vspm_max) { /* within VSPM mappings */
+ pg_dir++;
+ address += PAGE_SIZE * PTRS_PER_PTE;
+ continue;
+ }
+#endif
+
/*
* We're on a [34]86, use normal page tables.
* pg_table is physical at this point
@@ -247,12 +319,18 @@

pgd_val(*pg_dir) = _PAGE_TABLE | (unsigned long) pg_table;
pg_dir++;
+
/* now change pg_table to kernel virtual addresses */
pg_table = (pte_t *) __va(pg_table);
for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) {
pte_t pte = mk_pte(address, PAGE_KERNEL);
+#if defined(CONFIG_CYRIX) && defined(CONFIG_CYRIX_6X86_VSPM) && !defined(__SMP__)
+ if (address < vspm_max || address >= end_mem)
+ pte_val(pte) = 0;
+#else
if (address >= end_mem)
pte_val(pte) = 0;
+#endif
set_pte(pg_table, pte);
address += PAGE_SIZE;
}
diff -urN --exclude=.* linux-2.1.62/include/asm/bugs.h linux/include/asm/bugs.h
--- linux-2.1.62/include/asm/bugs.h Mon Oct 27 17:49:14 1997
+++ linux/include/asm/bugs.h Mon Nov 3 17:25:11 1997
@@ -173,5 +173,5 @@
check_hlt();
check_popad();
check_amd_k6();
- system_utsname.machine[1] = '0' + x86;
+ system_utsname.machine[1] = '0' + (x86 & 0x0f);
}
diff -urN --exclude=.* linux-2.1.62/include/asm/processor.h linux/include/asm/processor.h
--- linux-2.1.62/include/asm/processor.h Tue May 13 22:41:17 1997
+++ linux/include/asm/processor.h Mon Nov 3 17:13:53 1997
@@ -16,7 +16,7 @@
*/

extern char hard_math;
-extern char x86; /* lower 4 bits */
+extern char x86; /* upper 4 bits=vendor, lower 4 bits=family */
extern char x86_vendor_id[13];
extern char x86_model; /* lower 4 bits */
extern char x86_mask; /* lower 4 bits */
@@ -174,5 +174,21 @@

#define init_task (init_task_union.task)
#define init_stack (init_task_union.stack)
+
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ __asm__("movl %4,%%eax\n\t"
+ ".byte 0x0f, 0xa2\n\t"
+ "movl %%eax,%0\n\t"
+ "movl %%ebx,%1\n\t"
+ "movl %%ecx,%2\n\t"
+ "movl %%edx,%3\n\t"
+ : "=m" (*eax),
+ "=m" (*ebx),
+ "=m" (*ecx),
+ "=m" (*edx)
+ : "g" (op)
+ : "eax", "ebx", "ecx", "edx", "cc");
+}

#endif /* __ASM_I386_PROCESSOR_H */
diff -urN --exclude=.* linux-2.1.62/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- linux-2.1.62/include/asm-i386/bugs.h Mon Oct 27 17:49:14 1997
+++ linux/include/asm-i386/bugs.h Mon Nov 3 17:25:11 1997
@@ -173,5 +173,5 @@
check_hlt();
check_popad();
check_amd_k6();
- system_utsname.machine[1] = '0' + x86;
+ system_utsname.machine[1] = '0' + (x86 & 0x0f);
}
diff -urN --exclude=.* linux-2.1.62/include/asm-i386/processor.h linux/include/asm-i386/processor.h
--- linux-2.1.62/include/asm-i386/processor.h Tue May 13 22:41:17 1997
+++ linux/include/asm-i386/processor.h Mon Nov 3 17:13:53 1997
@@ -16,7 +16,7 @@
*/

extern char hard_math;
-extern char x86; /* lower 4 bits */
+extern char x86; /* upper 4 bits=vendor, lower 4 bits=family */
extern char x86_vendor_id[13];
extern char x86_model; /* lower 4 bits */
extern char x86_mask; /* lower 4 bits */
@@ -174,5 +174,21 @@

#define init_task (init_task_union.task)
#define init_stack (init_task_union.stack)
+
+extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+{
+ __asm__("movl %4,%%eax\n\t"
+ ".byte 0x0f, 0xa2\n\t"
+ "movl %%eax,%0\n\t"
+ "movl %%ebx,%1\n\t"
+ "movl %%ecx,%2\n\t"
+ "movl %%edx,%3\n\t"
+ : "=m" (*eax),
+ "=m" (*ebx),
+ "=m" (*ecx),
+ "=m" (*edx)
+ : "g" (op)
+ : "eax", "ebx", "ecx", "edx", "cc");
+}

#endif /* __ASM_I386_PROCESSOR_H */