From 06477bc3a1029448a17ff03d4318648d4a74cf88 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sun, 30 Nov 2003 12:18:36 +0000 Subject: [PATCH] [AGPGART] Merge missing chunk of NVIDIA nForce agpgart driver. This bit has been in the 2.4 driver since it appeared, but I dropped it (partly deliberatly), and then forgot all about it. Turns out that some systems really need this stuff, as their BIOS hasn't set up the IORRs. http://bugme.osdl.org/show_bug.cgi?id=1521 --- drivers/char/agp/nvidia-agp.c | 52 ++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index c934e62b3cd5d..679f7477ee424 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -46,10 +46,54 @@ static int nvidia_fetch_size(void) 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, num_dirs; + int i, rc, num_dirs; u32 apbase, aplimit; struct aper_size_info_8 *current_size; u32 temp; @@ -69,6 +113,8 @@ static int nvidia_configure(void) pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APLIMIT, aplimit); pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APBASE, apbase); pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APLIMIT, aplimit); + if (0 != (rc = nvidia_init_iorr(apbase, current_size->size * 1024 * 1024))) + return rc; /* directory size is 64k */ num_dirs = current_size->size / 64; @@ -122,6 +168,10 @@ static void nvidia_cleanup(void) previous_size = A_SIZE_8(agp_bridge->previous_size); pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, previous_size->size_value); + + /* restore iorr for previous aperture size */ + nvidia_init_iorr(agp_bridge->gart_bus_addr, + previous_size->size * 1024 * 1024); } -- 2.53.0