From: Bartlomiej Zolnierkiewicz <B.Zolnierkiewicz@elka.pw.edu.pl>

Based on information provided by "Allen Martin" <AMartin@nvidia.com>.

Problem:
C1 Halt Disconnect problem on nForce2 systems

Description:
A hang is caused when the CPU generates a very fast CONNECT/HALT cycle
sequence.

Workaround:
Set the SYSTEM_IDLE_TIMEOUT to 80 ns. This allows the state-machine and
timer to return to a proper state within 80 ns of the CONNECT and probe
appearing together.

Since the CPU will not issue another HALT within 80 ns of the initial
HALT, the failure condition is avoided.

This will require changing the value for register at bus:0 dev:0 func:0
offset 6c.

Chip   Current Value   New Value
C17       1F0FFF01     1F01FF01
C18D      9F0FFF01     9F01FF01

Northbridge chip version may be determined by reading the PCI revision
ID (offset 8) of the host bridge at bus:0 dev:0 func:0.  C1 or greater
is C18D.



---

 25-akpm/arch/i386/pci/fixup.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 39 insertions(+)

diff -puN arch/i386/pci/fixup.c~nforce-disconnect-fix arch/i386/pci/fixup.c
--- 25/arch/i386/pci/fixup.c~nforce-disconnect-fix	Mon May  3 16:37:47 2004
+++ 25-akpm/arch/i386/pci/fixup.c	Mon May  3 16:37:47 2004
@@ -187,6 +187,39 @@ static void __devinit pci_fixup_transpar
 		dev->transparent = 1;
 }
 
+/*
+ * Fixup for C1 Halt Disconnect problem on nForce2 systems.
+ *
+ * From information provided by "Allen Martin" <AMartin@nvidia.com>:
+ *
+ * A hang is caused when the CPU generates a very fast CONNECT/HALT cycle
+ * sequence.  Workaround is to set the SYSTEM_IDLE_TIMEOUT to 80 ns.
+ * This allows the state-machine and timer to return to a proper state within
+ * 80 ns of the CONNECT and probe appearing together.  Since the CPU will not
+ * issue another HALT within 80 ns of the initial HALT, the failure condition
+ * is avoided.
+ */
+static void __devinit pci_fixup_nforce2(struct pci_dev *dev)
+{
+	u32 val, fixed_val;
+	u8 rev;
+
+	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+	/*
+	 * Chip  Old value   New value
+	 * C17   0x1F01FF01  0x1F0FFF01
+	 * C18D  0x9F01FF01  0x9F0FFF01
+	 */
+	fixed_val = rev < 0xC1 ? 0x1F01FF01 : 0x9F01FF01;
+
+	pci_read_config_dword(dev, 0x6c, &val);
+	if (val != fixed_val) {
+		printk(KERN_WARNING "PCI: nForce2 C1 Halt Disconnet fixup\n");
+		pci_write_config_dword(dev, 0x6c, fixed_val);
+	}
+}
+
 struct pci_fixup pcibios_fixups[] = {
 	{
 		.pass		= PCI_FIXUP_HEADER,
@@ -290,5 +323,11 @@ struct pci_fixup pcibios_fixups[] = {
 		.device		= PCI_ANY_ID,
 		.hook		= pci_fixup_transparent_bridge
 	},
+	{
+		.pass		= PCI_FIXUP_HEADER,
+		.vendor		= PCI_VENDOR_ID_NVIDIA,
+		.device		= PCI_DEVICE_ID_NVIDIA_NFORCE2,
+		.hook		= pci_fixup_nforce2
+	},
 	{ .pass = 0 }
 };

_