6x86 configuration registers ------------------------------------------------------------------------ Cyrix/IBM 6x86 CPUs have 24 configuration registers, divided in 4 functional groups, that are used to set various performance features. The 4 functional groups are: * Configuration Control Registers (CCRs): CCR0 to CCR5. * Address Region Registers (ARRs): ARR0 to ARR7. ARR7 has special settings. * Region Configuration Registers (RCRs): RCR0 to RCR7. Each RCR corresponds to an ARR. * Device Identification Registers(DIRs): DIR0 and DIR1. All registers are single byte, except for the Address Region Registers (ARRs) which are 3 bytes wide. Each register (and each byte in the ARRs) is identified by an index, used to read or write to it. Setting 6x86 registers with gcc assembly code To access one of the registers, a write must be done to I/O port 22h, with the index as the value of the data written. The following instruction must be a read or a write to I/O port 23h, which will then transfer the data from/to the specified configuration register. Additionally, to access ARR0-ARR7, RCR0-RCR7, CCR4 and CCR5, bits (7-4) of CCR3 must be set to 0001b (these bits are called MAPEN(3-0) in the Cyrix/IBM docs). The mechanism seems complicated but in practice it is relatively simple, even if a little awkward. The actual code for the kernel patches is the following: (This macro defines a mechanism for setting a register with index reg to a given value val) #define setCx86(reg, val) \ movb reg,%ax; \ outb %ax,$0x22; \ movb val,%ax; \ outb %ax,$0x23 (This macro defines a mechanism for reading a register with index reg to AX) #define getCx86(reg) \ movb reg,%ax; \ outb %ax,$0x22; \ inb $0x23,%ax And this is an example of using the above macros: cli # disable interrupts getCx86($0xc3) # get CCR3 movb %ax,%cx # Save old value in register ECX movb %ax,%bx andb $0x0f,%bx # Enable access to all config registers orb $0x10,%bx # by setting bits 7-4 to 0001 setCx86($0xc3,%bx) # ... do something setCx86($0xc3,%cx) # reset CCR3 to previous state sti # enable interrupts Note that this short routine must run with interrupts disabled. In the ...do something part one could for example setup ARRs for specific memory regions in one's system. ARR configuration Configuring ARRs is the most important, but also the most involved operation to improve the performance of any Linux system with a 6x86 family CPU. It can be done quite simply with set6x86, but one should at least read the ARR description in the relevant Application Notes (e.g. IBM Application Note 40205) or in the 6x86 Data Book. Usually, ARRs 0 to 3 and ARR7 will have been setup by the BIOS, taking care of setting up the 6x86 for your main memory. All that one will have to do to optimize performance is to setup a separate ARR for the video card(s). Assuming you have set6x86 version 1.3 or later installed on your system, the actual procedure to setup an ARR is not too complicated: 1. Find an unused ARR. 1. Use the 6x86_arr or 6x86_reg utility provided with set6x86 to display the ARR registers settings. 2. Determine the amount of DRAM (Fast Page, EDO or SDRAM) you have on your motherboard. 3. Determine which ARR you are going to setup. If you have a power of 2 amount of DRAM installed on your motherboard (e.g. 16Mb or 32Mb), then ARR6 should be available; otherwise (e.g. 24Mb or 48Mb) ARR5 or ARR4 should be available (see below). 2. Determine the address and size of the Linear Video Frame Buffer (LVFB) of your video card or other memory address region you wish to setup. 3. Determine which RCR settings are recommended for this region of memory. 4. Once you have the information determined in steps 1, 2 and 3, you will be ready to setup the 4 calls to set6x86 to correctly setup an ARR: 1. Two calls are needed to specify the address of the memory region. 2. A third call is needed to specify the size of the memory region. 3. The fourth and last call specifies the settings for the memory region. 5. Note that these calls must take place with MAPEN enabled. See the sample rc.cyrix script included with set6x86. MAPEN must be disabled again after the ARR register is setup. This seems very theoretical so let's see an example configuration: Step 1 - Finding an unused ARR. 6x86_arr reports the following on my system: 6x86 Address Region Register dump: ARR0: address = 0xA0000 , size = 128 KB RCR = 0x9 : not cached, write gathering, ARR1: address = 0xC0000 , size = 256 KB RCR = 0x1 : not cached, ARR2: disabled ARR3: address = 0xA8000 , size = 32 KB RCR = 0x9 : not cached, write gathering, ARR4: disabled ARR5: disabled ARR6: disabled ARR7: address = 0x0 , size = 32 MB RCR = 0xB : cached, weak write ordering, write gathering, As we can see, ARRs 4, 5 and 6 are free. Let's setup ARR6. Step 2 - Find the size and address of the memory region we want to setup an ARR for. In this example, we want to setup an ARR for the Linear Video Frame Buffer of a standard S3 Trio64 V2 video card with 2Mb of EDO video DRAM.We simply type X > -probeonly and this reports various lines on the screen, one of which reads: (--) S3: PCI: Trio64V2 rev 14, Linear FB @ 0xe0000000. Step 3 - Determine RCR settings. Usually this is the simplest possible setting: not cached, write gathering enabled. This results in an RCR value of 0x09. Step 4 - Setup the four calls to set6x86. set6x86 -p 0xD6 0xE0 set6x86 -p 0xD7 0x00 set6x86 -p 0xD8 0x0A set6x86 -p 0xE2 0x09 In this example, D6, D7 and D8 are indexes to ARR6, and E2 is the index to RCR6. D6 and D7 must be loaded with the two most significant bytes of my Linear Video Frame Buffer address 0xE0 and 0x00 respectively. D8 is setup with a value (0x0A) that corresponds to the size of the memory region being setup, in this case 2Mb. If I had 4Mb on my video card, this value would be 0x0B. If I had 1Mb, it would be 0x09; adjust accordingly. Finally, RCR6 is loaded with 0x09, resulting in a non-cached memory region with write gathering enabled. Step 5 - Include the above sequence in rc.local or rc.cyrix, in the part that has MAPEN enabled. Step 6 - Reboot and check that the new ARR is correctly configured by running 6x86_arr again: 6x86 Address Region Register dump: ARR0: address = 0xA0000 , size = 128 KB RCR = 0x9 : not cached, write gathering, ARR1: address = 0xC0000 , size = 256 KB RCR = 0x1 : not cached, ARR2: disabled ARR3: address = 0xA8000 , size = 32 KB RCR = 0x9 : not cached, write gathering, ARR4: disabled ARR5: disabled ARR6: address = 0xE0000000 , size = 2 MB RCR = 0x9 : not cached, write gathering, ARR7: address = 0x0 , size = 32 MB RCR = 0xB : cached, weak write ordering, write gathering, Step 7 - Test with an adequate benchmark (dga, Xmark, xbench, xengine, Doom, Quake or anything else that measures video memory bandwidth). Non-power-of-two amount of DRAM systems In case your system has12Mb, 24Mb, 48Mb or 96Mb of total DRAM installed, you will notice that ARR6 has already been setup by the BIOS for an unused memory region. This is OK, but now you will have to setup ARR5 instead of ARR6 for your LVFB. In step 4 above, replace the D6, D7, D8 and E2 indexes by D3, D4, D5 and E1 respectively. If your system also has ARR5 used by the BIOS, you will have to use ARR4. The indexes to setup will be D0, D1, D2 and E0 respectively. ------------------------------------------------------------------------ Last updated on January 4, 1998. Copyright 1997 Andrew D. Balsa