Module to Enable Advanced Features in Cyrix 5x86  ver 1.0c beta
---------------------------------------------------------------


Table of Contents
-----------------

o Table of Contents
o Prelude
o Objective
o What's New in Version 1.0beta
o Sources of Info
o Prerequisites
o How to Use It (new method)
o How to Use It (old method)
o Module Symbols (Options)
o Order of Execution
o Technical Info (yeah, right.)
o History
o Questions?


Prelude
-------

Disclaimer: I am not responsible if this software, directly or
indirectly, causes your CPU to meltdown, your Linux filesystem to
be totally corrupted, your parents to disown you, your dog to leave
you, or any other bad things to happen to you before, during and
after you used this software.

Also, the next line will be referenced several times:

REMINDER 1:
I have virtually no experience in kernel hacking, and just a little
experience in C.  So, it is more than likely that many things that
I have written, coded, assumed, etc., could be completely wrong
or at least very stupid.  Keep that in mind.  (Suggestions and
corrections will be most welcomed, of course.)

Ok.  That being done with, let's have a little fun.


Objective
---------

The aim of this software is to enable the _advanced_ features of your
Cyrix 5x86 cpu, especially if the motherboard BIOS doesn't enable it.
Of course, the reason that it is not enabled could be that it may
be unstable and causes BAD THINGS (TM) to happen.  The instability
might not be caused by your incompatible motherboard, or it might
be caused by the cpu itself (yes, some revisions of the cpu have
bugs that make them unstable when certain features are turned on,
or so I have heard.)  But if you want to chance it, then read on.
Otherwise, go play boggles.

This program is a shameless hack of Christopher Lau's CxPatch030
for enabling the 1KB cache in some Cyrix 486 CPUs.  At this stage,
however, there is actually very little of Christopher's code left
in cx5x86.c and cx5x86.h, if there are any at all.  The bogo.c,
however, is still mostly Christopher's original version.  My original
source of information is the C't magazine's ctchipz.exe DOS program.
My most important info comes from the docs available from IBM's
Microelectronic Division web site.  If you are faint of heart,
then let me reference you to REMINDER 1 above.  But it does work
on my machine and if you look at the source, you will notice that
it is really simple and straight forward.

What's New in Version 1.0beta
-----------------------------

1) User friendly way to fiddle with the registers.  Just compile the
   module as is, and then use it as some kind of funky executable:

     modprobe cx5x86 btb_en=1 show_reg=1 ; modprobe -r cx5x86

   This way, you don't need to recompile the module everytime you
   want to experiment with another settings.  Cool, eh?

   Of course, if you prefer the old way of doing it, you can always
   edit the cxdefaults() function in cx5x86.c and then use

     modprobe cx5x86 use_def=1; modprobe -r cx5x86

2) Cleaned up the #include order, so let's hope we won't have any more
   of those module version not found errors ;-)

3) Improved Makefile so that it will automatically install the module
   in the right place if you do:

     make install

4) The L1 cache WB is disabled by default.  If you want it, edit the
   cx5x86.c file and uncomment the #define L1_WB line.

5) Cleaner code (I hope) so that it can be easily hacked to include
   support for the 6x86 and DLC, a kind of grand unified Cyrix hack
   for Linux.  Of course, I have no idea if the 6x86 needs the hack
   or not, as I suspect the motherboards have optimal BIOS settings
   for the 6x86.  The DLC, of course, already have a hack from
   Christopher.


Sources of Info
---------------

Main source is from a couple of documents from IBM's Microelectronic
Division web site: (1) 5x86 BIOS Writer's Guide (2) 5x86 Databook.

Original source of info is from C't magazine's ctchipz.exe DOS
program.

Plus various net rumours, etc.


Prerequisites
-------------

The program will compile as a module.  

I have said that kernel patches could probably be done, and I did
receive several inquiries about kernel patches but due to several
reasons, I doubt that it can be done, or at least I doubt if I have
the time and skill to do it.  The main reason is that there are too
many varieties of motherboards out there that have varying degrees
of support for the Cyrix 5x86.  A setting that works well on one
motherboard might be catastrophic on another.  Detection for various
motherboards is not easy (if possible at all).  Even if detection
can be done, there must be a database of what settings work with what
motherboard, and this can be a daunting process.  Anyone is welcomed
to try, of course.

To use the program, you need to fulfill the following prerequisites:

1) have gcc
2) have your kernel source available (untarred in the proper place)
3) have the modules utilities installed (use the version that is
   compatible with your kernel)
4) have the Cyrix 5x86 cpu, of course 8^)


How to Use It (new method)
--------------------------

NOTE: There has been much changes since version 002a.  Please
      read the instructions again.

There are several ways to use this module.  The new way is to compile
the module and then invoke the module with modprobe along with the
settings, like:

        modprobe cx5x86 lsser=1 show_reg=1 pcr0=xxxx1xxx; \
        modprobe -r cx5x86

For the old method (using hard compiled defaults) see next section.

1) make all

If the program compiles fine, then you can run it.  But if this is the
first time, I would strongly suggest that you sync everything, and
unmount all unnecessary devices.  Paranoia is a good thing here.

Now type:

2) modprobe cx5x86.o use_def=1 ; modprobe -r cx5x86

If the system didn't crash (yet) or give you the famous kernel
opps messages, then the module was run successfully.  The above
command is using the default that I have hard-coded into the module
(if you have not changed the module).  It is equivalent to

modprobe cx5x86.o btb_en=1 lsser=0 mem_byp=1 fp_fast=1 show_reg=1; \
modprobe -r cx5x86

You should also see the new settings of your registers.

Now, for the best part, type:

3) modprobe bogo.o ; modprobe -r bogo

And then type dmesg.  If you are lucky, then you should get bogomips
in the range of 100 (for 100MHz version). :-)

If you are comfortable that your system is stable enough, you can put
the file in /lib/modules/... by typing

4) make install; depmod -a

Once it is in /lib/modules/..., you can use it from anywhere with
modprobe cx5x86 whateveryouwant; modprobe -r cx5x86.  Note that you
don't need the .o anymore.

To automate the stuff to run at boot, you can hacked around with
/etc/rc.d/* or /etc/init.d/* and make an appropriate rc.cx5x86.
An example is supplied which you should edit to customize your
particular set-up.

The bogomips at boot-up is done before the module was run and
so does not reflect the advanced features setting of your 5x86.

Please read the section Module Symbols (Options) for more info.


How to Use It (old method)
--------------------------

The old way means that settings are hard coded into the cx5x86.c.

To do that:

1) Edit cx5x86.c, in the function cxdefaults(). Information on how to
   do that is documented in that function and should be easy
   to follow.

Then compile the stuff with

2) make all

To use the defaults that you have compiled in, try something like:

        modprobe cx5x86 use_def=1; modprobe -r cx5x86

If you don't like the use_def=1 line, you can edit cx5x86.h and
change the line to

   static int use_def = 1;

To install the module in /lib/modules/..., try

3) make install; depmod -a

As before, you can hack /etc/rc* stuff to automatically run the
module upon boot up.  A sample rc.cx5x86 is supplied which you
should edit to fit your needs.

The bogomips at boot-up is done before the module was run and
so does not reflect the advanced features setting of your 5x86.

Please read the section Module Symbols (Options) for more info.


Module Symbols (Options)
------------------------

The syntax to use the cx5x85 module is:

modprobe cx5x86 [symbol=value [symbol=value [...]]]; modprobe -r cx5x86

The options that the module accepts are actually the module symbols,
much like modprobe ne irq=10 stuff.  The valid symbols are:

1) show_reg
   0 (default) don't show register settings
   1 show register settings

2) use_def
   0 (default) don't use defaults settings in cxdefaults()
   1 use defaults settings in cxdefaults()

3) verb
   0 (default) don't show too much junk
   1 show the junk

4) Various register flags like lsser, btb_en, fp_fast, etc.
   -1 (default) don't do anything (i.e., no action to set to 0 or 1)
   0 clear the flag (set to 0)
   1 set the flag (set to 1)

5) Various registers like pcr0, ccr1, etc.
   "" don't do anything
   xxxx1xxx set the 3rd bit to 1
   xxxxxx0x set the 1st bit to 0

   Note that the settings for 5) must be a string. Previously
   I thought that strings need to be enclosed in qoutes, but I
   was wrong.  It seems that the kernel will guess what kind of
   data type it is.  Thus, something like xxx1xxx00 will be ok,
   because the first character is only interpretable as a string.
   Something like 00001001 will be interpreted as an integer,
   which will become a char pointer of that address!  Something
   like 0x000011 is also interpreted as a hex integer!  The best
   solution is always to start your string with x, e.g., xxxx1x01.
   If you need to set something like 1xxxxxxx, use x1xxxxxxx as
   the string will be truncated to 8 characters or less.

   5) is actually for compatibility purposes.  Most relevant settings
   can be accomplished with 4).

Some examples:

1) To enable branch target buffer, you can use

   modprobe cx5x85 btb_en=1; modprobe -r cx5x86

   or

   modprobe cx5x85 pcr0=xxxx1xxx; modprobe -r cx5x86

2) To see what settings you have now, try

   modprobe cx5x86 show_reg=1; modprobe -r cx5x86


Order of Execution
------------------

The order of executions of the settings are:

1) Those that use setcxreg() in cxdefaults()

2) Those that change the symbols to non-default values.  Changes
   are collected and then executed one after another.  Thus, if you
   specify contradictory settings, then:

   a) All symbols will be overwritten by those (if any) in
      cxdefaults() if you load the module with use_def=1.

   b) Settings with method 5) in the Module Symbols (Options) section
      will not interfere with method 4); those set with method 5)
      will be acted upon first.

   The order of action on the symbols/settings is determined by the
   arrays of structure of cxreg[] and cxbit[].  If you need to have
   a certain order of execution, either load cx5x86 several times
   or use cxdefaults().


Technical Info (yeah, right.)
-----------------------------

The idea behind the program is really, really simple.  The concept
is this: the CPU features are controlled by the settings of the CPU
CR0 register and other registers (probably among other things -- I
claim ignorance here, remember REMINDER 1).  The CR0 register can be
changed by writing the %cr0 register directly using assembly/machine
code.  The other registers can be changed by writing to two ioports,
0x22 and 0x23 (hexadecimal, please).  0x22 is the index port, which
means that if you write a 1-byte value to it, you can reference
the information the 1-byte value on the index port points to, by
using 0x23.  For example, you want to read the Configuration Control
Register 1, which is index port 0xc1.  So you put the value 0xc1
into ioport 0x22 (which is the index port), and read the settings
of the Configuration Control Register 1 from ioport 0x23.  To change
an index setting, just write to ioport 0x23 instead of reading.

The command to write to ioport is outb_p(value, ioport), and to read
is simply inb_p(ioport), which will return the 1-byte value of the
ioport.

I have tried to make the program as informative as possible with
comments.  The default configuration of the module, invoked with
use_def=1, is just to:

a) enable branch prediction (BTB=1)
b) enable memory bypassing (MEM_BYP=1)
c) set load/store ordering to weak (LSSER=0)
d) enable fast FPU exception reporting (FP_FAST=1)

Since I have no idea what is good/stable for other machines, it is up
to you to see what works and what doesn't.  As far as I can tell from
the net news, your mileage WILL vary, and probably by a lot, too.  The
default, I _think_, is safe for _most_ boxes, but YMWV!

Personally, I find that if I enable FPU fast exception reporting I can
get an extra 5-10% when doing fpu intensive stuff.  Also, memory
bypassing works wonder for me.  Don't ask me what those means because
I have no idea.

For what it is worth, I have an ASUS PCI/I-486SP3G mainboard with the
5x86-100GP rev 1.3 cpu.  And my settings and bogomips are:

cx5x86: cx5x86 Revision 1.3
cx5x86: Register settings:
PCR0=2 CCR1=0 CCR2=0 CCR3=10 SMAR=0 SMAR0=0 SMAR1=0 SMAR2=0 CCR4=2d PMR=3 DIR0=2d DIR1=13

Calibrating delay loop.. ok - 100.16 BogoMips (tm)

That's 100.16 (sometimes I get 99.42) up from 39.94, for what
it's worth...


History
-------

Never thought that a version 1.0 was ever going to get done, but
here it is.

Version 1.0c:
- fixed bug in setcxreg()
- added patch to update /proc/cpuinfo bogomips in bogo.c, much thanks
  to Richard <richard@radar.demon.co.uk> (Apology to Richard, who I
  can't seem to be able to contact via email and thus can't get his
  family name.)
- fixed the irritating "Unresolved Symbols" message when doing depmod -a

Version 1.0b:
- fixed bug with register specification (e.g., pcr0, ccr4, etc.)
- fixed bug in documentation on how to use them

Version 1.0 beta:
- user friendly way to fiddle with the registers.  Just compile the
  module as is, and then use it as some kind of funky executable.
- cleaned up the #include order, so let's hope we won't have any more
  of those module version not found errors ;-)
- improved Makefile so that it will automatically install the module
  in the right place.
- the L1 cache WB is disabled by default.
- cleaner code (I hope) so that it can be easily hacked to include
  support for the 6x86 and DLC, a kind of grand unified Cyrix hack
  for Linux.

Version 0.02:
- make setting the registers easier so that you don't have to convert
  the #!@$% binary bits to hexadecimal.
- the previous line implies that a bug in the example code in cx5x86.c 
  (version 0.01) which will not compile (if you try it) has been removed.
- included asm routine to set L1 cache to write-back -- thanks to
  Bruce Stough <sbs1@PO6.RV.unisys.com>.
- cx5x86.c and bogo.c are fixed so that they will compile with whatever
  `kernel source' version you have untarred (version 0.01 always compile
  with version 1.2.13) as their module versions.
- cleaned up a little of the code.

Questions?
----------

Send me the bug reports and suggestions, people!  Let's make this the
final version so that I can be rid of this yoke.  I am also looking for

1) a way for the module to automatically unload itself.

If you like the program, buy a GNU T-shirt from the Free Software
Foundation (they have a new one out now), or donate to the XFree86
project, or get a friend to try Linux.  And definitely remove that
last DOS partition from your drive since you don't need DOS to run the
ctchipz.exe program any more...

Good luck!

Edwin _Lim_ Aun Whei
elim@dodo.eng.uci.edu
