Subject: port-i386/28759: System instability due to incorrect setting of 82443BX SDRAM control
To: None <port-i386-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <scottr@netbsd.org>
List: netbsd-bugs
Date: 12/23/2004 09:57:00
>Number: 28759
>Category: port-i386
>Synopsis: System instability due to incorrect setting of 82443BX SDRAM control
>Confidential: no
>Severity: critical
>Priority: medium
>Responsible: port-i386-maintainer
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Dec 23 09:57:00 +0000 2004
>Originator: Scott Reynolds
>Release: NetBSD 1.6 and later
>Organization:
No organization here but us chickens.
>Environment:
System: NetBSD grunt 2.99.11 NetBSD 2.99.11 (GENERIC.TGI) #1: Thu Dec 23 02:45:38 CST 2004 root@grunt:/usr/src/sys/arch/i386/compile/GENERIC.TGI i386
Architecture: i386
Machine: i386
>Description:
The 82443BX has a problem that causes the first several steppings
of the chip to potentially place an incorrect address on the DRAM
bus. Code added in rev 1.19 of sys/arch/i386/pci/pchb.c works
around the problem when the IPDLT bits are set incorrectly by the
system BIOS. Unfortunately, the brush this change paints with is
too broad; I've got (4) HP NetServer LPr systems, all with this
same host bridge, that work fine as long as there are DIMMs only
in slots 0 and 1 of the mainboard. As evidence of the fact that
the IPDLT setting needs to be qualified on the stepping of the
chip I present the January 2001 Specification Update to the
82443BX datasheet:
http://www.intel.com/design/chipsets/specupdt/290639.htm
Notice particularly on page 9 that the hardware issue was
corrected in stepping C0 of the chip.
I first ran into this problem when I upgraded an HP NetServer LPr
way back when NetBSD 1.6 was released, but as it was a lone
occurrence, I chalked it up to bad RAM. It wasn't until two days
ago that I actually correlated this historical issue with a more
recent problem I had upgrading my production NetBSD 2.0 servers
to 1 GB of RAM. It turns out that NetBSD 1.5.x, which ran fine,
was based on rev 1.18 of pchb.c and the change was never ported
back to the 1.5 release branch.
>How-To-Repeat:
Start with an affected system. I have NetServer LPr systems from
both the original 400/450 MHz Pentium II class and the
600/650/700/800 MHz Pentium III class, all of which have rev 3
(stepping C1) of the host bridge. Make sure that you have RAM
in all 4 DIMM slots (PC100, CL=2, ECC, registered -- haven't
tried with CL=3, but that's not as easy to get these days).
You can reproduce the problem by simply configuring a kernel to
compile, change to the kernel compile directory, typing the
"make depend", and waiting for a few minutes to see fireworks.
A panic of nearly any variety, but usually involving uvm_fault(),
will appear.
It is easier to reproduce the problem if you have smaller DIMMs
in slots 0-1 (e.g. 64 MB).
>Fix:
Apply the appended patch. The BIOS should be allowed to set the
IPDLT bits however it likes if the 82443BX is rev 3 or greater, as
this may be necessary to ensure proper operation of the system.
Index: sys/arch/i386/pci/pchb.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/pci/pchb.c,v
retrieving revision 1.54
diff -u -r1.54 pchb.c
--- sys/arch/i386/pci/pchb.c 30 Aug 2004 15:05:17 -0000 1.54
+++ sys/arch/i386/pci/pchb.c 23 Dec 2004 09:23:38 -0000
@@ -192,22 +192,25 @@
case PCI_PRODUCT_INTEL_82443BX_AGP:
case PCI_PRODUCT_INTEL_82443BX_NOAGP:
/*
- * BIOS BUG WORKAROUND! The 82443BX
+ * BIOS BUG WORKAROUND! For revisions
+ * of the 82443BX earlier than rev 3, the
* datasheet indicates that the only
* legal setting for the "Idle/Pipeline
* DRAM Leadoff Timing (IPLDT)" parameter
* (bits 9:8) is 01. Unfortunately, some
* BIOSs do not set these bits properly.
*/
- bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
- I82443BX_SDRAMC_REG);
- if ((bcreg & 0x0300) != 0x0100) {
- printf("%s: fixing Idle/Pipeline DRAM "
- "Leadoff Timing\n", self->dv_xname);
- bcreg &= ~0x0300;
- bcreg |= 0x0100;
- pci_conf_write(pa->pa_pc, pa->pa_tag,
- I82443BX_SDRAMC_REG, bcreg);
+ if (PCI_REVISION(pa->pa_class) < 0x3) {
+ bcreg = pci_conf_read(pa->pa_pc, pa->pa_tag,
+ I82443BX_SDRAMC_REG);
+ if ((bcreg & 0x0300) != 0x0100) {
+ printf("%s: fixing Idle/Pipeline DRAM "
+ "Leadoff Timing\n", self->dv_xname);
+ bcreg &= ~0x0300;
+ bcreg |= 0x0100;
+ pci_conf_write(pa->pa_pc, pa->pa_tag,
+ I82443BX_SDRAMC_REG, bcreg);
+ }
}
break;