Bit flipping problems solved (for me) + performance INCREASE!

Robert L Krawitz (rlk@tiac.net)
Tue, 14 May 1996 16:58:19 -0400


Gerard Roudier sent me a program to change the memory clocking on my
motherboard (Plato) from x-4-4-4 to x-3-3-3. Having new 60 ns DRAM,
and figuring that I'd at least see if I had problems, I tried changing
it. Not only did I get a noticeable performance boost, but problems
I've had for a while copying large trees around completely went away.
Evidently the slow timing was occasionally screwing something up.

Other people having problems on Neptune-based motherboards might want
to give this a try.

/*
* compiling: [g]cc setpci.c -o setpci
* for SVR4 (not Solaris), UnixWare use:
* [g]cc -DSVR4 scanpci.c -o setpci
* for DOS, watcom 9.5:
* wcc386p -zq -omaxet -7 -4s -s -w3 -d2 name.c
* and link with PharLap or other dos extender for exe
*
*/

#if defined(__SVR4)
#if !defined(SVR4)
#define SVR4
#endif
#endif

#include <stdio.h>
#include <sys/types.h>
#if defined(SVR4)
#if defined(sun)
#define __EXTENSIONS__
#endif
#include <sys/proc.h>
#include <sys/tss.h>
#if defined(NCR)
#define __STDC
#include <sys/sysi86.h>
#undef __STDC
#else
#include <sys/sysi86.h>
#endif
#if defined(__SUNPRO_C) || defined(sun) || defined(__sun)
#include <sys/psw.h>
#else
#include <sys/seg.h>
#endif
#include <sys/v86.h>
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__386BSD__)
#include <sys/file.h>
#include <machine/console.h>
#define GCCUSESGAS
#endif
#if defined(__bsdi__)
#include <sys/file.h>
#include <sys/ioctl.h>
#include <i386/isa/pcconsioctl.h>
#define GCCUSESGAS
#endif
#if defined(SCO)
#include <sys/console.h>
#include <sys/param.h>
#include <sys/immu.h>
#include <sys/region.h>
#include <sys/proc.h>
#include <sys/tss.h>
#include <sys/sysi86.h>
#include <sys/v86.h>
#endif
#if defined(Lynx_22)
#define GCCUSESGAS
#endif

#if defined(__WATCOMC__)

#include <stdlib.h>
void outl(unsigned port, unsigned data);
#pragma aux outl = "out dx, eax" parm [dx] [eax];
void outb(unsigned port, unsigned data);
#pragma aux outb = "out dx, al" parm [dx] [eax];
unsigned inl(unsigned port);
#pragma aux inl = "in eax, dx" parm [dx];
unsigned inb(unsigned port);
#pragma aux inb = "xor eax,eax" "in al, dx" parm [dx];

#else /* __WATCOMC__ */

#if defined(__GNUC__)

#if defined(GCCUSESGAS)
#define OUTB_GCC "outb %0,%1"
#define OUTL_GCC "outl %0,%1"
#define INB_GCC "inb %1,%0"
#define INL_GCC "inl %1,%0"
#else
#define OUTB_GCC "out%B0 (%1)"
#define OUTL_GCC "out%L0 (%1)"
#define INB_GCC "in%B0 (%1)"
#define INL_GCC "in%L0 (%1)"
#endif /* GCCUSESGAS */

static void outb(unsigned short port, unsigned char val) {
__asm__ __volatile__(OUTB_GCC : :"a" (val), "d" (port)); }
static void outl(unsigned short port, unsigned long val) {
__asm__ __volatile__(OUTL_GCC : :"a" (val), "d" (port)); }
static unsigned char inb(unsigned short port) { unsigned char ret;
__asm__ __volatile__(INB_GCC : "=a" (ret) : "d" (port)); return ret; }
static unsigned long inl(unsigned short port) { unsigned long ret;
__asm__ __volatile__(INL_GCC : "=a" (ret) : "d" (port)); return ret; }

#else /* __GNUC__ */

#if defined(__STDC__) && (__STDC__ == 1)
# if !defined(NCR)
# define asm __asm
# endif
#endif

#if defined(__SUNPRO_C)
/*
* This section is a gross hack in if you tell anyone that I wrote it,
* I'll deny it. :-)
* The leave/ret instructions are the big hack to leave %eax alone on return.
*/
unsigned char inb(int port) {
asm(" movl 8(%esp),%edx");
asm(" subl %eax,%eax");
asm(" inb (%dx)");
asm(" leave");
asm(" ret");
}

unsigned short inw(int port) {
asm(" movl 8(%esp),%edx");
asm(" subl %eax,%eax");
asm(" inw (%dx)");
asm(" leave");
asm(" ret");
}

unsigned long inl(int port) {
asm(" movl 8(%esp),%edx");
asm(" inl (%dx)");
asm(" leave");
asm(" ret");
}

void outb(int port, unsigned char value) {
asm(" movl 8(%esp),%edx");
asm(" movl 12(%esp),%eax");
asm(" outb (%dx)");
}

void outw(int port, unsigned short value) {
asm(" movl 8(%esp),%edx");
asm(" movl 12(%esp),%eax");
asm(" outw (%dx)");
}

void outl(int port, unsigned long value) {
asm(" movl 8(%esp),%edx");
asm(" movl 12(%esp),%eax");
asm(" outl (%dx)");
}
#else

#if defined(SVR4)
# if !defined(__USLC__)
# define __USLC__
# endif
#endif

#include <sys/inline.h>

#endif /* SUNPRO_C */

#endif /* __GNUC__ */
#endif /* __WATCOMC__ */

void enable_os_io();
void disable_os_io();

#define M_EQ 0 /* mask and return true if equal */
#define M_NE 1 /* mask and return true if not equal */
#define TRUE 2 /* don't read config, always true */

struct condmsg {
unsigned char port;
unsigned char mask;
unsigned char value;
char flags;
char *text;
};

static const struct condmsg set82434lx[] =
{
{ 0x00, 0x00, 0x00, TRUE, " memory clocks=" },
{ 0x57, 0xc0, 0xc0, M_EQ, "X-3-3-3 (50ns)" },
{ 0x58, 0x01, 0x00, M_EQ, ", no CAS-wait" },
{ 0x53, 0x08, 0x08, M_EQ, ", read around write"},
/*
{ 0x57, 0xc0, 0x40, M_EQ, "X-4-4-4/X-3-3-3 (60ns)" },
*/
{ 0x00, 0x00, 0x00, TRUE, "\n" },
/* end marker */
{ 0 }
};

static const struct condmsg conf82434lx[] =
{
{ 0x00, 0x00, 0x00, TRUE, "\tCPU: " },
{ 0x50, 0xe3, 0x82, M_EQ, "Pentium, 60MHz" },
{ 0x50, 0xe3, 0x83, M_EQ, "Pentium, 66MHz" },
{ 0x50, 0xe3, 0xa2, M_EQ, "Pentium, 90MHz" },
{ 0x50, 0xe3, 0xa3, M_EQ, "Pentium, 100MHz" },
{ 0x50, 0xc2, 0x82, M_NE, "(unknown)" },
{ 0x50, 0x04, 0x00, M_EQ, " (primary cache OFF)" },

{ 0x53, 0x01, 0x01, TRUE, ", CPU->Memory posting "},
{ 0x53, 0x01, 0x01, M_NE, "OFF" },
{ 0x53, 0x01, 0x01, M_EQ, "ON" },

{ 0x53, 0x08, 0x00, M_NE, ", read around write"},

{ 0x70, 0x04, 0x00, M_EQ, "\n\tWarning: Cache parity disabled!" },
{ 0x57, 0x20, 0x00, M_NE, "\n\tWarning: DRAM parity mask!" },
{ 0x57, 0x01, 0x00, M_EQ, "\n\tWarning: refresh OFF! " },

{ 0x00, 0x00, 0x00, TRUE, "\n\tCache: " },
{ 0x52, 0x01, 0x00, M_EQ, "None" },
{ 0x52, 0x81, 0x01, M_EQ, "" },
{ 0x52, 0xc1, 0x81, M_EQ, "256KB" },
{ 0x52, 0xc1, 0xc1, M_EQ, "512KB" },
{ 0x52, 0x03, 0x01, M_EQ, " writethrough" },
{ 0x52, 0x03, 0x03, M_EQ, " writeback" },

{ 0x52, 0x01, 0x01, M_EQ, ", cache clocks=" },
{ 0x52, 0x21, 0x01, M_EQ, "3-2-2-2/4-2-2-2" },
{ 0x52, 0x21, 0x21, M_EQ, "3-1-1-1" },

{ 0x52, 0x01, 0x01, M_EQ, "\n\tCache flags: " },
{ 0x52, 0x11, 0x11, M_EQ, " cache-all" },
{ 0x52, 0x09, 0x09, M_EQ, " byte-control" },
{ 0x52, 0x05, 0x05, M_EQ, " powersaver" },

{ 0x00, 0x00, 0x00, TRUE, "\n\tDRAM:" },
{ 0x57, 0x10, 0x00, M_EQ, " page mode" },

{ 0x00, 0x00, 0x00, TRUE, " memory clocks=" },
{ 0x57, 0xc0, 0x00, M_EQ, "X-4-4-4 (70ns)" },
{ 0x57, 0xc0, 0x40, M_EQ, "X-4-4-4/X-3-3-3 (60ns)" },
{ 0x57, 0xc0, 0x80, M_EQ, "???" },
{ 0x57, 0xc0, 0xc0, M_EQ, "X-3-3-3 (50ns)" },
{ 0x58, 0x02, 0x02, M_EQ, ", RAS-wait" },
{ 0x58, 0x01, 0x01, M_EQ, ", CAS-wait" },

{ 0x00, 0x00, 0x00, TRUE, "\n\tCPU->PCI: posting " },
{ 0x53, 0x02, 0x02, M_EQ, "ON" },
{ 0x53, 0x02, 0x00, M_EQ, "OFF" },
{ 0x00, 0x00, 0x00, TRUE, ", burst mode " },
{ 0x54, 0x02, 0x00, M_NE, "ON" },
{ 0x54, 0x02, 0x00, M_EQ, "OFF" },
{ 0x54, 0x04, 0x00, TRUE, ", PCI clocks=" },
{ 0x54, 0x04, 0x00, M_EQ, "2-2-2-2" },
{ 0x54, 0x04, 0x00, M_NE, "2-1-1-1" },
{ 0x00, 0x00, 0x00, TRUE, "\n\tPCI->Memory: posting " },
{ 0x54, 0x01, 0x00, M_NE, "ON" },
{ 0x54, 0x01, 0x00, M_EQ, "OFF" },

{ 0x57, 0x01, 0x01, M_EQ, "\n\tRefresh:" },
{ 0x57, 0x03, 0x03, M_EQ, " CAS#/RAS#(Hidden)" },
{ 0x57, 0x03, 0x01, M_EQ, " RAS#Only" },
{ 0x57, 0x05, 0x05, M_EQ, " BurstOf4" },

{ 0x00, 0x00, 0x00, TRUE, "\n" },

/* end marker */
{ 0 }
};

static char confread (int dev_num, int port)
{
unsigned long portw = port & ~3;
unsigned long ports = (port - portw) << 3;

unsigned long l = inl(0xC000 + portw);
return (l >> ports);
}

static void confwrite (int dev_num, int port, unsigned char value)
{
unsigned long portw = port & ~3;
unsigned long ports = (port - portw) << 3;

unsigned long l = inl(0xC000 + portw);

l &= (~(0xff << ports));
l |= (value << ports);

#if 1
outl(0xC000 + portw, l);
#endif
}

static void setconfig (int dev_num, const struct condmsg *tbl)
{
while (tbl->text) {
int cond = 0;
if (tbl->flags == TRUE) {
cond = 1;
} else {
unsigned char v = (unsigned char) confread(dev_num, tbl->port);
v &= (~tbl->mask);
v |= tbl->value;
confwrite(dev_num, tbl->port, v);
cond = 1;
}
if (cond) printf ("%s", tbl->text);
tbl++;
}
}

static void showconfig (int dev_num, const struct condmsg *tbl)
{
while (tbl->text) {
int cond = 0;
if (tbl->flags == TRUE) {
cond = 1;
} else {
unsigned char v = (unsigned char) confread(dev_num, tbl->port);
switch (tbl->flags) {
case M_EQ:
if ((v & tbl->mask) == tbl->value) cond = 1;
break;
case M_NE:
if ((v & tbl->mask) != tbl->value) cond = 1;
break;
}
}
if (cond) printf ("%s", tbl->text);
tbl++;
}
}

main(int argc, unsigned char *argv[])
{
unsigned long config_cmd;

if (argc != 1) {
printf("Usage: %s\n");
exit(1);
}
#if !defined(MSDOS)
if (getuid()) {
printf("This program must be run as root\n");
exit(1);
}
#endif

enable_os_io();

outb(0xCF8, 0xF1);
outb(0xCFA, 0x00); /* bus 0 for now */

setconfig(0, set82434lx);
showconfig(0, conf82434lx);

outb(0xCF8, 0x00);

disable_os_io();
}

static int io_fd;

void
enable_os_io()
{
#if defined(SVR4) || defined(SCO)
#if defined(SI86IOPL)
sysi86(SI86IOPL, 3);
#else
sysi86(SI86V86, V86SC_IOPL, PS_IOPL);
#endif
#endif
#if defined(linux)
iopl(3);
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__386BSD__) || defined(__bsdi__)
if ((io_fd = open("/dev/console", O_RDWR, 0)) < 0) {
perror("/dev/console");
exit(1);
}
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__386BSD__)
if (ioctl(io_fd, KDENABIO, 0) < 0) {
perror("ioctl(KDENABIO)");
exit(1);
}
#endif
#if defined(__bsdi__)
if (ioctl(io_fd, PCCONENABIOPL, 0) < 0) {
perror("ioctl(PCCONENABIOPL)");
exit(1);
}
#endif
#endif
#if defined(MACH386)
if ((io_fd = open("/dev/iopl", O_RDWR, 0)) < 0) {
perror("/dev/iopl");
exit(1);
}
#endif
}

void
disable_os_io()
{
#if defined(SVR4) || defined(SCO)
#if defined(SI86IOPL)
sysi86(SI86IOPL, 0);
#else
sysi86(SI86V86, V86SC_IOPL, 0);
#endif
#endif
#if defined(linux)
iopl(0);
#endif
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__386BSD__)
if (ioctl(io_fd, KDDISABIO, 0) < 0) {
perror("ioctl(KDDISABIO)");
close(io_fd);
exit(1);
}
close(io_fd);
#endif
#if defined(__bsdi__)
if (ioctl(io_fd, PCCONDISABIOPL, 0) < 0) {
perror("ioctl(PCCONDISABIOPL)");
close(io_fd);
exit(1);
}
close(io_fd);
#endif
#if defined(MACH386)
close(io_fd);
#endif
}