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;