Re: nforce3 agpgart support

From: Terence Ripperda
Date: Thu Oct 23 2003 - 13:16:07 EST


Thanks Dave,

ccing linux-kernel with the nforce patch for 2.4.22.

Terence

On Thu, Oct 23, 2003 at 07:04:03PM +0100, davej@xxxxxxxxxx wrote:
> On Thu, Oct 23, 2003 at 12:57:00PM -0500, Terence Ripperda wrote:
> > Here's an updated patch for linux 2.4.22, which also includes support for an additional nforce3s chipset.
> >
> > are these the correct people that I should be sending these patches to, or is there someone else I should be contacting?
>
> For 2.4, send stuff straight to Marcelo (Cc linux-kernel is usually a
> good idea too). 2.6 stuff, bounce to me first please. With Alan busy
> doing an MBA for the next year, he likely won't have time to feed
> Marcelo patches.
>
> Dave
>
> --
> Dave Jones http://www.codemonkey.org.uk

diff -ru linux-2.4.22/arch/i386/defconfig linux-2.4.22-nforce/arch/i386/defconfig
--- linux-2.4.22/arch/i386/defconfig 2002-11-28 15:53:09.000000000 -0800
+++ linux-2.4.22-nforce/arch/i386/defconfig 2003-09-29 18:29:11.000000000 -0700
@@ -607,6 +607,7 @@
CONFIG_AGP_SIS=y
CONFIG_AGP_ALI=y
# CONFIG_AGP_SWORKS is not set
+CONFIG_AGP_NVIDIA=y
CONFIG_DRM=y
# CONFIG_DRM_OLD is not set

diff -ru linux-2.4.22/arch/x86_64/defconfig linux-2.4.22-nforce/arch/x86_64/defconfig
--- linux-2.4.22/arch/x86_64/defconfig 2003-08-25 04:44:40.000000000 -0700
+++ linux-2.4.22-nforce/arch/x86_64/defconfig 2003-09-29 18:29:11.000000000 -0700
@@ -528,7 +528,7 @@
#
# CONFIG_FTAPE is not set
CONFIG_AGP=y
-CONFIG_AGP_AMD_8151=y
+CONFIG_AGP_X86_64=y
CONFIG_AGP_INTEL=y
CONFIG_AGP_I810=y
CONFIG_AGP_VIA=y
@@ -536,6 +536,7 @@
CONFIG_AGP_SIS=y
CONFIG_AGP_ALI=y
CONFIG_AGP_SWORKS=y
+CONFIG_AGP_NVIDIA=y
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set

diff -ru linux-2.4.22/Documentation/Configure.help linux-2.4.22-nforce/Documentation/Configure.help
--- linux-2.4.22/Documentation/Configure.help 2003-08-25 04:44:39.000000000 -0700
+++ linux-2.4.22-nforce/Documentation/Configure.help 2003-09-29 18:29:11.000000000 -0700
@@ -3697,9 +3697,9 @@
You should say Y here if you use XFree86 3.3.6 or 4.x and want to
use GLX or DRI. If unsure, say N.

-CONFIG_AGP_AMD_8151
+CONFIG_AGP_X86_64
This option gives you AGP support for the GLX component of
- XFree86 on AMD K8 with an AGP 8151 chipset.
+ XFree86 on AMD K8 with an AGP 8151 or NVIDIA nForce3 chipset.

You should say Y here if you use XFree86 3.3.6 or 4.x and want to
use GLX or DRI. If unsure, say N.
diff -ru linux-2.4.22/drivers/char/agp/agpgart_be.c linux-2.4.22-nforce/drivers/char/agp/agpgart_be.c
--- linux-2.4.22/drivers/char/agp/agpgart_be.c 2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.22-nforce/drivers/char/agp/agpgart_be.c 2003-09-29 18:29:11.000000000 -0700
@@ -49,7 +49,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/page.h>
-#ifdef CONFIG_AGP_NVIDIA
+#if defined(CONFIG_AGP_NVIDIA) || defined(CONFIG_AGP_X86_64)
#include <asm/msr.h>
#endif

@@ -2744,7 +2744,7 @@

#endif /* CONFIG_AGP_AMD */

-#ifdef CONFIG_AGP_AMD_8151
+#ifdef CONFIG_AGP_X86_64

/* Begin AMD-8151 support */

@@ -3207,7 +3207,162 @@
(void) pdev; /* unused */
}

-#endif /* CONFIG_AGP_AMD_8151 */
+
+/* NVIDIA x86-64 chipset support */
+
+
+static struct _nvidia_x86_64_private {
+ struct pci_dev *dev_1;
+} nvidia_x86_64_private;
+
+
+static int nvidia_init_iorr(u32 base, u32 size);
+
+
+static aper_size_info_32 nvidia_x86_64_sizes[5] =
+{
+ {512, 131072, 7, 0x00000000 },
+ {256, 65536, 6, 0x00000008 },
+ {128, 32768, 5, 0x0000000C },
+ {64, 16384, 4, 0x0000000E },
+ {32, 8192, 3, 0x0000000F }
+};
+
+
+static int nvidia_x86_64_configure(void)
+{
+ struct pci_dev *dev, *hammer=NULL;
+ int i, current_size, rc;
+ u32 tmp, apbase, apbar, aplimit;
+ unsigned long gatt_bus = virt_to_phys(agp_bridge.gatt_table_real);
+
+ if (!agp_bridge.dev)
+ return -ENODEV;
+
+ /* configure AGP regs in each x86-64 host bridge */
+ pci_for_each_dev(dev) {
+ if (dev->bus->number==0 &&
+ PCI_FUNC(dev->devfn)==3 &&
+ PCI_SLOT(dev->devfn)>=24 && PCI_SLOT(dev->devfn)<=31) {
+ agp_bridge.gart_bus_addr = amd_x86_64_configure(dev,gatt_bus);
+ hammer = dev;
+ }
+ }
+ if (hammer == NULL)
+ return -ENODEV;
+
+ /* translate x86-64 aperture size to NVIDIA aperture size */
+ current_size = amd_x86_64_fetch_size();
+ for (i = 0 ; i < agp_bridge.num_aperture_sizes; i++) {
+ if (nvidia_x86_64_sizes[i].size == current_size)
+ break;
+ }
+ /* if x86-64 size does not match any NVIDIA size, exit here */
+ if (i == agp_bridge.num_aperture_sizes)
+ return -ENODEV;
+ pci_read_config_dword(nvidia_x86_64_private.dev_1, NVIDIA_X86_64_1_APSIZE, &tmp);
+ tmp &= ~(0xf);
+ tmp |= nvidia_x86_64_sizes[i].size_value;
+ pci_write_config_dword(nvidia_x86_64_private.dev_1, NVIDIA_X86_64_1_APSIZE, tmp);
+
+ /* shadow x86-64 registers into NVIDIA registers */
+ pci_read_config_dword (hammer, AMD_X86_64_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(agp_bridge.dev, NVIDIA_X86_64_0_APBASE, &apbar);
+ apbar &= ~PCI_BASE_ADDRESS_MEM_MASK;
+ apbar |= apbase;
+ pci_write_config_dword(agp_bridge.dev, NVIDIA_X86_64_0_APBASE, apbar);
+ aplimit = apbase + (current_size * 1024 * 1024) - 1;
+ pci_write_config_dword(nvidia_x86_64_private.dev_1, NVIDIA_X86_64_1_APBASE1, apbase);
+ pci_write_config_dword(nvidia_x86_64_private.dev_1, NVIDIA_X86_64_1_APLIMIT1, aplimit);
+ pci_write_config_dword(nvidia_x86_64_private.dev_1, NVIDIA_X86_64_1_APBASE2, apbase);
+ pci_write_config_dword(nvidia_x86_64_private.dev_1, NVIDIA_X86_64_1_APLIMIT2, aplimit);
+
+ // update aperture IORR
+ if (0 != (rc = nvidia_init_iorr(apbase, current_size * 1024 * 1024)))
+ return rc;
+
+ return 0;
+}
+
+
+static void nvidia_x86_64_cleanup(void)
+{
+ struct pci_dev *dev;
+ u32 tmp;
+
+ pci_for_each_dev(dev) {
+ /* disable gart translation */
+ if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 &&
+ (PCI_SLOT(dev->devfn) >=24) && (PCI_SLOT(dev->devfn) <=31)) {
+
+ pci_read_config_dword (dev, AMD_X86_64_GARTAPERTURECTL, &tmp);
+ tmp &= ~(AMD_X86_64_GARTEN);
+ pci_write_config_dword (dev, AMD_X86_64_GARTAPERTURECTL, tmp);
+ }
+ }
+}
+
+
+static unsigned long nvidia_x86_64_mask_memory(unsigned long addr, int type)
+{
+ return addr | agp_bridge.masks[0].mask;
+}
+
+
+static gatt_mask nvidia_x86_64_masks[] =
+{
+ {0x00000001, 0}
+};
+
+
+static int __init nvidia_x86_64_setup (struct pci_dev *pdev)
+{
+ nvidia_x86_64_private.dev_1 =
+ pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(11, 0));
+
+ if (nvidia_x86_64_private.dev_1 == NULL) {
+ printk(KERN_INFO PFX "agpgart: Detected an NVIDIA "
+ "nForce3 chipset, but could not find "
+ "the secondary device.\n");
+ agp_bridge.type = NOT_SUPPORTED;
+ return -ENODEV;
+ }
+
+ agp_bridge.masks = nvidia_x86_64_masks;
+ agp_bridge.aperture_sizes = (void *) nvidia_x86_64_sizes;
+ agp_bridge.size_type = U32_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 5;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = nvidia_x86_64_configure;
+ agp_bridge.fetch_size = amd_x86_64_fetch_size;
+ agp_bridge.cleanup = nvidia_x86_64_cleanup;
+ agp_bridge.tlb_flush = amd_x86_64_tlbflush;
+ agp_bridge.mask_memory = nvidia_x86_64_mask_memory;
+ agp_bridge.agp_enable = agp_x86_64_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = x86_64_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+ agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+ agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+ agp_bridge.suspend = agp_generic_suspend;
+ agp_bridge.resume = agp_generic_resume;
+ agp_bridge.cant_use_aperture = 0;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_X86_64 */

#ifdef CONFIG_AGP_ALI

@@ -4060,6 +4215,8 @@
off_t pg_offset;
} nvidia_private;

+static int nvidia_init_iorr(u32 base, u32 size);
+
static int nvidia_fetch_size(void)
{
int i;
@@ -4082,52 +4239,6 @@
return 0;
}

-#define SYSCFG 0xC0010010
-#define IORR_BASE0 0xC0010016
-#define IORR_MASK0 0xC0010017
-#define AMD_K7_NUM_IORR 2
-
-static int nvidia_init_iorr(u32 base, u32 size)
-{
- u32 base_hi, base_lo;
- u32 mask_hi, mask_lo;
- u32 sys_hi, sys_lo;
- u32 iorr_addr, free_iorr_addr;
-
- /* Find the iorr that is already used for the base */
- /* If not found, determine the uppermost available iorr */
- free_iorr_addr = AMD_K7_NUM_IORR;
- for(iorr_addr = 0; iorr_addr < AMD_K7_NUM_IORR; iorr_addr++) {
- rdmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi);
- rdmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi);
-
- if ((base_lo & 0xfffff000) == (base & 0xfffff000))
- break;
-
- if ((mask_lo & 0x00000800) == 0)
- free_iorr_addr = iorr_addr;
- }
-
- if (iorr_addr >= AMD_K7_NUM_IORR) {
- iorr_addr = free_iorr_addr;
- if (iorr_addr >= AMD_K7_NUM_IORR)
- return -EINVAL;
- }
-
- base_hi = 0x0;
- base_lo = (base & ~0xfff) | 0x18;
- mask_hi = 0xf;
- mask_lo = ((~(size - 1)) & 0xfffff000) | 0x800;
- wrmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi);
- wrmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi);
-
- rdmsr(SYSCFG, sys_lo, sys_hi);
- sys_lo |= 0x00100000;
- wrmsr(SYSCFG, sys_lo, sys_hi);
-
- return 0;
-}
-
static int nvidia_configure(void)
{
int i, rc, num_dirs;
@@ -4373,6 +4484,58 @@

#endif /* CONFIG_AGP_NVIDIA */

+/* make IORR setup available to NVIDIA nForce/nForce2 support as well as to */
+/* NVIDIA nForce3 support in the x86-64 section. */
+#if defined(CONFIG_AGP_NVIDIA) || defined(CONFIG_AGP_X86_64)
+
+#define SYSCFG 0xC0010010
+#define IORR_BASE0 0xC0010016
+#define IORR_MASK0 0xC0010017
+#define AMD_K7_NUM_IORR 2
+
+static int nvidia_init_iorr(u32 base, u32 size)
+{
+ u32 base_hi, base_lo;
+ u32 mask_hi, mask_lo;
+ u32 sys_hi, sys_lo;
+ u32 iorr_addr, free_iorr_addr;
+
+ /* Find the iorr that is already used for the base */
+ /* If not found, determine the uppermost available iorr */
+ free_iorr_addr = AMD_K7_NUM_IORR;
+ for(iorr_addr = 0; iorr_addr < AMD_K7_NUM_IORR; iorr_addr++) {
+ rdmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi);
+ rdmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi);
+
+ if ((base_lo & 0xfffff000) == (base & 0xfffff000))
+ break;
+
+ if ((mask_lo & 0x00000800) == 0)
+ free_iorr_addr = iorr_addr;
+ }
+
+ if (iorr_addr >= AMD_K7_NUM_IORR) {
+ iorr_addr = free_iorr_addr;
+ if (iorr_addr >= AMD_K7_NUM_IORR)
+ return -EINVAL;
+ }
+
+ base_hi = 0x0;
+ base_lo = (base & ~0xfff) | 0x18;
+ mask_hi = 0xf;
+ mask_lo = ((~(size - 1)) & 0xfffff000) | 0x800;
+ wrmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi);
+ wrmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi);
+
+ rdmsr(SYSCFG, sys_lo, sys_hi);
+ sys_lo |= 0x00100000;
+ wrmsr(SYSCFG, sys_lo, sys_hi);
+
+ return 0;
+}
+
+#endif /* defined(CONFIG_AGP_NVIDIA) || defined(CONFIG_AGP_X86_64) */
+
#ifdef CONFIG_AGP_HP_ZX1

#ifndef log2
@@ -4837,14 +5000,26 @@
amd_irongate_setup },
#endif /* CONFIG_AGP_AMD */

-#ifdef CONFIG_AGP_AMD_8151
+#ifdef CONFIG_AGP_X86_64
{ PCI_DEVICE_ID_AMD_8151_0,
PCI_VENDOR_ID_AMD,
AMD_8151,
"AMD",
"8151",
amd_8151_setup },
-#endif /* CONFIG_AGP_AMD */
+ { PCI_DEVICE_ID_NVIDIA_NFORCE3,
+ PCI_VENDOR_ID_NVIDIA,
+ NVIDIA_NFORCE3,
+ "NVIDIA",
+ "nForce3",
+ nvidia_x86_64_setup },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE3S,
+ PCI_VENDOR_ID_NVIDIA,
+ NVIDIA_NFORCE3,
+ "NVIDIA",
+ "nForce3",
+ nvidia_x86_64_setup },
+#endif /* CONFIG_AGP_X86_64 */

#ifdef CONFIG_AGP_INTEL
{ PCI_DEVICE_ID_INTEL_82443LX_0,
diff -ru linux-2.4.22/drivers/char/agp/agp.h linux-2.4.22-nforce/drivers/char/agp/agp.h
--- linux-2.4.22/drivers/char/agp/agp.h 2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.22-nforce/drivers/char/agp/agp.h 2003-09-29 18:29:11.000000000 -0700
@@ -466,6 +466,14 @@
#define NVIDIA_3_APBASE 0x50
#define NVIDIA_3_APLIMIT 0x54

+/* NVIDIA x86-64 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
+
/* HP ZX1 SBA registers */
#define HP_ZX1_CTRL 0x200
#define HP_ZX1_IBASE 0x300
diff -ru linux-2.4.22/drivers/char/Config.in linux-2.4.22-nforce/drivers/char/Config.in
--- linux-2.4.22/drivers/char/Config.in 2003-08-25 04:44:41.000000000 -0700
+++ linux-2.4.22-nforce/drivers/char/Config.in 2003-09-29 18:29:11.000000000 -0700
@@ -294,7 +294,7 @@

if [ "$CONFIG_GART_IOMMU" = "y" ]; then
bool '/dev/agpgart (AGP Support)' CONFIG_AGP
- define_bool CONFIG_AGP_AMD_8151 y
+ define_bool CONFIG_AGP_X86_64 y
else
tristate '/dev/agpgart (AGP Support)' CONFIG_AGP
fi
@@ -304,7 +304,7 @@
bool ' VIA chipset support' CONFIG_AGP_VIA
bool ' AMD Irongate, 761, and 762 support' CONFIG_AGP_AMD
if [ "$CONFIG_GART_IOMMU" != "y" ]; then
- bool ' AMD 8151 support' CONFIG_AGP_AMD_8151
+ bool ' x86-64 chipset support (AMD 8151, NVIDIA nForce3)' CONFIG_AGP_X86_64
fi
bool ' Generic SiS support' CONFIG_AGP_SIS
bool ' ALI chipset support' CONFIG_AGP_ALI
diff -ru linux-2.4.22/include/linux/agp_backend.h linux-2.4.22-nforce/include/linux/agp_backend.h
--- linux-2.4.22/include/linux/agp_backend.h 2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-nforce/include/linux/agp_backend.h 2003-09-29 18:29:11.000000000 -0700
@@ -88,6 +88,7 @@
SVWRKS_GENERIC,
NVIDIA_NFORCE,
NVIDIA_NFORCE2,
+ NVIDIA_NFORCE3,
NVIDIA_GENERIC,
HP_ZX1,
};
diff -ru linux-2.4.22/include/linux/pci_ids.h linux-2.4.22-nforce/include/linux/pci_ids.h
--- linux-2.4.22/include/linux/pci_ids.h 2003-08-25 04:44:44.000000000 -0700
+++ linux-2.4.22-nforce/include/linux/pci_ids.h 2003-09-29 18:29:11.000000000 -0700
@@ -965,6 +965,8 @@
#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D
#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065
#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_GEFORCE_SDR 0x0100
#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101
#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103
@@ -977,7 +979,7 @@
#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152
#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153
#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0
-#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4
+#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4
#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc
#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0
#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200