From: Andi Kleen <ak@muc.de>

Fix a couple of bugs in the AGP support for AMD K8 and add preliminary
support for the GART in the NForce3 chipsets (this is a "subvariant" of K8,
but needs to set up some more registers in a shadow device) 

DaveJ was ok with me merging this directly.

- Always manage all northbridges in the system, even when on a UP kernel
- Add Nforce3 (Crush) support. It needs some special hacks
  (based on an older patch from Nvidia, with changes by me) 
- Move AMD 8151 init into an own function.
- Do proper resource management for the aperture



 drivers/char/agp/amd64-agp.c |  186 ++++++++++++++++++++++++++++++++-----------
 include/linux/pci_ids.h      |    2 
 2 files changed, 144 insertions(+), 44 deletions(-)

diff -puN drivers/char/agp/amd64-agp.c~amd-k8-fixes drivers/char/agp/amd64-agp.c
--- 25/drivers/char/agp/amd64-agp.c~amd-k8-fixes	2004-01-01 14:08:07.000000000 -0800
+++ 25-akpm/drivers/char/agp/amd64-agp.c	2004-01-01 14:08:07.000000000 -0800
@@ -16,11 +16,7 @@
 #include "agp.h"
 
 /* Will need to be increased if AMD64 ever goes >8-way. */
-#ifdef CONFIG_SMP
 #define MAX_HAMMER_GARTS   8
-#else
-#define MAX_HAMMER_GARTS   1
-#endif
 
 /* PTE bits. */
 #define GPTE_VALID	1
@@ -35,9 +31,18 @@
 #define INVGART		(1<<0)
 #define GARTPTEERR	(1<<1)
 
+/* NVIDIA K8 registers */
+#define NVIDIA_X86_64_0_APBASE		0x10
+#define NVIDIA_X86_64_1_APBASE1		0x50
+#define NVIDIA_X86_64_1_APLIMIT1	0x54
+#define NVIDIA_X86_64_1_APSIZE		0xa8
+#define NVIDIA_X86_64_1_APBASE2		0xd8
+#define NVIDIA_X86_64_1_APLIMIT2	0xdc
+
 static int nr_garts;
 static struct pci_dev * hammers[MAX_HAMMER_GARTS];
 
+static struct resource *aperture_resource;
 static int __initdata agp_try_unsupported;
 
 static int gart_iterator;
@@ -250,7 +255,6 @@ struct agp_bridge_driver amd_8151_driver
 /* Some basic sanity checks for the aperture. */
 static int __devinit aperture_valid(u64 aper, u32 size)
 { 
-	static int not_first_call; 
 	u32 pfn, c;
 	if (aper == 0) { 
 		printk(KERN_ERR PFX "No aperture\n");
@@ -279,12 +283,11 @@ static int __devinit aperture_valid(u64 
 
 	   Maybe better to use pci_assign_resource/pci_enable_device instead trusting
 	   the bridges? */
-	if (!not_first_call && request_mem_region(aper, size, "aperture") < 0) { 
+	if (!aperture_resource &&
+	    !(aperture_resource = request_mem_region(aper, size, "aperture"))) {
 		printk(KERN_ERR PFX "Aperture conflicts with PCI mapping.\n"); 
 		return 0;
 	}
-
-	not_first_call = 1;
 	return 1;
 } 
 
@@ -347,31 +350,124 @@ static __devinit int cache_nbs (struct p
 	/* cache pci_devs of northbridges. */
 	while ((loop_dev = pci_find_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) 
 			!= NULL) {
+		if (i == MAX_HAMMER_GARTS) {
+			printk(KERN_ERR PFX "Too many northbridges for AGP\n");
+			return -1;
+		}
 		if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) { 
-			printk(KERN_INFO PFX "No usable aperture found.\n");
+			printk(KERN_ERR PFX "No usable aperture found.\n");
 #ifdef __x86_64__ 
 			/* should port this to i386 */
-			printk(KERN_INFO PFX "Consider rebooting with iommu=memaper=2 to get a good aperture.\n");
+			printk(KERN_ERR PFX "Consider rebooting with iommu=memaper=2 to get a good aperture.\n");
 #endif 
 			return -1;  
 		}
 		hammers[i++] = loop_dev;
+	}
 		nr_garts = i;
-		if (i == MAX_HAMMER_GARTS) { 
-			printk(KERN_INFO PFX "Too many northbridges for AGP\n");
-			return -1;
+	return i == 0 ? -1 : 0;
+}
+
+/* Handle AMD 8151 quirks */
+static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge)
+
+{
+	char *revstring;
+	u8 rev_id;
+
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+	switch (rev_id) {
+	case 0x01: revstring="A0"; break;
+	case 0x02: revstring="A1"; break;
+	case 0x11: revstring="B0"; break;
+	case 0x12: revstring="B1"; break;
+	case 0x13: revstring="B2"; break;
+	default:   revstring="??"; break;
 		}
+
+	printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring);
+
+	/*
+	 * Work around errata.
+	 * Chips before B2 stepping incorrectly reporting v3.5
+	 */
+	if (rev_id < 0x13) {
+		printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n");
+		bridge->major_version = 3;
+		bridge->minor_version = 0;
 	}
-	return i == 0 ? -1 : 0;
+}
+
+static struct aper_size_info_32 nforce3_sizes[5] =
+{
+	{512,  131072, 7, 0x00000000 },
+	{256,  65536,  6, 0x00000008 },
+	{128,  32768,  5, 0x0000000C },
+	{64,   16384,  4, 0x0000000E },
+	{32,   8192,   3, 0x0000000F }
+};
+
+/* Handle shadow device of the Nvidia NForce3 */
+/* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */
+static int __devinit nforce3_agp_init(struct pci_dev *pdev)
+{
+	u32 tmp, apbase, apbar, aplimit;
+	struct pci_dev *dev1;
+	int i;
+	unsigned size = amd64_fetch_size();
+
+	printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n");
+
+	dev1 = pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(11, 0));
+	if (dev1 == NULL) {
+		printk(KERN_INFO PFX "agpgart: Detected an NVIDIA "
+			"nForce3 chipset, but could not find "
+			"the secondary device.\n");
+		return -ENODEV;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(nforce3_sizes); i++)
+		if (nforce3_sizes[i].size == size)
+			break;
+
+	if (i == ARRAY_SIZE(nforce3_sizes)) {
+		printk(KERN_INFO PFX "No NForce3 size found for %d\n", size);
+		return -ENODEV;
+	}
+
+	pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp);
+	tmp &= ~(0xf);
+	tmp |= nforce3_sizes[i].size_value;
+	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp);
+
+	/* shadow x86-64 registers into NVIDIA registers */
+	pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase);
+
+	/* if x86-64 aperture base is beyond 4G, exit here */
+	if ( (apbase & 0x7fff) >> (32 - 25) )
+		 return -ENODEV;
+
+	apbase = (apbase & 0x7fff) << 25;
+
+	pci_read_config_dword(pdev, NVIDIA_X86_64_0_APBASE, &apbar);
+	apbar &= ~PCI_BASE_ADDRESS_MEM_MASK;
+	apbar |= apbase;
+	pci_write_config_dword(pdev, NVIDIA_X86_64_0_APBASE, apbar);
+
+	aplimit = apbase + (size * 1024 * 1024) - 1;
+	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE1, apbase);
+	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT1, aplimit);
+	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase);
+	pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit);
+
+	return 0;
 }
 
 static int __devinit agp_amd64_probe(struct pci_dev *pdev,
 				     const struct pci_device_id *ent)
 {
 	struct agp_bridge_data *bridge;
-	u8 rev_id;
 	u8 cap_ptr;
-	char *revstring=NULL;
 
 	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 	if (!cap_ptr)
@@ -385,32 +481,7 @@ static int __devinit agp_amd64_probe(str
 
 	if (pdev->vendor == PCI_VENDOR_ID_AMD &&
 	    pdev->device == PCI_DEVICE_ID_AMD_8151_0) {
-
-		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
-		switch (rev_id) {
-		case 0x01:	revstring="A0";
-				break;
-		case 0x02:	revstring="A1";
-				break;
-		case 0x11:	revstring="B0";
-				break;
-		case 0x12:	revstring="B1";
-				break;
-		case 0x13:	revstring="B2";
-				break;
-		default:	revstring="??";
-				break;
-		}
-		printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring);
-		/*
-		 * Work around errata.
-		 * Chips before B2 stepping incorrectly reporting v3.5
-		 */
-		if (rev_id < 0x13) {
-			printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n");
-			bridge->major_version = 3;
-			bridge->minor_version = 0;
-		}
+		amd8151_init(pdev, bridge);
 	} else {
 		printk(KERN_INFO PFX "Detected AGP bridge %x\n",
 			pdev->devfn);
@@ -428,6 +499,14 @@ static int __devinit agp_amd64_probe(str
 		return -ENODEV;
 	}
 
+	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
+		int ret = nforce3_agp_init(pdev);
+		if (ret) {
+			agp_put_bridge(bridge);
+			return ret;
+		}
+	}
+
 	pci_set_drvdata(pdev, bridge);
 	return agp_add_bridge(bridge);
 }
@@ -472,8 +551,25 @@ static struct pci_device_id agp_amd64_pc
 	{
 	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
 	.class_mask	= ~0,
-	.vendor		= PCI_VENDOR_ID_SI,
-	.device		= PCI_DEVICE_ID_SI_755,
+	.vendor		= PCI_VENDOR_ID_VIA,
+	.device		= PCI_DEVICE_ID_VIA_8380_0,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	/* NForce3 */
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_NVIDIA,
+	.device		= PCI_DEVICE_ID_NVIDIA_NFORCE3,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_NVIDIA,
+	.device		= PCI_DEVICE_ID_NVIDIA_NFORCE3S,
 	.subvendor	= PCI_ANY_ID,
 	.subdevice	= PCI_ANY_ID,
 	},
@@ -530,6 +626,8 @@ int __init agp_amd64_init(void)
 
 static void __exit agp_amd64_cleanup(void)
 {
+	if (aperture_resource)
+		release_resource(aperture_resource);
 	pci_unregister_driver(&agp_amd64_pci_driver);
 }
 
diff -puN include/linux/pci_ids.h~amd-k8-fixes include/linux/pci_ids.h
--- 25/include/linux/pci_ids.h~amd-k8-fixes	2004-01-01 14:08:07.000000000 -0800
+++ 25-akpm/include/linux/pci_ids.h	2004-01-01 14:08:07.000000000 -0800
@@ -1034,6 +1034,8 @@
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE	0x0085
 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA	0x008e
 #define PCI_DEVICE_ID_NVIDIA_ITNT2		0x00A0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3		0x00d1
+#define PCI_DEVICE_ID_NVIDIA_NFORCE3S  		0x00e1
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE	0x00d5
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA	0x00e3
 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE	0x00e5

_