1250c2277SThomas Gleixner /* 2250c2277SThomas Gleixner * Firmware replacement code. 3250c2277SThomas Gleixner * 48caac563SPavel Machek * Work around broken BIOSes that don't set an aperture, only set the 58caac563SPavel Machek * aperture in the AGP bridge, or set too small aperture. 68caac563SPavel Machek * 7250c2277SThomas Gleixner * If all fails map the aperture over some low memory. This is cheaper than 8250c2277SThomas Gleixner * doing bounce buffering. The memory is lost. This is done at early boot 9250c2277SThomas Gleixner * because only the bootmem allocator can allocate 32+MB. 10250c2277SThomas Gleixner * 11250c2277SThomas Gleixner * Copyright 2002 Andi Kleen, SuSE Labs. 12250c2277SThomas Gleixner */ 13*a5d3244aSBjorn Helgaas #define pr_fmt(fmt) "AGP: " fmt 14*a5d3244aSBjorn Helgaas 15250c2277SThomas Gleixner #include <linux/kernel.h> 16250c2277SThomas Gleixner #include <linux/types.h> 17250c2277SThomas Gleixner #include <linux/init.h> 1832e3f2b0SYinghai Lu #include <linux/memblock.h> 19250c2277SThomas Gleixner #include <linux/mmzone.h> 20250c2277SThomas Gleixner #include <linux/pci_ids.h> 21250c2277SThomas Gleixner #include <linux/pci.h> 22250c2277SThomas Gleixner #include <linux/bitops.h> 232050d45dSPavel Machek #include <linux/suspend.h> 24250c2277SThomas Gleixner #include <asm/e820.h> 25250c2277SThomas Gleixner #include <asm/io.h> 2646a7fa27SFUJITA Tomonori #include <asm/iommu.h> 27395624fcSJoerg Roedel #include <asm/gart.h> 28250c2277SThomas Gleixner #include <asm/pci-direct.h> 29250c2277SThomas Gleixner #include <asm/dma.h> 3023ac4ae8SAndreas Herrmann #include <asm/amd_nb.h> 31de957628SFUJITA Tomonori #include <asm/x86_init.h> 32250c2277SThomas Gleixner 33c387aa3aSJoerg Roedel /* 34c387aa3aSJoerg Roedel * Using 512M as goal, in case kexec will load kernel_big 35c387aa3aSJoerg Roedel * that will do the on-position decompress, and could overlap with 36c387aa3aSJoerg Roedel * with the gart aperture that is used. 37c387aa3aSJoerg Roedel * Sequence: 38c387aa3aSJoerg Roedel * kernel_small 39c387aa3aSJoerg Roedel * ==> kexec (with kdump trigger path or gart still enabled) 40c387aa3aSJoerg Roedel * ==> kernel_small (gart area become e820_reserved) 41c387aa3aSJoerg Roedel * ==> kexec (with kdump trigger path or gart still enabled) 42c387aa3aSJoerg Roedel * ==> kerne_big (uncompressed size will be big than 64M or 128M) 43c387aa3aSJoerg Roedel * So don't use 512M below as gart iommu, leave the space for kernel 44c387aa3aSJoerg Roedel * code for safe. 45c387aa3aSJoerg Roedel */ 46c387aa3aSJoerg Roedel #define GART_MIN_ADDR (512ULL << 20) 47c387aa3aSJoerg Roedel #define GART_MAX_ADDR (1ULL << 32) 48c387aa3aSJoerg Roedel 490440d4c0SJoerg Roedel int gart_iommu_aperture; 507de6a4cdSPavel Machek int gart_iommu_aperture_disabled __initdata; 517de6a4cdSPavel Machek int gart_iommu_aperture_allowed __initdata; 52250c2277SThomas Gleixner 53250c2277SThomas Gleixner int fallback_aper_order __initdata = 1; /* 64MB */ 547de6a4cdSPavel Machek int fallback_aper_force __initdata; 55250c2277SThomas Gleixner 56250c2277SThomas Gleixner int fix_aperture __initdata = 1; 57250c2277SThomas Gleixner 58250c2277SThomas Gleixner /* This code runs before the PCI subsystem is initialized, so just 59250c2277SThomas Gleixner access the northbridge directly. */ 60250c2277SThomas Gleixner 61250c2277SThomas Gleixner static u32 __init allocate_aperture(void) 62250c2277SThomas Gleixner { 63250c2277SThomas Gleixner u32 aper_size; 6432e3f2b0SYinghai Lu unsigned long addr; 65250c2277SThomas Gleixner 667677b2efSYinghai Lu /* aper_size should <= 1G */ 677677b2efSYinghai Lu if (fallback_aper_order > 5) 687677b2efSYinghai Lu fallback_aper_order = 5; 69250c2277SThomas Gleixner aper_size = (32 * 1024 * 1024) << fallback_aper_order; 70250c2277SThomas Gleixner 71250c2277SThomas Gleixner /* 72c140df97SIngo Molnar * Aperture has to be naturally aligned. This means a 2GB aperture 73c140df97SIngo Molnar * won't have much chance of finding a place in the lower 4GB of 74c140df97SIngo Molnar * memory. Unfortunately we cannot move it up because that would 75c140df97SIngo Molnar * make the IOMMU useless. 76250c2277SThomas Gleixner */ 77c387aa3aSJoerg Roedel addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR, 78c387aa3aSJoerg Roedel aper_size, aper_size); 7926bfc540SWang YanQing if (!addr) { 80*a5d3244aSBjorn Helgaas pr_err("Cannot allocate aperture memory hole (%lx,%uK)\n", 8132e3f2b0SYinghai Lu addr, aper_size>>10); 8232e3f2b0SYinghai Lu return 0; 8332e3f2b0SYinghai Lu } 8424aa0788STejun Heo memblock_reserve(addr, aper_size); 85*a5d3244aSBjorn Helgaas pr_info("Mapping aperture over %d KB of RAM @ %lx\n", aper_size >> 10, 86*a5d3244aSBjorn Helgaas addr); 8732e3f2b0SYinghai Lu register_nosave_region(addr >> PAGE_SHIFT, 8832e3f2b0SYinghai Lu (addr+aper_size) >> PAGE_SHIFT); 89c140df97SIngo Molnar 9032e3f2b0SYinghai Lu return (u32)addr; 91250c2277SThomas Gleixner } 92250c2277SThomas Gleixner 93250c2277SThomas Gleixner 94250c2277SThomas Gleixner /* Find a PCI capability */ 95dd564d0cSPavel Machek static u32 __init find_cap(int bus, int slot, int func, int cap) 96250c2277SThomas Gleixner { 97250c2277SThomas Gleixner int bytes; 98c140df97SIngo Molnar u8 pos; 99c140df97SIngo Molnar 10055c0d721SYinghai Lu if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) & 101c140df97SIngo Molnar PCI_STATUS_CAP_LIST)) 102250c2277SThomas Gleixner return 0; 103c140df97SIngo Molnar 10455c0d721SYinghai Lu pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST); 105250c2277SThomas Gleixner for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { 106250c2277SThomas Gleixner u8 id; 107c140df97SIngo Molnar 108250c2277SThomas Gleixner pos &= ~3; 10955c0d721SYinghai Lu id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID); 110250c2277SThomas Gleixner if (id == 0xff) 111250c2277SThomas Gleixner break; 112250c2277SThomas Gleixner if (id == cap) 113250c2277SThomas Gleixner return pos; 11455c0d721SYinghai Lu pos = read_pci_config_byte(bus, slot, func, 115c140df97SIngo Molnar pos+PCI_CAP_LIST_NEXT); 116250c2277SThomas Gleixner } 117250c2277SThomas Gleixner return 0; 118250c2277SThomas Gleixner } 119250c2277SThomas Gleixner 120250c2277SThomas Gleixner /* Read a standard AGPv3 bridge header */ 121dd564d0cSPavel Machek static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order) 122250c2277SThomas Gleixner { 123250c2277SThomas Gleixner u32 apsize; 124250c2277SThomas Gleixner u32 apsizereg; 125250c2277SThomas Gleixner int nbits; 126250c2277SThomas Gleixner u32 aper_low, aper_hi; 127250c2277SThomas Gleixner u64 aper; 1281edc1ab3SYinghai Lu u32 old_order; 129250c2277SThomas Gleixner 130*a5d3244aSBjorn Helgaas pr_info("AGP bridge at %02x:%02x:%02x\n", bus, slot, func); 13155c0d721SYinghai Lu apsizereg = read_pci_config_16(bus, slot, func, cap + 0x14); 132250c2277SThomas Gleixner if (apsizereg == 0xffffffff) { 133*a5d3244aSBjorn Helgaas pr_err("APSIZE in AGP bridge unreadable\n"); 134250c2277SThomas Gleixner return 0; 135250c2277SThomas Gleixner } 136250c2277SThomas Gleixner 1371edc1ab3SYinghai Lu /* old_order could be the value from NB gart setting */ 1381edc1ab3SYinghai Lu old_order = *order; 1391edc1ab3SYinghai Lu 140250c2277SThomas Gleixner apsize = apsizereg & 0xfff; 141250c2277SThomas Gleixner /* Some BIOS use weird encodings not in the AGPv3 table. */ 142250c2277SThomas Gleixner if (apsize & 0xff) 143250c2277SThomas Gleixner apsize |= 0xf00; 144250c2277SThomas Gleixner nbits = hweight16(apsize); 145250c2277SThomas Gleixner *order = 7 - nbits; 146250c2277SThomas Gleixner if ((int)*order < 0) /* < 32MB */ 147250c2277SThomas Gleixner *order = 0; 148250c2277SThomas Gleixner 14955c0d721SYinghai Lu aper_low = read_pci_config(bus, slot, func, 0x10); 15055c0d721SYinghai Lu aper_hi = read_pci_config(bus, slot, func, 0x14); 151250c2277SThomas Gleixner aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); 152250c2277SThomas Gleixner 1531edc1ab3SYinghai Lu /* 1541edc1ab3SYinghai Lu * On some sick chips, APSIZE is 0. It means it wants 4G 1551edc1ab3SYinghai Lu * so let double check that order, and lets trust AMD NB settings: 1561edc1ab3SYinghai Lu */ 157*a5d3244aSBjorn Helgaas pr_info("Aperture from AGP @ %Lx old size %u MB\n", 1588c9fd91aSYinghai Lu aper, 32 << old_order); 1598c9fd91aSYinghai Lu if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) { 160*a5d3244aSBjorn Helgaas pr_info("Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n", 1611edc1ab3SYinghai Lu 32 << *order, apsizereg); 1621edc1ab3SYinghai Lu *order = old_order; 1631edc1ab3SYinghai Lu } 1641edc1ab3SYinghai Lu 165*a5d3244aSBjorn Helgaas pr_info("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", aper, 166*a5d3244aSBjorn Helgaas 32 << *order, apsizereg); 167250c2277SThomas Gleixner 1688c9fd91aSYinghai Lu if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20)) 169250c2277SThomas Gleixner return 0; 170250c2277SThomas Gleixner return (u32)aper; 171250c2277SThomas Gleixner } 172250c2277SThomas Gleixner 173c140df97SIngo Molnar /* 174c140df97SIngo Molnar * Look for an AGP bridge. Windows only expects the aperture in the 175c140df97SIngo Molnar * AGP bridge and some BIOS forget to initialize the Northbridge too. 176c140df97SIngo Molnar * Work around this here. 177c140df97SIngo Molnar * 178c140df97SIngo Molnar * Do an PCI bus scan by hand because we're running before the PCI 179c140df97SIngo Molnar * subsystem. 180c140df97SIngo Molnar * 181eec1d4faSHans Rosenfeld * All AMD AGP bridges are AGPv3 compliant, so we can do this scan 182c140df97SIngo Molnar * generically. It's probably overkill to always scan all slots because 183c140df97SIngo Molnar * the AGP bridges should be always an own bus on the HT hierarchy, 184c140df97SIngo Molnar * but do it here for future safety. 185c140df97SIngo Molnar */ 186dd564d0cSPavel Machek static u32 __init search_agp_bridge(u32 *order, int *valid_agp) 187250c2277SThomas Gleixner { 18855c0d721SYinghai Lu int bus, slot, func; 189250c2277SThomas Gleixner 190250c2277SThomas Gleixner /* Poor man's PCI discovery */ 19155c0d721SYinghai Lu for (bus = 0; bus < 256; bus++) { 192250c2277SThomas Gleixner for (slot = 0; slot < 32; slot++) { 193250c2277SThomas Gleixner for (func = 0; func < 8; func++) { 194250c2277SThomas Gleixner u32 class, cap; 195250c2277SThomas Gleixner u8 type; 19655c0d721SYinghai Lu class = read_pci_config(bus, slot, func, 197250c2277SThomas Gleixner PCI_CLASS_REVISION); 198250c2277SThomas Gleixner if (class == 0xffffffff) 199250c2277SThomas Gleixner break; 200250c2277SThomas Gleixner 201250c2277SThomas Gleixner switch (class >> 16) { 202250c2277SThomas Gleixner case PCI_CLASS_BRIDGE_HOST: 203250c2277SThomas Gleixner case PCI_CLASS_BRIDGE_OTHER: /* needed? */ 204250c2277SThomas Gleixner /* AGP bridge? */ 20555c0d721SYinghai Lu cap = find_cap(bus, slot, func, 206c140df97SIngo Molnar PCI_CAP_ID_AGP); 207250c2277SThomas Gleixner if (!cap) 208250c2277SThomas Gleixner break; 209250c2277SThomas Gleixner *valid_agp = 1; 21055c0d721SYinghai Lu return read_agp(bus, slot, func, cap, 211c140df97SIngo Molnar order); 212250c2277SThomas Gleixner } 213250c2277SThomas Gleixner 214250c2277SThomas Gleixner /* No multi-function device? */ 21555c0d721SYinghai Lu type = read_pci_config_byte(bus, slot, func, 216250c2277SThomas Gleixner PCI_HEADER_TYPE); 217250c2277SThomas Gleixner if (!(type & 0x80)) 218250c2277SThomas Gleixner break; 219250c2277SThomas Gleixner } 220250c2277SThomas Gleixner } 221250c2277SThomas Gleixner } 222*a5d3244aSBjorn Helgaas pr_info("No AGP bridge found\n"); 223c140df97SIngo Molnar 224250c2277SThomas Gleixner return 0; 225250c2277SThomas Gleixner } 226250c2277SThomas Gleixner 227aaf23042SYinghai Lu static int gart_fix_e820 __initdata = 1; 228aaf23042SYinghai Lu 229aaf23042SYinghai Lu static int __init parse_gart_mem(char *p) 230aaf23042SYinghai Lu { 231aaf23042SYinghai Lu if (!p) 232aaf23042SYinghai Lu return -EINVAL; 233aaf23042SYinghai Lu 234aaf23042SYinghai Lu if (!strncmp(p, "off", 3)) 235aaf23042SYinghai Lu gart_fix_e820 = 0; 236aaf23042SYinghai Lu else if (!strncmp(p, "on", 2)) 237aaf23042SYinghai Lu gart_fix_e820 = 1; 238aaf23042SYinghai Lu 239aaf23042SYinghai Lu return 0; 240aaf23042SYinghai Lu } 241aaf23042SYinghai Lu early_param("gart_fix_e820", parse_gart_mem); 242aaf23042SYinghai Lu 243aaf23042SYinghai Lu void __init early_gart_iommu_check(void) 244aaf23042SYinghai Lu { 245aaf23042SYinghai Lu /* 246aaf23042SYinghai Lu * in case it is enabled before, esp for kexec/kdump, 247aaf23042SYinghai Lu * previous kernel already enable that. memset called 248aaf23042SYinghai Lu * by allocate_aperture/__alloc_bootmem_nopanic cause restart. 249aaf23042SYinghai Lu * or second kernel have different position for GART hole. and new 250aaf23042SYinghai Lu * kernel could use hole as RAM that is still used by GART set by 251aaf23042SYinghai Lu * first kernel 252aaf23042SYinghai Lu * or BIOS forget to put that in reserved. 253aaf23042SYinghai Lu * try to update e820 to make that region as reserved. 254aaf23042SYinghai Lu */ 255fa10ba64SAndi Kleen u32 agp_aper_order = 0; 256f3eee542SYinghai Lu int i, fix, slot, valid_agp = 0; 257aaf23042SYinghai Lu u32 ctl; 258aaf23042SYinghai Lu u32 aper_size = 0, aper_order = 0, last_aper_order = 0; 259aaf23042SYinghai Lu u64 aper_base = 0, last_aper_base = 0; 260fa5b8a30SPavel Machek int aper_enabled = 0, last_aper_enabled = 0, last_valid = 0; 261aaf23042SYinghai Lu 262aaf23042SYinghai Lu if (!early_pci_allowed()) 263aaf23042SYinghai Lu return; 264aaf23042SYinghai Lu 265fa5b8a30SPavel Machek /* This is mostly duplicate of iommu_hole_init */ 266fa10ba64SAndi Kleen search_agp_bridge(&agp_aper_order, &valid_agp); 267f3eee542SYinghai Lu 268aaf23042SYinghai Lu fix = 0; 26924d9b70bSJan Beulich for (i = 0; amd_nb_bus_dev_ranges[i].dev_limit; i++) { 27055c0d721SYinghai Lu int bus; 27155c0d721SYinghai Lu int dev_base, dev_limit; 27255c0d721SYinghai Lu 27324d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 27424d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 27524d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 27655c0d721SYinghai Lu 27755c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 278eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 279aaf23042SYinghai Lu continue; 280aaf23042SYinghai Lu 28155c0d721SYinghai Lu ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); 28257ab43e3SBorislav Petkov aper_enabled = ctl & GARTEN; 283aaf23042SYinghai Lu aper_order = (ctl >> 1) & 7; 284aaf23042SYinghai Lu aper_size = (32 * 1024 * 1024) << aper_order; 28555c0d721SYinghai Lu aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; 286aaf23042SYinghai Lu aper_base <<= 25; 287aaf23042SYinghai Lu 288fa5b8a30SPavel Machek if (last_valid) { 289fa5b8a30SPavel Machek if ((aper_order != last_aper_order) || 290fa5b8a30SPavel Machek (aper_base != last_aper_base) || 291fa5b8a30SPavel Machek (aper_enabled != last_aper_enabled)) { 292aaf23042SYinghai Lu fix = 1; 293fa5b8a30SPavel Machek break; 294aaf23042SYinghai Lu } 29555c0d721SYinghai Lu } 296aaf23042SYinghai Lu 297fa5b8a30SPavel Machek last_aper_order = aper_order; 298fa5b8a30SPavel Machek last_aper_base = aper_base; 299fa5b8a30SPavel Machek last_aper_enabled = aper_enabled; 300fa5b8a30SPavel Machek last_valid = 1; 301fa5b8a30SPavel Machek } 302fa5b8a30SPavel Machek } 303fa5b8a30SPavel Machek 304aaf23042SYinghai Lu if (!fix && !aper_enabled) 305aaf23042SYinghai Lu return; 306aaf23042SYinghai Lu 307aaf23042SYinghai Lu if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL) 308aaf23042SYinghai Lu fix = 1; 309aaf23042SYinghai Lu 310aaf23042SYinghai Lu if (gart_fix_e820 && !fix && aper_enabled) { 3110754557dSYinghai Lu if (e820_any_mapped(aper_base, aper_base + aper_size, 3120754557dSYinghai Lu E820_RAM)) { 3130abbc78aSPavel Machek /* reserve it, so we can reuse it in second kernel */ 314*a5d3244aSBjorn Helgaas pr_info("update e820 for GART\n"); 315d0be6bdeSYinghai Lu e820_add_region(aper_base, aper_size, E820_RESERVED); 316aaf23042SYinghai Lu update_e820(); 317aaf23042SYinghai Lu } 318aaf23042SYinghai Lu } 319aaf23042SYinghai Lu 320f3eee542SYinghai Lu if (valid_agp) 3214f384f8bSPavel Machek return; 3224f384f8bSPavel Machek 323f3eee542SYinghai Lu /* disable them all at first */ 32424d9b70bSJan Beulich for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 32555c0d721SYinghai Lu int bus; 32655c0d721SYinghai Lu int dev_base, dev_limit; 32755c0d721SYinghai Lu 32824d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 32924d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 33024d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 33155c0d721SYinghai Lu 33255c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 333eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 334aaf23042SYinghai Lu continue; 335aaf23042SYinghai Lu 33655c0d721SYinghai Lu ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); 33757ab43e3SBorislav Petkov ctl &= ~GARTEN; 33855c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 33955c0d721SYinghai Lu } 340aaf23042SYinghai Lu } 341aaf23042SYinghai Lu 342aaf23042SYinghai Lu } 343aaf23042SYinghai Lu 3448c9fd91aSYinghai Lu static int __initdata printed_gart_size_msg; 3458c9fd91aSYinghai Lu 346480125baSKonrad Rzeszutek Wilk int __init gart_iommu_hole_init(void) 347250c2277SThomas Gleixner { 3488c9fd91aSYinghai Lu u32 agp_aper_base = 0, agp_aper_order = 0; 349250c2277SThomas Gleixner u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; 350250c2277SThomas Gleixner u64 aper_base, last_aper_base = 0; 35155c0d721SYinghai Lu int fix, slot, valid_agp = 0; 35255c0d721SYinghai Lu int i, node; 353250c2277SThomas Gleixner 3540440d4c0SJoerg Roedel if (gart_iommu_aperture_disabled || !fix_aperture || 3550440d4c0SJoerg Roedel !early_pci_allowed()) 356480125baSKonrad Rzeszutek Wilk return -ENODEV; 357250c2277SThomas Gleixner 358*a5d3244aSBjorn Helgaas pr_info("Checking aperture...\n"); 359250c2277SThomas Gleixner 3608c9fd91aSYinghai Lu if (!fallback_aper_force) 3618c9fd91aSYinghai Lu agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp); 3628c9fd91aSYinghai Lu 363250c2277SThomas Gleixner fix = 0; 36447db4c3eSYinghai Lu node = 0; 36524d9b70bSJan Beulich for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 36655c0d721SYinghai Lu int bus; 36755c0d721SYinghai Lu int dev_base, dev_limit; 3684b83873dSJoerg Roedel u32 ctl; 36955c0d721SYinghai Lu 37024d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 37124d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 37224d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 37355c0d721SYinghai Lu 37455c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 375eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 376250c2277SThomas Gleixner continue; 377250c2277SThomas Gleixner 378250c2277SThomas Gleixner iommu_detected = 1; 3790440d4c0SJoerg Roedel gart_iommu_aperture = 1; 380de957628SFUJITA Tomonori x86_init.iommu.iommu_init = gart_iommu_init; 381250c2277SThomas Gleixner 3824b83873dSJoerg Roedel ctl = read_pci_config(bus, slot, 3, 3834b83873dSJoerg Roedel AMD64_GARTAPERTURECTL); 3844b83873dSJoerg Roedel 3854b83873dSJoerg Roedel /* 3864b83873dSJoerg Roedel * Before we do anything else disable the GART. It may 3874b83873dSJoerg Roedel * still be enabled if we boot into a crash-kernel here. 3884b83873dSJoerg Roedel * Reconfiguring the GART while it is enabled could have 3894b83873dSJoerg Roedel * unknown side-effects. 3904b83873dSJoerg Roedel */ 3914b83873dSJoerg Roedel ctl &= ~GARTEN; 3924b83873dSJoerg Roedel write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 3934b83873dSJoerg Roedel 3944b83873dSJoerg Roedel aper_order = (ctl >> 1) & 7; 395250c2277SThomas Gleixner aper_size = (32 * 1024 * 1024) << aper_order; 39655c0d721SYinghai Lu aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; 397250c2277SThomas Gleixner aper_base <<= 25; 398250c2277SThomas Gleixner 399*a5d3244aSBjorn Helgaas pr_info("Node %d: aperture @ %Lx size %u MB\n", 40047db4c3eSYinghai Lu node, aper_base, aper_size >> 20); 40147db4c3eSYinghai Lu node++; 402250c2277SThomas Gleixner 4038c9fd91aSYinghai Lu if (!aperture_valid(aper_base, aper_size, 64<<20)) { 4048c9fd91aSYinghai Lu if (valid_agp && agp_aper_base && 4058c9fd91aSYinghai Lu agp_aper_base == aper_base && 4068c9fd91aSYinghai Lu agp_aper_order == aper_order) { 4078c9fd91aSYinghai Lu /* the same between two setting from NB and agp */ 408c987d12fSYinghai Lu if (!no_iommu && 409c987d12fSYinghai Lu max_pfn > MAX_DMA32_PFN && 410c987d12fSYinghai Lu !printed_gart_size_msg) { 411*a5d3244aSBjorn Helgaas pr_err("you are using iommu with agp, but GART size is less than 64M\n"); 412*a5d3244aSBjorn Helgaas pr_err("please increase GART size in your BIOS setup\n"); 413*a5d3244aSBjorn Helgaas pr_err("if BIOS doesn't have that option, contact your HW vendor!\n"); 4148c9fd91aSYinghai Lu printed_gart_size_msg = 1; 4158c9fd91aSYinghai Lu } 4168c9fd91aSYinghai Lu } else { 417250c2277SThomas Gleixner fix = 1; 41855c0d721SYinghai Lu goto out; 419250c2277SThomas Gleixner } 4208c9fd91aSYinghai Lu } 421250c2277SThomas Gleixner 422250c2277SThomas Gleixner if ((last_aper_order && aper_order != last_aper_order) || 423250c2277SThomas Gleixner (last_aper_base && aper_base != last_aper_base)) { 424250c2277SThomas Gleixner fix = 1; 42555c0d721SYinghai Lu goto out; 426250c2277SThomas Gleixner } 427250c2277SThomas Gleixner last_aper_order = aper_order; 428250c2277SThomas Gleixner last_aper_base = aper_base; 429250c2277SThomas Gleixner } 43055c0d721SYinghai Lu } 431250c2277SThomas Gleixner 43255c0d721SYinghai Lu out: 433250c2277SThomas Gleixner if (!fix && !fallback_aper_force) { 434707d4eefSBjorn Helgaas if (last_aper_base) 435480125baSKonrad Rzeszutek Wilk return 1; 436480125baSKonrad Rzeszutek Wilk return 0; 437250c2277SThomas Gleixner } 438250c2277SThomas Gleixner 4398c9fd91aSYinghai Lu if (!fallback_aper_force) { 4408c9fd91aSYinghai Lu aper_alloc = agp_aper_base; 4418c9fd91aSYinghai Lu aper_order = agp_aper_order; 4428c9fd91aSYinghai Lu } 443250c2277SThomas Gleixner 444250c2277SThomas Gleixner if (aper_alloc) { 445250c2277SThomas Gleixner /* Got the aperture from the AGP bridge */ 446c987d12fSYinghai Lu } else if ((!no_iommu && max_pfn > MAX_DMA32_PFN) || 447250c2277SThomas Gleixner force_iommu || 448250c2277SThomas Gleixner valid_agp || 449250c2277SThomas Gleixner fallback_aper_force) { 450*a5d3244aSBjorn Helgaas pr_info("Your BIOS doesn't leave a aperture memory hole\n"); 451*a5d3244aSBjorn Helgaas pr_info("Please enable the IOMMU option in the BIOS setup\n"); 452*a5d3244aSBjorn Helgaas pr_info("This costs you %d MB of RAM\n", 453250c2277SThomas Gleixner 32 << fallback_aper_order); 454250c2277SThomas Gleixner 455250c2277SThomas Gleixner aper_order = fallback_aper_order; 456250c2277SThomas Gleixner aper_alloc = allocate_aperture(); 457250c2277SThomas Gleixner if (!aper_alloc) { 458c140df97SIngo Molnar /* 459c140df97SIngo Molnar * Could disable AGP and IOMMU here, but it's 460c140df97SIngo Molnar * probably not worth it. But the later users 461c140df97SIngo Molnar * cannot deal with bad apertures and turning 462c140df97SIngo Molnar * on the aperture over memory causes very 463c140df97SIngo Molnar * strange problems, so it's better to panic 464c140df97SIngo Molnar * early. 465c140df97SIngo Molnar */ 466250c2277SThomas Gleixner panic("Not enough memory for aperture"); 467250c2277SThomas Gleixner } 468250c2277SThomas Gleixner } else { 469480125baSKonrad Rzeszutek Wilk return 0; 470250c2277SThomas Gleixner } 471250c2277SThomas Gleixner 472250c2277SThomas Gleixner /* Fix up the north bridges */ 47324d9b70bSJan Beulich for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 474260133abSBorislav Petkov int bus, dev_base, dev_limit; 475260133abSBorislav Petkov 476260133abSBorislav Petkov /* 477260133abSBorislav Petkov * Don't enable translation yet but enable GART IO and CPU 478260133abSBorislav Petkov * accesses and set DISTLBWALKPRB since GART table memory is UC. 479260133abSBorislav Petkov */ 480c34151a7SJoerg Roedel u32 ctl = aper_order << 1; 48155c0d721SYinghai Lu 48224d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 48324d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 48424d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 48555c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 486eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 487250c2277SThomas Gleixner continue; 488250c2277SThomas Gleixner 489260133abSBorislav Petkov write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 49055c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25); 49155c0d721SYinghai Lu } 492250c2277SThomas Gleixner } 4936703f6d1SRafael J. Wysocki 4946703f6d1SRafael J. Wysocki set_up_gart_resume(aper_order, aper_alloc); 495480125baSKonrad Rzeszutek Wilk 496480125baSKonrad Rzeszutek Wilk return 1; 497250c2277SThomas Gleixner } 498